1 /* $NetBSD: pckbc.c,v 1.46 2009/05/12 14:25:18 cegger Exp $ */
4 * Copyright (c) 2004 Ben Harris.
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
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>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
39 #include <sys/errno.h>
40 #include <sys/queue.h>
44 #include <dev/ic/i8042reg.h>
45 #include <dev/ic/pckbcvar.h>
47 #include <dev/pckbport/pckbportvar.h>
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 */
62 rndsource_element_t rnd_source
;
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
= {
102 #define KBD_DELAY DELAY(8)
105 pckbc_wait_output(bus_space_tag_t iot
, bus_space_handle_t ioh_c
)
109 for (i
= 100000; i
; i
--)
110 if (!(bus_space_read_1(iot
, ioh_c
, 0) & KBS_IBF
)) {
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
))
122 bus_space_write_1(iot
, ioh_c
, 0, val
);
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
];
138 int i
= 100; /* polls for ~100ms */
139 int checkaux
= t
->t_haveaux
;
143 if (q
&& q
->polling
&& q
->poll_data
!= -1 && q
->poll_stat
!= -1) {
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
) {
155 c
= bus_space_read_1(t
->t_iot
, t
->t_ioh_d
, 0);
158 if (checkaux
&& (stat
& 0x20)) { /* aux data */
159 if (slot
!= PCKBC_AUX_SLOT
) {
161 printf("pckbc: lost aux 0x%x\n", c
);
166 if (slot
== PCKBC_AUX_SLOT
) {
168 printf("pckbc: lost kbd 0x%x\n", c
);
183 * Get the current command byte.
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
;
192 if (!pckbc_send_cmd(iot
, ioh_c
, K_RDCMDBYTE
))
194 data
= pckbc_poll_data1(t
, PCKBC_KBD_SLOT
);
202 * Pass command byte to keyboard controller (8042).
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
))
213 if (!pckbc_wait_output(iot
, ioh_c
))
215 bus_space_write_1(iot
, ioh_d
, 0, t
->t_cmdbyte
);
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
))
231 if (!pckbc_wait_output(iot
, ioh_c
))
233 bus_space_write_1(iot
, ioh_d
, 0, val
);
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
)
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
;
259 if (t
->t_slotdata
[slot
] == NULL
) {
260 sdata
= malloc(sizeof(struct pckbc_slotdata
),
263 aprint_error_dev(sc
->sc_dv
, "no memory\n");
266 t
->t_slotdata
[slot
] = sdata
;
267 pckbc_init_slotdata(t
->t_slotdata
[slot
]);
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
;
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);
283 return child
!= NULL
;
287 pckbc_attach(struct pckbc_softc
*sc
)
289 struct pckbc_internal
*t
;
291 bus_space_handle_t ioh_d
, ioh_c
;
300 t
->t_pt
= pckbport_attach(t
, &pckbc_ops
);
301 if (t
->t_pt
== NULL
) {
302 aprint_error(": attach failed\n");
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");
316 * XXX Don't check the keyboard port. There are broken keyboard controllers
317 * which don't pass the test but work normally otherwise.
323 if (!pckbc_send_cmd(iot
, ioh_c
, KBC_KBDTEST
))
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) {
334 printf("pckbc: returned %x on kbd slot test\n", res
);
336 if (pckbc_attach_slot(sc
, PCKBC_KBD_SLOT
))
337 cmdbits
|= KC8_KENABLE
;
339 printf("pckbc: kbd port test: %x\n", res
);
343 if (pckbc_attach_slot(sc
, PCKBC_KBD_SLOT
))
344 cmdbits
|= KC8_KENABLE
;
349 * Avoid KBC_AUXTEST because it hangs some older controllers
352 if (!pckbc_send_cmd(iot
, ioh_c
, KBC_AUXECHO
)) {
353 printf("pckbc: aux echo error 1\n");
356 if (!pckbc_wait_output(iot
, ioh_c
)) {
357 printf("pckbc: aux echo error 2\n");
361 bus_space_write_1(iot
, ioh_d
, 0, 0x5a); /* a random value */
362 res
= pckbc_poll_data1(t
, PCKBC_AUX_SLOT
);
365 * In most cases, the 0x5a gets echoed.
366 * Some older controllers (Gateway 2000 circa 1993)
368 * We are satisfied if there is anything in the
371 if (pckbc_attach_slot(sc
, PCKBC_AUX_SLOT
))
372 cmdbits
|= KC8_MENABLE
;
375 printf("pckbc: aux echo test failed\n");
381 /* enable needed interrupts */
382 t
->t_cmdbyte
|= cmdbits
;
383 if (!pckbc_put8042cmd(t
))
384 printf("pckbc: cmd word write error\n");
388 pckbc_init_slotdata(struct pckbc_slotdata
*q
)
395 * switch scancode translation on / off
396 * return nonzero on success
399 pckbc_xt_translation(void *self
, pckbc_slot_t slot
, int on
)
401 struct pckbc_internal
*t
= self
;
404 if (slot
!= PCKBC_KBD_SLOT
) {
405 /* translation only for kbd slot */
412 ison
= t
->t_cmdbyte
& KC8_TRANS
;
413 if ((on
&& ison
) || (!on
&& !ison
))
416 t
->t_cmdbyte
^= KC8_TRANS
;
417 if (!pckbc_put8042cmd(t
))
420 /* read back to be sure */
421 if (!pckbc_get8042cmd(t
))
424 ison
= t
->t_cmdbyte
& KC8_TRANS
;
425 if ((on
&& ison
) || (!on
&& !ison
))
430 static const struct pckbc_portcmd
{
431 u_char cmd_en
, cmd_dis
;
432 } pckbc_portcmd
[2] = {
434 KBC_KBDENABLE
, KBC_KBDDISABLE
,
436 KBC_AUXENABLE
, KBC_AUXDISABLE
,
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
);
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
;
461 t
->t_slotdata
[slot
]->poll_data
= -1;
462 t
->t_slotdata
[slot
]->poll_stat
= -1;
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
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
;
495 struct pckbc_slotdata
*q
;
496 int served
= 0, data
, next
, s
;
499 stat
= bus_space_read_1(t
->t_iot
, t
->t_ioh_c
, 0);
500 if (!(stat
& KBS_DIB
))
505 slot
= (t
->t_haveaux
&& (stat
& 0x20)) ?
506 PCKBC_AUX_SLOT
: PCKBC_KBD_SLOT
;
507 q
= t
->t_slotdata
[slot
];
510 /* XXX do something for live insertion? */
511 printf("pckbc: no dev for slot %d\n", slot
);
513 (void) bus_space_read_1(t
->t_iot
, t
->t_ioh_d
, 0);
518 data
= bus_space_read_1(t
->t_iot
, t
->t_ioh_d
, 0);
521 rnd_add_uint32(&q
->rnd_source
, (stat
<<8)|data
);
527 break; /* pckbc_poll_data() will get it */
531 if (CMD_IN_QUEUE(q
) && pckbc_cmdresponse(t
, slot
, data
))
536 next
= (t
->rbuf_write
+1) % PCKBC_RBUF_SIZE
;
537 if (next
== t
->rbuf_read
) {
541 t
->rbuf
[t
->rbuf_write
].data
= data
;
542 t
->rbuf
[t
->rbuf_write
].slot
= slot
;
543 t
->rbuf_write
= next
;
551 pckbcintr_soft(void *vsc
)
553 struct pckbc_softc
*sc
= vsc
;
554 struct pckbc_internal
*t
= sc
->id
;
556 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
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
;
568 pckbportintr(t
->t_pt
, slot
, data
);
574 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
582 struct pckbc_softc
*sc
= (struct pckbc_softc
*)vsc
;
583 struct pckbc_internal
*t
= sc
->id
;
586 struct pckbc_slotdata
*q
;
587 int served
= 0, data
;
590 stat
= bus_space_read_1(t
->t_iot
, t
->t_ioh_c
, 0);
591 if (!(stat
& KBS_DIB
))
596 slot
= (t
->t_haveaux
&& (stat
& 0x20)) ?
597 PCKBC_AUX_SLOT
: PCKBC_KBD_SLOT
;
598 q
= t
->t_slotdata
[slot
];
601 data
= bus_space_read_1(t
->t_iot
, t
->t_ioh_d
, 0);
604 rnd_add_uint32(&q
->rnd_source
, (stat
<<8)|data
);
607 pckbportintr(t
->t_pt
, slot
, data
);
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
623 if (bus_space_map(iot
, addr
+ KBDATAP
, 1, 0, &ioh_d
))
625 if (bus_space_map(iot
, addr
+ cmd_offset
, 1, 0, &ioh_c
)) {
626 bus_space_unmap(iot
, ioh_d
, 1);
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);
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");
651 reply
= pckbc_poll_data1(&pckbc_consdata
, PCKBC_KBD_SLOT
);
653 printf("pckbc: selftest returned 0x%02x\n", reply
);
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");
667 res
= pckbport_cnattach(&pckbc_consdata
, &pckbc_ops
, slot
);
671 bus_space_unmap(iot
, pckbc_consdata
.t_ioh_d
, 1);
672 bus_space_unmap(iot
, pckbc_consdata
.t_ioh_c
, 1);
674 pckbc_consdata
.t_slotdata
[slot
] = &pckbc_cons_slotdata
;
675 pckbc_init_slotdata(&pckbc_cons_slotdata
);
683 pckbc_resume(device_t dv
, pmf_qual_t qual
)
685 struct pckbc_softc
*sc
= device_private(dv
);
686 struct pckbc_internal
*t
;
689 (void)pckbc_poll_data1(t
, PCKBC_KBD_SLOT
);
690 if (!pckbc_send_cmd(t
->t_iot
, t
->t_ioh_c
, KBC_SELFTEST
))
692 (void)pckbc_poll_data1(t
, PCKBC_KBD_SLOT
);
693 (void)pckbc_put8042cmd(t
);