pckbc.c revision 1.49 1 /* $NetBSD: pckbc.c,v 1.49 2010/03/22 23:08:34 dyoung Exp $ */
2
3 /*
4 * Copyright (c) 2004 Ben Harris.
5 * Copyright (c) 1998
6 * Matthias Drochner. All rights reserved.
7 *
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.
16 *
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.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: pckbc.c,v 1.49 2010/03/22 23:08:34 dyoung Exp $");
31
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>
41
42 #include <sys/bus.h>
43
44 #include <dev/ic/i8042reg.h>
45 #include <dev/ic/pckbcvar.h>
46
47 #include <dev/pckbport/pckbportvar.h>
48
49 #include "rnd.h"
50 #include "locators.h"
51
52 #if NRND > 0
53 #include <sys/rnd.h>
54 #endif
55
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
64 };
65
66 static void pckbc_init_slotdata(struct pckbc_slotdata *);
67 static int pckbc_attach_slot(struct pckbc_softc *, pckbc_slot_t);
68
69 struct pckbc_internal pckbc_consdata;
70 int pckbc_console_attached;
71
72 static int pckbc_console;
73 static struct pckbc_slotdata pckbc_cons_slotdata;
74
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);
80
81 static int pckbc_wait_output(bus_space_tag_t, bus_space_handle_t);
82
83 static int pckbc_get8042cmd(struct pckbc_internal *);
84 static int pckbc_put8042cmd(struct pckbc_internal *);
85
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);
90
91 const char * const pckbc_slot_names[] = { "kbd", "aux" };
92
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
100 };
101
102 #define KBD_DELAY DELAY(8)
103
104 static inline int
105 pckbc_wait_output(bus_space_tag_t iot, bus_space_handle_t ioh_c)
106 {
107 u_int i;
108
109 for (i = 100000; i; i--)
110 if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
111 KBD_DELAY;
112 return (1);
113 }
114 return (0);
115 }
116
117 int
118 pckbc_send_cmd(bus_space_tag_t iot, bus_space_handle_t ioh_c, u_char val)
119 {
120 if (!pckbc_wait_output(iot, ioh_c))
121 return (0);
122 bus_space_write_1(iot, ioh_c, 0, val);
123 return (1);
124 }
125
126 /*
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.
130 */
131 int
132 pckbc_poll_data1(void *pt, pckbc_slot_t slot)
133 {
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;
140
141 s = splhigh();
142
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;
149 }
150
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);
156
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;
164 }
165 } else {
166 if (slot == PCKBC_AUX_SLOT) {
167 #ifdef PCKBCDEBUG
168 printf("pckbc: lost kbd 0x%x\n", c);
169 #endif
170 continue;
171 }
172 }
173 splx(s);
174 return (c);
175 }
176 }
177
178 splx(s);
179 return (-1);
180 }
181
182 /*
183 * Get the current command byte.
184 */
185 static int
186 pckbc_get8042cmd(struct pckbc_internal *t)
187 {
188 bus_space_tag_t iot = t->t_iot;
189 bus_space_handle_t ioh_c = t->t_ioh_c;
190 int data;
191
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);
199 }
200
201 /*
202 * Pass command byte to keyboard controller (8042).
203 */
204 static int
205 pckbc_put8042cmd(struct pckbc_internal *t)
206 {
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;
210
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);
217 }
218
219 static int
220 pckbc_send_devcmd(void *pt, pckbc_slot_t slot, u_char val)
221 {
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;
226
227 if (slot == PCKBC_AUX_SLOT) {
228 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
229 return (0);
230 }
231 if (!pckbc_wait_output(iot, ioh_c))
232 return (0);
233 bus_space_write_1(iot, ioh_d, 0, val);
234 return (1);
235 }
236
237 int
238 pckbc_is_console(bus_space_tag_t iot, bus_addr_t addr)
239 {
240 if (pckbc_console && !pckbc_console_attached &&
241 #if 0 /* XXX Comparing bus_space_tag_t is a no-no! */
242 pckbc_consdata.t_iot == iot &&
243 #endif
244 pckbc_consdata.t_addr == addr)
245 return (1);
246 return (0);
247 }
248
249 static int
250 pckbc_attach_slot(struct pckbc_softc *sc, pckbc_slot_t slot)
251 {
252 struct pckbc_internal *t = sc->id;
253 struct pckbc_attach_args pa;
254 void *sdata;
255 device_t child;
256 int alloced = 0;
257
258 pa.pa_tag = t;
259 pa.pa_slot = slot;
260
261 if (t->t_slotdata[slot] == NULL) {
262 sdata = malloc(sizeof(struct pckbc_slotdata),
263 M_DEVBUF, M_NOWAIT);
264 if (sdata == NULL) {
265 aprint_error_dev(sc->sc_dv, "no memory\n");
266 return (0);
267 }
268 t->t_slotdata[slot] = sdata;
269 pckbc_init_slotdata(t->t_slotdata[slot]);
270 alloced++;
271 }
272
273 child = pckbport_attach_slot(sc->sc_dv, t->t_pt, slot);
274
275 if (child == NULL && alloced) {
276 free(t->t_slotdata[slot], M_DEVBUF);
277 t->t_slotdata[slot] = NULL;
278 }
279
280 #if NRND > 0
281 if (child != NULL && t->t_slotdata[slot] != NULL)
282 rnd_attach_source(&t->t_slotdata[slot]->rnd_source,
283 device_xname(child), RND_TYPE_TTY, 0);
284 #endif
285 return child != NULL;
286 }
287
288 void
289 pckbc_attach(struct pckbc_softc *sc)
290 {
291 struct pckbc_internal *t;
292 bus_space_tag_t iot;
293 bus_space_handle_t ioh_d, ioh_c;
294 int res;
295 u_char cmdbits = 0;
296
297 t = sc->id;
298 iot = t->t_iot;
299 ioh_d = t->t_ioh_d;
300 ioh_c = t->t_ioh_c;
301
302 t->t_pt = pckbport_attach(t, &pckbc_ops);
303 if (t->t_pt == NULL) {
304 aprint_error(": attach failed\n");
305 return;
306 }
307
308 /* flush */
309 (void) pckbc_poll_data1(t, PCKBC_KBD_SLOT);
310
311 /* set initial cmd byte */
312 if (!pckbc_put8042cmd(t)) {
313 printf("pckbc: cmd word write error\n");
314 return;
315 }
316
317 /*
318 * XXX Don't check the keyboard port. There are broken keyboard controllers
319 * which don't pass the test but work normally otherwise.
320 */
321 #if 0
322 /*
323 * check kbd port ok
324 */
325 if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
326 return;
327 res = pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
328
329 /*
330 * Normally, we should get a "0" here.
331 * But there are keyboard controllers behaving differently.
332 */
333 if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
334 #ifdef PCKBCDEBUG
335 if (res != 0)
336 printf("pckbc: returned %x on kbd slot test\n", res);
337 #endif
338 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
339 cmdbits |= KC8_KENABLE;
340 } else {
341 printf("pckbc: kbd port test: %x\n", res);
342 return;
343 }
344 #else
345 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
346 cmdbits |= KC8_KENABLE;
347 #endif /* 0 */
348
349 /*
350 * Check aux port ok.
351 * Avoid KBC_AUXTEST because it hangs some older controllers
352 * (eg UMC880?).
353 */
354 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
355 printf("pckbc: aux echo error 1\n");
356 goto nomouse;
357 }
358 if (!pckbc_wait_output(iot, ioh_c)) {
359 printf("pckbc: aux echo error 2\n");
360 goto nomouse;
361 }
362 t->t_haveaux = 1;
363 bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
364 res = pckbc_poll_data1(t, PCKBC_AUX_SLOT);
365 if (res != -1) {
366 /*
367 * In most cases, the 0x5a gets echoed.
368 * Some older controllers (Gateway 2000 circa 1993)
369 * return 0xfe here.
370 * We are satisfied if there is anything in the
371 * aux output buffer.
372 */
373 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
374 cmdbits |= KC8_MENABLE;
375 } else {
376 #ifdef PCKBCDEBUG
377 printf("pckbc: aux echo test failed\n");
378 #endif
379 t->t_haveaux = 0;
380 }
381
382 nomouse:
383 /* enable needed interrupts */
384 t->t_cmdbyte |= cmdbits;
385 if (!pckbc_put8042cmd(t))
386 printf("pckbc: cmd word write error\n");
387 }
388
389 static void
390 pckbc_init_slotdata(struct pckbc_slotdata *q)
391 {
392
393 q->polling = 0;
394 }
395
396 /*
397 * switch scancode translation on / off
398 * return nonzero on success
399 */
400 static int
401 pckbc_xt_translation(void *self, pckbc_slot_t slot, int on)
402 {
403 struct pckbc_internal *t = self;
404 int ison;
405
406 if (slot != PCKBC_KBD_SLOT) {
407 /* translation only for kbd slot */
408 if (on)
409 return (0);
410 else
411 return (1);
412 }
413
414 ison = t->t_cmdbyte & KC8_TRANS;
415 if ((on && ison) || (!on && !ison))
416 return (1);
417
418 t->t_cmdbyte ^= KC8_TRANS;
419 if (!pckbc_put8042cmd(t))
420 return (0);
421
422 /* read back to be sure */
423 if (!pckbc_get8042cmd(t))
424 return (0);
425
426 ison = t->t_cmdbyte & KC8_TRANS;
427 if ((on && ison) || (!on && !ison))
428 return (1);
429 return (0);
430 }
431
432 static const struct pckbc_portcmd {
433 u_char cmd_en, cmd_dis;
434 } pckbc_portcmd[2] = {
435 {
436 KBC_KBDENABLE, KBC_KBDDISABLE,
437 }, {
438 KBC_AUXENABLE, KBC_AUXDISABLE,
439 }
440 };
441
442 void
443 pckbc_slot_enable(void *self, pckbc_slot_t slot, int on)
444 {
445 struct pckbc_internal *t = (struct pckbc_internal *)self;
446 const struct pckbc_portcmd *cmd;
447
448 cmd = &pckbc_portcmd[slot];
449
450 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
451 on ? cmd->cmd_en : cmd->cmd_dis))
452 printf("pckbc: pckbc_slot_enable(%d) failed\n", on);
453 }
454
455 static void
456 pckbc_set_poll(void *self, pckbc_slot_t slot, int on)
457 {
458 struct pckbc_internal *t = (struct pckbc_internal *)self;
459
460 t->t_slotdata[slot]->polling = on;
461
462 if (on) {
463 t->t_slotdata[slot]->poll_data = -1;
464 t->t_slotdata[slot]->poll_stat = -1;
465 } else {
466 int s;
467
468 /*
469 * If disabling polling on a device that's been configured,
470 * make sure there are no bytes left in the FIFO, holding up
471 * the interrupt line. Otherwise we won't get any further
472 * interrupts.
473 */
474 if (t->t_sc) {
475 s = spltty();
476 pckbcintr(t->t_sc);
477 splx(s);
478 }
479 }
480 }
481
482 static void
483 pckbc_intr_establish(void *pt, pckbport_slot_t slot)
484 {
485 struct pckbc_internal *t = pt;
486
487 (*t->t_sc->intr_establish)(t->t_sc, slot);
488 }
489
490 int
491 pckbcintr_hard(void *vsc)
492 {
493 struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
494 struct pckbc_internal *t = sc->id;
495 u_char stat;
496 pckbc_slot_t slot;
497 struct pckbc_slotdata *q;
498 int served = 0, data, next, s;
499
500 for(;;) {
501 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
502 if (!(stat & KBS_DIB))
503 break;
504
505 served = 1;
506
507 slot = (t->t_haveaux && (stat & 0x20)) ?
508 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
509 q = t->t_slotdata[slot];
510
511 if (!q) {
512 /* XXX do something for live insertion? */
513 printf("pckbc: no dev for slot %d\n", slot);
514 KBD_DELAY;
515 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
516 continue;
517 }
518
519 KBD_DELAY;
520 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
521
522 #if NRND > 0
523 rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
524 #endif
525
526 if (q->polling) {
527 q->poll_data = data;
528 q->poll_stat = stat;
529 break; /* pckbc_poll_data() will get it */
530 }
531
532 #if 0 /* XXXBJH */
533 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
534 continue;
535 #endif
536
537 s = splhigh();
538 next = (t->rbuf_write+1) % PCKBC_RBUF_SIZE;
539 if (next == t->rbuf_read) {
540 splx(s);
541 break;
542 }
543 t->rbuf[t->rbuf_write].data = data;
544 t->rbuf[t->rbuf_write].slot = slot;
545 t->rbuf_write = next;
546 splx(s);
547 }
548
549 return (served);
550 }
551
552 void
553 pckbcintr_soft(void *vsc)
554 {
555 struct pckbc_softc *sc = vsc;
556 struct pckbc_internal *t = sc->id;
557 int data, slot, s;
558 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
559 int st;
560
561 st = spltty();
562 #endif
563
564 s = splhigh();
565 while (t->rbuf_read != t->rbuf_write) {
566 slot = t->rbuf[t->rbuf_read].slot;
567 data = t->rbuf[t->rbuf_read].data;
568 t->rbuf_read = (t->rbuf_read+1) % PCKBC_RBUF_SIZE;
569 splx(s);
570 pckbportintr(t->t_pt, slot, data);
571 s = splhigh();
572 }
573 splx(s);
574
575
576 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
577 splx(st);
578 #endif
579 }
580
581 int
582 pckbcintr(void *vsc)
583 {
584 struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
585 struct pckbc_internal *t = sc->id;
586 u_char stat;
587 pckbc_slot_t slot;
588 struct pckbc_slotdata *q;
589 int served = 0, data;
590
591 for(;;) {
592 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
593 if (!(stat & KBS_DIB))
594 break;
595
596 served = 1;
597
598 slot = (t->t_haveaux && (stat & 0x20)) ?
599 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
600 q = t->t_slotdata[slot];
601
602 KBD_DELAY;
603 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
604
605 #if NRND > 0
606 rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
607 #endif
608
609 pckbportintr(t->t_pt, slot, data);
610 }
611
612 return (served);
613 }
614
615 int
616 pckbc_cnattach(bus_space_tag_t iot, bus_addr_t addr,
617 bus_size_t cmd_offset, pckbc_slot_t slot)
618 {
619 bus_space_handle_t ioh_d, ioh_c;
620 #ifdef PCKBC_CNATTACH_SELFTEST
621 int reply;
622 #endif
623 int res = 0;
624
625 if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
626 return (ENXIO);
627 if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
628 bus_space_unmap(iot, ioh_d, 1);
629 return (ENXIO);
630 }
631
632 memset(&pckbc_consdata, 0, sizeof(pckbc_consdata));
633 pckbc_consdata.t_iot = iot;
634 pckbc_consdata.t_ioh_d = ioh_d;
635 pckbc_consdata.t_ioh_c = ioh_c;
636 pckbc_consdata.t_addr = addr;
637 callout_init(&pckbc_consdata.t_cleanup, 0);
638
639 /* flush */
640 (void) pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
641
642 #ifdef PCKBC_CNATTACH_SELFTEST
643 /*
644 * In some machines (e.g. netwinder) pckbc refuses to talk at
645 * all until we request a self-test.
646 */
647 if (!pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST)) {
648 printf("pckbc: unable to request selftest\n");
649 res = EIO;
650 goto out;
651 }
652
653 reply = pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
654 if (reply != 0x55) {
655 printf("pckbc: selftest returned 0x%02x\n", reply);
656 res = EIO;
657 goto out;
658 }
659 #endif /* PCKBC_CNATTACH_SELFTEST */
660
661 /* init cmd byte, enable ports */
662 pckbc_consdata.t_cmdbyte = KC8_CPU;
663 if (!pckbc_put8042cmd(&pckbc_consdata)) {
664 printf("pckbc: cmd word write error\n");
665 res = EIO;
666 goto out;
667 }
668
669 res = pckbport_cnattach(&pckbc_consdata, &pckbc_ops, slot);
670
671 out:
672 if (res) {
673 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
674 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
675 } else {
676 pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
677 pckbc_init_slotdata(&pckbc_cons_slotdata);
678 pckbc_console = 1;
679 }
680
681 return (res);
682 }
683
684 bool
685 pckbc_resume(device_t dv, const pmf_qual_t *qual)
686 {
687 struct pckbc_softc *sc = device_private(dv);
688 struct pckbc_internal *t;
689
690 t = sc->id;
691 (void)pckbc_poll_data1(t, PCKBC_KBD_SLOT);
692 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c, KBC_SELFTEST))
693 return false;
694 (void)pckbc_poll_data1(t, PCKBC_KBD_SLOT);
695 (void)pckbc_put8042cmd(t);
696 pckbcintr(t->t_sc);
697
698 return true;
699 }
700