Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / dev / ic / pckbc.c
blob215c85cd53b89bdffac56b06dd20eddca0161166
1 /* $NetBSD: pckbc.c,v 1.46 2009/05/12 14:25:18 cegger Exp $ */
3 /*
4 * Copyright (c) 2004 Ben Harris.
5 * Copyright (c) 1998
6 * Matthias Drochner. All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: pckbc.c,v 1.46 2009/05/12 14:25:18 cegger Exp $");
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/callout.h>
35 #include <sys/kernel.h>
36 #include <sys/proc.h>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
39 #include <sys/errno.h>
40 #include <sys/queue.h>
42 #include <sys/bus.h>
44 #include <dev/ic/i8042reg.h>
45 #include <dev/ic/pckbcvar.h>
47 #include <dev/pckbport/pckbportvar.h>
49 #include "rnd.h"
50 #include "locators.h"
52 #if NRND > 0
53 #include <sys/rnd.h>
54 #endif
56 /* data per slave device */
57 struct pckbc_slotdata {
58 int polling; /* don't process data in interrupt handler */
59 int poll_data; /* data read from inr handler if polling */
60 int poll_stat; /* status read from inr handler if polling */
61 #if NRND > 0
62 rndsource_element_t rnd_source;
63 #endif
66 static void pckbc_init_slotdata(struct pckbc_slotdata *);
67 static int pckbc_attach_slot(struct pckbc_softc *, pckbc_slot_t);
69 struct pckbc_internal pckbc_consdata;
70 int pckbc_console_attached;
72 static int pckbc_console;
73 static struct pckbc_slotdata pckbc_cons_slotdata;
75 static int pckbc_xt_translation(void *, pckbport_slot_t, int);
76 static int pckbc_send_devcmd(void *, pckbport_slot_t, u_char);
77 static void pckbc_slot_enable(void *, pckbport_slot_t, int);
78 static void pckbc_intr_establish(void *, pckbport_slot_t);
79 static void pckbc_set_poll(void *, pckbc_slot_t, int on);
81 static int pckbc_wait_output(bus_space_tag_t, bus_space_handle_t);
83 static int pckbc_get8042cmd(struct pckbc_internal *);
84 static int pckbc_put8042cmd(struct pckbc_internal *);
86 void pckbc_cleanqueue(struct pckbc_slotdata *);
87 void pckbc_cleanup(void *);
88 int pckbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char);
89 void pckbc_start(struct pckbc_internal *, pckbc_slot_t);
91 const char * const pckbc_slot_names[] = { "kbd", "aux" };
93 static struct pckbport_accessops const pckbc_ops = {
94 pckbc_xt_translation,
95 pckbc_send_devcmd,
96 pckbc_poll_data1,
97 pckbc_slot_enable,
98 pckbc_intr_establish,
99 pckbc_set_poll
102 #define KBD_DELAY DELAY(8)
104 static inline int
105 pckbc_wait_output(bus_space_tag_t iot, bus_space_handle_t ioh_c)
107 u_int i;
109 for (i = 100000; i; i--)
110 if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
111 KBD_DELAY;
112 return (1);
114 return (0);
118 pckbc_send_cmd(bus_space_tag_t iot, bus_space_handle_t ioh_c, u_char val)
120 if (!pckbc_wait_output(iot, ioh_c))
121 return (0);
122 bus_space_write_1(iot, ioh_c, 0, val);
123 return (1);
127 * Note: the spl games here are to deal with some strange PC kbd controllers
128 * in some system configurations.
129 * This is not canonical way to handle polling input.
132 pckbc_poll_data1(void *pt, pckbc_slot_t slot)
134 struct pckbc_internal *t = pt;
135 struct pckbc_slotdata *q = t->t_slotdata[slot];
136 int s;
137 u_char stat, c;
138 int i = 100; /* polls for ~100ms */
139 int checkaux = t->t_haveaux;
141 s = splhigh();
143 if (q && q->polling && q->poll_data != -1 && q->poll_stat != -1) {
144 stat = q->poll_stat;
145 c = q->poll_data;
146 q->poll_data = -1;
147 q->poll_stat = -1;
148 goto process;
151 for (; i; i--, delay(1000)) {
152 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
153 if (stat & KBS_DIB) {
154 KBD_DELAY;
155 c = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
157 process:
158 if (checkaux && (stat & 0x20)) { /* aux data */
159 if (slot != PCKBC_AUX_SLOT) {
160 #ifdef PCKBCDEBUG
161 printf("pckbc: lost aux 0x%x\n", c);
162 #endif
163 continue;
165 } else {
166 if (slot == PCKBC_AUX_SLOT) {
167 #ifdef PCKBCDEBUG
168 printf("pckbc: lost kbd 0x%x\n", c);
169 #endif
170 continue;
173 splx(s);
174 return (c);
178 splx(s);
179 return (-1);
183 * Get the current command byte.
185 static int
186 pckbc_get8042cmd(struct pckbc_internal *t)
188 bus_space_tag_t iot = t->t_iot;
189 bus_space_handle_t ioh_c = t->t_ioh_c;
190 int data;
192 if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
193 return (0);
194 data = pckbc_poll_data1(t, PCKBC_KBD_SLOT);
195 if (data == -1)
196 return (0);
197 t->t_cmdbyte = data;
198 return (1);
202 * Pass command byte to keyboard controller (8042).
204 static int
205 pckbc_put8042cmd(struct pckbc_internal *t)
207 bus_space_tag_t iot = t->t_iot;
208 bus_space_handle_t ioh_d = t->t_ioh_d;
209 bus_space_handle_t ioh_c = t->t_ioh_c;
211 if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE))
212 return (0);
213 if (!pckbc_wait_output(iot, ioh_c))
214 return (0);
215 bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte);
216 return (1);
219 static int
220 pckbc_send_devcmd(void *pt, pckbc_slot_t slot, u_char val)
222 struct pckbc_internal *t = pt;
223 bus_space_tag_t iot = t->t_iot;
224 bus_space_handle_t ioh_d = t->t_ioh_d;
225 bus_space_handle_t ioh_c = t->t_ioh_c;
227 if (slot == PCKBC_AUX_SLOT) {
228 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
229 return (0);
231 if (!pckbc_wait_output(iot, ioh_c))
232 return (0);
233 bus_space_write_1(iot, ioh_d, 0, val);
234 return (1);
238 pckbc_is_console(bus_space_tag_t iot, bus_addr_t addr)
240 if (pckbc_console && !pckbc_console_attached &&
241 pckbc_consdata.t_iot == iot &&
242 pckbc_consdata.t_addr == addr)
243 return (1);
244 return (0);
247 static int
248 pckbc_attach_slot(struct pckbc_softc *sc, pckbc_slot_t slot)
250 struct pckbc_internal *t = sc->id;
251 struct pckbc_attach_args pa;
252 void *sdata;
253 device_t child;
254 int alloced = 0;
256 pa.pa_tag = t;
257 pa.pa_slot = slot;
259 if (t->t_slotdata[slot] == NULL) {
260 sdata = malloc(sizeof(struct pckbc_slotdata),
261 M_DEVBUF, M_NOWAIT);
262 if (sdata == NULL) {
263 aprint_error_dev(sc->sc_dv, "no memory\n");
264 return (0);
266 t->t_slotdata[slot] = sdata;
267 pckbc_init_slotdata(t->t_slotdata[slot]);
268 alloced++;
271 child = pckbport_attach_slot(sc->sc_dv, t->t_pt, slot);
273 if (child == NULL && alloced) {
274 free(t->t_slotdata[slot], M_DEVBUF);
275 t->t_slotdata[slot] = NULL;
278 #if NRND > 0
279 if (child != NULL && t->t_slotdata[slot] != NULL)
280 rnd_attach_source(&t->t_slotdata[slot]->rnd_source,
281 device_xname(child), RND_TYPE_TTY, 0);
282 #endif
283 return child != NULL;
286 void
287 pckbc_attach(struct pckbc_softc *sc)
289 struct pckbc_internal *t;
290 bus_space_tag_t iot;
291 bus_space_handle_t ioh_d, ioh_c;
292 int res;
293 u_char cmdbits = 0;
295 t = sc->id;
296 iot = t->t_iot;
297 ioh_d = t->t_ioh_d;
298 ioh_c = t->t_ioh_c;
300 t->t_pt = pckbport_attach(t, &pckbc_ops);
301 if (t->t_pt == NULL) {
302 aprint_error(": attach failed\n");
303 return;
306 /* flush */
307 (void) pckbc_poll_data1(t, PCKBC_KBD_SLOT);
309 /* set initial cmd byte */
310 if (!pckbc_put8042cmd(t)) {
311 printf("pckbc: cmd word write error\n");
312 return;
316 * XXX Don't check the keyboard port. There are broken keyboard controllers
317 * which don't pass the test but work normally otherwise.
319 #if 0
321 * check kbd port ok
323 if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
324 return;
325 res = pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
328 * Normally, we should get a "0" here.
329 * But there are keyboard controllers behaving differently.
331 if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
332 #ifdef PCKBCDEBUG
333 if (res != 0)
334 printf("pckbc: returned %x on kbd slot test\n", res);
335 #endif
336 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
337 cmdbits |= KC8_KENABLE;
338 } else {
339 printf("pckbc: kbd port test: %x\n", res);
340 return;
342 #else
343 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
344 cmdbits |= KC8_KENABLE;
345 #endif /* 0 */
348 * Check aux port ok.
349 * Avoid KBC_AUXTEST because it hangs some older controllers
350 * (eg UMC880?).
352 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
353 printf("pckbc: aux echo error 1\n");
354 goto nomouse;
356 if (!pckbc_wait_output(iot, ioh_c)) {
357 printf("pckbc: aux echo error 2\n");
358 goto nomouse;
360 t->t_haveaux = 1;
361 bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
362 res = pckbc_poll_data1(t, PCKBC_AUX_SLOT);
363 if (res != -1) {
365 * In most cases, the 0x5a gets echoed.
366 * Some older controllers (Gateway 2000 circa 1993)
367 * return 0xfe here.
368 * We are satisfied if there is anything in the
369 * aux output buffer.
371 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
372 cmdbits |= KC8_MENABLE;
373 } else {
374 #ifdef PCKBCDEBUG
375 printf("pckbc: aux echo test failed\n");
376 #endif
377 t->t_haveaux = 0;
380 nomouse:
381 /* enable needed interrupts */
382 t->t_cmdbyte |= cmdbits;
383 if (!pckbc_put8042cmd(t))
384 printf("pckbc: cmd word write error\n");
387 static void
388 pckbc_init_slotdata(struct pckbc_slotdata *q)
391 q->polling = 0;
395 * switch scancode translation on / off
396 * return nonzero on success
398 static int
399 pckbc_xt_translation(void *self, pckbc_slot_t slot, int on)
401 struct pckbc_internal *t = self;
402 int ison;
404 if (slot != PCKBC_KBD_SLOT) {
405 /* translation only for kbd slot */
406 if (on)
407 return (0);
408 else
409 return (1);
412 ison = t->t_cmdbyte & KC8_TRANS;
413 if ((on && ison) || (!on && !ison))
414 return (1);
416 t->t_cmdbyte ^= KC8_TRANS;
417 if (!pckbc_put8042cmd(t))
418 return (0);
420 /* read back to be sure */
421 if (!pckbc_get8042cmd(t))
422 return (0);
424 ison = t->t_cmdbyte & KC8_TRANS;
425 if ((on && ison) || (!on && !ison))
426 return (1);
427 return (0);
430 static const struct pckbc_portcmd {
431 u_char cmd_en, cmd_dis;
432 } pckbc_portcmd[2] = {
434 KBC_KBDENABLE, KBC_KBDDISABLE,
435 }, {
436 KBC_AUXENABLE, KBC_AUXDISABLE,
440 void
441 pckbc_slot_enable(void *self, pckbc_slot_t slot, int on)
443 struct pckbc_internal *t = (struct pckbc_internal *)self;
444 const struct pckbc_portcmd *cmd;
446 cmd = &pckbc_portcmd[slot];
448 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
449 on ? cmd->cmd_en : cmd->cmd_dis))
450 printf("pckbc: pckbc_slot_enable(%d) failed\n", on);
453 static void
454 pckbc_set_poll(void *self, pckbc_slot_t slot, int on)
456 struct pckbc_internal *t = (struct pckbc_internal *)self;
458 t->t_slotdata[slot]->polling = on;
460 if (on) {
461 t->t_slotdata[slot]->poll_data = -1;
462 t->t_slotdata[slot]->poll_stat = -1;
463 } else {
464 int s;
467 * If disabling polling on a device that's been configured,
468 * make sure there are no bytes left in the FIFO, holding up
469 * the interrupt line. Otherwise we won't get any further
470 * interrupts.
472 if (t->t_sc) {
473 s = spltty();
474 pckbcintr(t->t_sc);
475 splx(s);
480 static void
481 pckbc_intr_establish(void *pt, pckbport_slot_t slot)
483 struct pckbc_internal *t = pt;
485 (*t->t_sc->intr_establish)(t->t_sc, slot);
489 pckbcintr_hard(void *vsc)
491 struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
492 struct pckbc_internal *t = sc->id;
493 u_char stat;
494 pckbc_slot_t slot;
495 struct pckbc_slotdata *q;
496 int served = 0, data, next, s;
498 for(;;) {
499 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
500 if (!(stat & KBS_DIB))
501 break;
503 served = 1;
505 slot = (t->t_haveaux && (stat & 0x20)) ?
506 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
507 q = t->t_slotdata[slot];
509 if (!q) {
510 /* XXX do something for live insertion? */
511 printf("pckbc: no dev for slot %d\n", slot);
512 KBD_DELAY;
513 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
514 continue;
517 KBD_DELAY;
518 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
520 #if NRND > 0
521 rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
522 #endif
524 if (q->polling) {
525 q->poll_data = data;
526 q->poll_stat = stat;
527 break; /* pckbc_poll_data() will get it */
530 #if 0 /* XXXBJH */
531 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
532 continue;
533 #endif
535 s = splhigh();
536 next = (t->rbuf_write+1) % PCKBC_RBUF_SIZE;
537 if (next == t->rbuf_read) {
538 splx(s);
539 break;
541 t->rbuf[t->rbuf_write].data = data;
542 t->rbuf[t->rbuf_write].slot = slot;
543 t->rbuf_write = next;
544 splx(s);
547 return (served);
550 void
551 pckbcintr_soft(void *vsc)
553 struct pckbc_softc *sc = vsc;
554 struct pckbc_internal *t = sc->id;
555 int data, slot, s;
556 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
557 int st;
559 st = spltty();
560 #endif
562 s = splhigh();
563 while (t->rbuf_read != t->rbuf_write) {
564 slot = t->rbuf[t->rbuf_read].slot;
565 data = t->rbuf[t->rbuf_read].data;
566 t->rbuf_read = (t->rbuf_read+1) % PCKBC_RBUF_SIZE;
567 splx(s);
568 pckbportintr(t->t_pt, slot, data);
569 s = splhigh();
571 splx(s);
574 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
575 splx(st);
576 #endif
580 pckbcintr(void *vsc)
582 struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
583 struct pckbc_internal *t = sc->id;
584 u_char stat;
585 pckbc_slot_t slot;
586 struct pckbc_slotdata *q;
587 int served = 0, data;
589 for(;;) {
590 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
591 if (!(stat & KBS_DIB))
592 break;
594 served = 1;
596 slot = (t->t_haveaux && (stat & 0x20)) ?
597 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
598 q = t->t_slotdata[slot];
600 KBD_DELAY;
601 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
603 #if NRND > 0
604 rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
605 #endif
607 pckbportintr(t->t_pt, slot, data);
610 return (served);
614 pckbc_cnattach(bus_space_tag_t iot, bus_addr_t addr,
615 bus_size_t cmd_offset, pckbc_slot_t slot)
617 bus_space_handle_t ioh_d, ioh_c;
618 #ifdef PCKBC_CNATTACH_SELFTEST
619 int reply;
620 #endif
621 int res = 0;
623 if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
624 return (ENXIO);
625 if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
626 bus_space_unmap(iot, ioh_d, 1);
627 return (ENXIO);
630 memset(&pckbc_consdata, 0, sizeof(pckbc_consdata));
631 pckbc_consdata.t_iot = iot;
632 pckbc_consdata.t_ioh_d = ioh_d;
633 pckbc_consdata.t_ioh_c = ioh_c;
634 pckbc_consdata.t_addr = addr;
635 callout_init(&pckbc_consdata.t_cleanup, 0);
637 /* flush */
638 (void) pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
640 #ifdef PCKBC_CNATTACH_SELFTEST
642 * In some machines (e.g. netwinder) pckbc refuses to talk at
643 * all until we request a self-test.
645 if (!pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST)) {
646 printf("pckbc: unable to request selftest\n");
647 res = EIO;
648 goto out;
651 reply = pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
652 if (reply != 0x55) {
653 printf("pckbc: selftest returned 0x%02x\n", reply);
654 res = EIO;
655 goto out;
657 #endif /* PCKBC_CNATTACH_SELFTEST */
659 /* init cmd byte, enable ports */
660 pckbc_consdata.t_cmdbyte = KC8_CPU;
661 if (!pckbc_put8042cmd(&pckbc_consdata)) {
662 printf("pckbc: cmd word write error\n");
663 res = EIO;
664 goto out;
667 res = pckbport_cnattach(&pckbc_consdata, &pckbc_ops, slot);
669 out:
670 if (res) {
671 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
672 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
673 } else {
674 pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
675 pckbc_init_slotdata(&pckbc_cons_slotdata);
676 pckbc_console = 1;
679 return (res);
682 bool
683 pckbc_resume(device_t dv, pmf_qual_t qual)
685 struct pckbc_softc *sc = device_private(dv);
686 struct pckbc_internal *t;
688 t = sc->id;
689 (void)pckbc_poll_data1(t, PCKBC_KBD_SLOT);
690 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c, KBC_SELFTEST))
691 return false;
692 (void)pckbc_poll_data1(t, PCKBC_KBD_SLOT);
693 (void)pckbc_put8042cmd(t);
694 pckbcintr(t->t_sc);
696 return true;