pckbc.c revision 1.31 1 /* $NetBSD: pckbc.c,v 1.31 2004/03/13 17:31:34 bjh21 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 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed for the NetBSD Project
19 * by Matthias Drochner.
20 * 4. The name of the author may not be used to endorse or promote products
21 * derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: pckbc.c,v 1.31 2004/03/13 17:31:34 bjh21 Exp $");
37
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/callout.h>
41 #include <sys/kernel.h>
42 #include <sys/proc.h>
43 #include <sys/device.h>
44 #include <sys/malloc.h>
45 #include <sys/errno.h>
46 #include <sys/queue.h>
47 #include <sys/lock.h>
48
49 #include <machine/bus.h>
50
51 #include <dev/ic/i8042reg.h>
52 #include <dev/ic/pckbcvar.h>
53
54 #include <dev/pckbport/pckbportvar.h>
55
56 #include "rnd.h"
57 #include "locators.h"
58
59 #if NRND > 0
60 #include <sys/rnd.h>
61 #endif
62
63 /* data per slave device */
64 struct pckbc_slotdata {
65 int polling; /* don't process data in interrupt handler */
66 int poll_data; /* data read from inr handler if polling */
67 int poll_stat; /* status read from inr handler if polling */
68 #if NRND > 0
69 rndsource_element_t rnd_source;
70 #endif
71 };
72
73 static void pckbc_init_slotdata __P((struct pckbc_slotdata *));
74 static int pckbc_attach_slot __P((struct pckbc_softc *, pckbc_slot_t));
75
76 struct pckbc_internal pckbc_consdata;
77 int pckbc_console_attached;
78
79 static int pckbc_console;
80 static struct pckbc_slotdata pckbc_cons_slotdata;
81
82 static int pckbc_xt_translation __P((void *, pckbport_slot_t, int));
83 static int pckbc_send_devcmd __P((void *, pckbport_slot_t, u_char));
84 static void pckbc_slot_enable __P((void *, pckbport_slot_t, int));
85 static void pckbc_intr_establish __P((void *, pckbport_slot_t));
86 static void pckbc_set_poll __P((void *, pckbc_slot_t, int on));
87
88 static int pckbc_wait_output __P((bus_space_tag_t, bus_space_handle_t));
89
90 static int pckbc_get8042cmd __P((struct pckbc_internal *));
91 static int pckbc_put8042cmd __P((struct pckbc_internal *));
92
93 void pckbc_cleanqueue __P((struct pckbc_slotdata *));
94 void pckbc_cleanup __P((void *));
95 int pckbc_cmdresponse __P((struct pckbc_internal *, pckbc_slot_t, u_char));
96 void pckbc_start __P((struct pckbc_internal *, pckbc_slot_t));
97
98 const char * const pckbc_slot_names[] = { "kbd", "aux" };
99
100 static struct pckbport_accessops const pckbc_ops = {
101 pckbc_xt_translation,
102 pckbc_send_devcmd,
103 pckbc_poll_data1,
104 pckbc_slot_enable,
105 pckbc_intr_establish,
106 pckbc_set_poll
107 };
108
109 #define KBD_DELAY DELAY(8)
110
111 static inline int
112 pckbc_wait_output(iot, ioh_c)
113 bus_space_tag_t iot;
114 bus_space_handle_t ioh_c;
115 {
116 u_int i;
117
118 for (i = 100000; i; i--)
119 if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
120 KBD_DELAY;
121 return (1);
122 }
123 return (0);
124 }
125
126 int
127 pckbc_send_cmd(iot, ioh_c, val)
128 bus_space_tag_t iot;
129 bus_space_handle_t ioh_c;
130 u_char val;
131 {
132 if (!pckbc_wait_output(iot, ioh_c))
133 return (0);
134 bus_space_write_1(iot, ioh_c, 0, val);
135 return (1);
136 }
137
138 /*
139 * Note: the spl games here are to deal with some strange PC kbd controllers
140 * in some system configurations.
141 * This is not canonical way to handle polling input.
142 */
143 int
144 pckbc_poll_data1(pt, slot)
145 void *pt;
146 pckbc_slot_t slot;
147 {
148 struct pckbc_internal *t = pt;
149 struct pckbc_slotdata *q = t->t_slotdata[slot];
150 int s;
151 u_char stat, c;
152 int i = 100000; /* if 1 port read takes 1us (?), this polls for 100ms */
153 int checkaux = t->t_haveaux;
154
155 s = splhigh();
156
157 if (q && q->polling && q->poll_data != -1 && q->poll_stat != -1) {
158 stat = q->poll_stat;
159 c = q->poll_data;
160 q->poll_data = -1;
161 q->poll_stat = -1;
162 goto process;
163 }
164
165 for (; i; i--) {
166 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
167 if (stat & KBS_DIB) {
168 KBD_DELAY;
169 c = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
170
171 process:
172 if (checkaux && (stat & 0x20)) { /* aux data */
173 if (slot != PCKBC_AUX_SLOT) {
174 #ifdef PCKBCDEBUG
175 printf("lost aux 0x%x\n", c);
176 #endif
177 continue;
178 }
179 } else {
180 if (slot == PCKBC_AUX_SLOT) {
181 #ifdef PCKBCDEBUG
182 printf("lost kbd 0x%x\n", c);
183 #endif
184 continue;
185 }
186 }
187 splx(s);
188 return (c);
189 }
190 }
191
192 splx(s);
193 return (-1);
194 }
195
196 /*
197 * Get the current command byte.
198 */
199 static int
200 pckbc_get8042cmd(t)
201 struct pckbc_internal *t;
202 {
203 bus_space_tag_t iot = t->t_iot;
204 bus_space_handle_t ioh_c = t->t_ioh_c;
205 int data;
206
207 if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
208 return (0);
209 data = pckbc_poll_data1(t, PCKBC_KBD_SLOT);
210 if (data == -1)
211 return (0);
212 t->t_cmdbyte = data;
213 return (1);
214 }
215
216 /*
217 * Pass command byte to keyboard controller (8042).
218 */
219 static int
220 pckbc_put8042cmd(t)
221 struct pckbc_internal *t;
222 {
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 (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE))
228 return (0);
229 if (!pckbc_wait_output(iot, ioh_c))
230 return (0);
231 bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte);
232 return (1);
233 }
234
235 static int
236 pckbc_send_devcmd(pt, slot, val)
237 void *pt;
238 pckbc_slot_t slot;
239 u_char val;
240 {
241 struct pckbc_internal *t = pt;
242 bus_space_tag_t iot = t->t_iot;
243 bus_space_handle_t ioh_d = t->t_ioh_d;
244 bus_space_handle_t ioh_c = t->t_ioh_c;
245
246 if (slot == PCKBC_AUX_SLOT) {
247 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
248 return (0);
249 }
250 if (!pckbc_wait_output(iot, ioh_c))
251 return (0);
252 bus_space_write_1(iot, ioh_d, 0, val);
253 return (1);
254 }
255
256 int
257 pckbc_is_console(iot, addr)
258 bus_space_tag_t iot;
259 bus_addr_t addr;
260 {
261 if (pckbc_console && !pckbc_console_attached &&
262 pckbc_consdata.t_iot == iot &&
263 pckbc_consdata.t_addr == addr)
264 return (1);
265 return (0);
266 }
267
268 static int
269 pckbc_attach_slot(sc, slot)
270 struct pckbc_softc *sc;
271 pckbc_slot_t slot;
272 {
273 struct pckbc_internal *t = sc->id;
274 struct pckbc_attach_args pa;
275 void *sdata;
276 struct device *child;
277 int alloced = 0;
278
279 pa.pa_tag = t;
280 pa.pa_slot = slot;
281
282 if (t->t_slotdata[slot] == NULL) {
283 sdata = malloc(sizeof(struct pckbc_slotdata),
284 M_DEVBUF, M_NOWAIT);
285 if (sdata == NULL) {
286 printf("%s: no memory\n", sc->sc_dv.dv_xname);
287 return (0);
288 }
289 t->t_slotdata[slot] = sdata;
290 pckbc_init_slotdata(t->t_slotdata[slot]);
291 alloced++;
292 }
293
294 child = pckbport_attach_slot(&sc->sc_dv, t->t_pt, slot);
295
296 if (child == NULL && alloced) {
297 free(t->t_slotdata[slot], M_DEVBUF);
298 t->t_slotdata[slot] = NULL;
299 }
300
301 #if NRND > 0
302 if (child != NULL && t->t_slotdata[slot] != NULL)
303 rnd_attach_source(&t->t_slotdata[slot]->rnd_source,
304 child->dv_xname, RND_TYPE_TTY, 0);
305 #endif
306 return child != NULL;
307 }
308
309 void
310 pckbc_attach(sc)
311 struct pckbc_softc *sc;
312 {
313 struct pckbc_internal *t;
314 bus_space_tag_t iot;
315 bus_space_handle_t ioh_d, ioh_c;
316 int res;
317 u_char cmdbits = 0;
318
319 t = sc->id;
320 iot = t->t_iot;
321 ioh_d = t->t_ioh_d;
322 ioh_c = t->t_ioh_c;
323
324 t->t_pt = pckbport_attach(t, &pckbc_ops);
325 if (t->t_pt == NULL) {
326 aprint_error(": attach failed\n");
327 return;
328 }
329
330 /* flush */
331 (void) pckbc_poll_data1(t, PCKBC_KBD_SLOT);
332
333 /* set initial cmd byte */
334 if (!pckbc_put8042cmd(t)) {
335 printf("kbc: cmd word write error\n");
336 return;
337 }
338
339 /*
340 * XXX Don't check the keyboard port. There are broken keyboard controllers
341 * which don't pass the test but work normally otherwise.
342 */
343 #if 0
344 /*
345 * check kbd port ok
346 */
347 if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
348 return;
349 res = pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
350
351 /*
352 * Normally, we should get a "0" here.
353 * But there are keyboard controllers behaving differently.
354 */
355 if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
356 #ifdef PCKBCDEBUG
357 if (res != 0)
358 printf("kbc: returned %x on kbd slot test\n", res);
359 #endif
360 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
361 cmdbits |= KC8_KENABLE;
362 } else {
363 printf("kbc: kbd port test: %x\n", res);
364 return;
365 }
366 #else
367 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
368 cmdbits |= KC8_KENABLE;
369 #endif /* 0 */
370
371 /*
372 * Check aux port ok.
373 * Avoid KBC_AUXTEST because it hangs some older controllers
374 * (eg UMC880?).
375 */
376 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
377 printf("kbc: aux echo error 1\n");
378 goto nomouse;
379 }
380 if (!pckbc_wait_output(iot, ioh_c)) {
381 printf("kbc: aux echo error 2\n");
382 goto nomouse;
383 }
384 t->t_haveaux = 1;
385 bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
386 res = pckbc_poll_data1(t, PCKBC_AUX_SLOT);
387 if (res != -1) {
388 /*
389 * In most cases, the 0x5a gets echoed.
390 * Some older controllers (Gateway 2000 circa 1993)
391 * return 0xfe here.
392 * We are satisfied if there is anything in the
393 * aux output buffer.
394 */
395 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
396 cmdbits |= KC8_MENABLE;
397 } else {
398 #ifdef PCKBCDEBUG
399 printf("kbc: aux echo test failed\n");
400 #endif
401 t->t_haveaux = 0;
402 }
403
404 nomouse:
405 /* enable needed interrupts */
406 t->t_cmdbyte |= cmdbits;
407 if (!pckbc_put8042cmd(t))
408 printf("kbc: cmd word write error\n");
409 }
410
411 static void
412 pckbc_init_slotdata(q)
413 struct pckbc_slotdata *q;
414 {
415
416 q->polling = 0;
417 }
418
419 /*
420 * switch scancode translation on / off
421 * return nonzero on success
422 */
423 static int
424 pckbc_xt_translation(self, slot, on)
425 void *self;
426 pckbc_slot_t slot;
427 int on;
428 {
429 struct pckbc_internal *t = self;
430 int ison;
431
432 if (slot != PCKBC_KBD_SLOT) {
433 /* translation only for kbd slot */
434 if (on)
435 return (0);
436 else
437 return (1);
438 }
439
440 ison = t->t_cmdbyte & KC8_TRANS;
441 if ((on && ison) || (!on && !ison))
442 return (1);
443
444 t->t_cmdbyte ^= KC8_TRANS;
445 if (!pckbc_put8042cmd(t))
446 return (0);
447
448 /* read back to be sure */
449 if (!pckbc_get8042cmd(t))
450 return (0);
451
452 ison = t->t_cmdbyte & KC8_TRANS;
453 if ((on && ison) || (!on && !ison))
454 return (1);
455 return (0);
456 }
457
458 static const struct pckbc_portcmd {
459 u_char cmd_en, cmd_dis;
460 } pckbc_portcmd[2] = {
461 {
462 KBC_KBDENABLE, KBC_KBDDISABLE,
463 }, {
464 KBC_AUXENABLE, KBC_AUXDISABLE,
465 }
466 };
467
468 void
469 pckbc_slot_enable(self, slot, on)
470 void *self;
471 pckbc_slot_t slot;
472 int on;
473 {
474 struct pckbc_internal *t = (struct pckbc_internal *)self;
475 const struct pckbc_portcmd *cmd;
476
477 cmd = &pckbc_portcmd[slot];
478
479 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
480 on ? cmd->cmd_en : cmd->cmd_dis))
481 printf("pckbc_slot_enable(%d) failed\n", on);
482 }
483
484 static void
485 pckbc_set_poll(self, slot, on)
486 void *self;
487 pckbc_slot_t slot;
488 int on;
489 {
490 struct pckbc_internal *t = (struct pckbc_internal *)self;
491
492 t->t_slotdata[slot]->polling = on;
493
494 if (on) {
495 t->t_slotdata[slot]->poll_data = -1;
496 t->t_slotdata[slot]->poll_stat = -1;
497 } else {
498 int s;
499
500 /*
501 * If disabling polling on a device that's been configured,
502 * make sure there are no bytes left in the FIFO, holding up
503 * the interrupt line. Otherwise we won't get any further
504 * interrupts.
505 */
506 if (t->t_sc) {
507 s = spltty();
508 pckbcintr(t->t_sc);
509 splx(s);
510 }
511 }
512 }
513
514 static void
515 pckbc_intr_establish(pt, slot)
516 void *pt;
517 pckbport_slot_t slot;
518 {
519 struct pckbc_internal *t = pt;
520
521 (*t->t_sc->intr_establish)(t->t_sc, slot);
522 }
523
524 int
525 pckbcintr_hard(vsc)
526 void *vsc;
527 {
528 struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
529 struct pckbc_internal *t = sc->id;
530 u_char stat;
531 pckbc_slot_t slot;
532 struct pckbc_slotdata *q;
533 int served = 0, data, next, s;
534
535 for(;;) {
536 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
537 if (!(stat & KBS_DIB))
538 break;
539
540 served = 1;
541
542 slot = (t->t_haveaux && (stat & 0x20)) ?
543 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
544 q = t->t_slotdata[slot];
545
546 if (!q) {
547 /* XXX do something for live insertion? */
548 printf("pckbcintr: no dev for slot %d\n", slot);
549 KBD_DELAY;
550 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
551 continue;
552 }
553
554 KBD_DELAY;
555 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
556
557 #if NRND > 0
558 rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
559 #endif
560
561 if (q->polling) {
562 q->poll_data = data;
563 q->poll_stat = stat;
564 break; /* pckbc_poll_data() will get it */
565 }
566
567 #if 0 /* XXXBJH */
568 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
569 continue;
570 #endif
571
572 s = splhigh();
573 next = (t->rbuf_write+1) % PCKBC_RBUF_SIZE;
574 if (next == t->rbuf_read) {
575 splx(s);
576 break;
577 }
578 t->rbuf[t->rbuf_write].data = data;
579 t->rbuf[t->rbuf_write].slot = slot;
580 t->rbuf_write = next;
581 splx(s);
582 }
583
584 return (served);
585 }
586
587 void
588 pckbcintr_soft(vsc)
589 void *vsc;
590 {
591 struct pckbc_softc *sc = vsc;
592 struct pckbc_internal *t = sc->id;
593 int data, slot, s;
594 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
595 int st;
596
597 st = spltty();
598 #endif
599
600 s = splhigh();
601 while (t->rbuf_read != t->rbuf_write) {
602 slot = t->rbuf[t->rbuf_read].slot;
603 data = t->rbuf[t->rbuf_read].data;
604 t->rbuf_read = (t->rbuf_read+1) % PCKBC_RBUF_SIZE;
605 splx(s);
606 pckbportintr(t->t_pt, slot, data);
607 s = splhigh();
608 }
609 splx(s);
610
611
612 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
613 splx(st);
614 #endif
615 }
616
617 int
618 pckbcintr(vsc)
619 void *vsc;
620 {
621 struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
622 struct pckbc_internal *t = sc->id;
623 u_char stat;
624 pckbc_slot_t slot;
625 struct pckbc_slotdata *q;
626 int served = 0, data;
627
628 for(;;) {
629 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
630 if (!(stat & KBS_DIB))
631 break;
632
633 served = 1;
634
635 slot = (t->t_haveaux && (stat & 0x20)) ?
636 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
637 q = t->t_slotdata[slot];
638
639 KBD_DELAY;
640 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
641
642 #if NRND > 0
643 rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
644 #endif
645
646 pckbportintr(t->t_pt, slot, data);
647 }
648
649 return (served);
650 }
651
652 int
653 pckbc_cnattach(iot, addr, cmd_offset, slot)
654 bus_space_tag_t iot;
655 bus_addr_t addr;
656 bus_size_t cmd_offset;
657 pckbc_slot_t slot;
658 {
659 bus_space_handle_t ioh_d, ioh_c;
660 #ifdef PCKBC_CNATTACH_SELFTEST
661 int reply;
662 #endif
663 int res = 0;
664
665 if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
666 return (ENXIO);
667 if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
668 bus_space_unmap(iot, ioh_d, 1);
669 return (ENXIO);
670 }
671
672 memset(&pckbc_consdata, 0, sizeof(pckbc_consdata));
673 pckbc_consdata.t_iot = iot;
674 pckbc_consdata.t_ioh_d = ioh_d;
675 pckbc_consdata.t_ioh_c = ioh_c;
676 pckbc_consdata.t_addr = addr;
677 callout_init(&pckbc_consdata.t_cleanup);
678
679 /* flush */
680 (void) pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
681
682 #ifdef PCKBC_CNATTACH_SELFTEST
683 /*
684 * In some machines (e.g. netwinder) pckbc refuses to talk at
685 * all until we request a self-test.
686 */
687 if (!pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST)) {
688 printf("kbc: unable to request selftest\n");
689 res = EIO;
690 goto out;
691 }
692
693 reply = pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
694 if (reply != 0x55) {
695 printf("kbc: selftest returned 0x%02x\n", reply);
696 res = EIO;
697 goto out;
698 }
699 #endif /* PCKBC_CNATTACH_SELFTEST */
700
701 /* init cmd byte, enable ports */
702 pckbc_consdata.t_cmdbyte = KC8_CPU;
703 if (!pckbc_put8042cmd(&pckbc_consdata)) {
704 printf("kbc: cmd word write error\n");
705 res = EIO;
706 goto out;
707 }
708
709 res = pckbport_cnattach(&pckbc_consdata, &pckbc_ops, slot);
710
711 out:
712 if (res) {
713 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
714 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
715 } else {
716 pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
717 pckbc_init_slotdata(&pckbc_cons_slotdata);
718 pckbc_console = 1;
719 }
720
721 return (res);
722 }
723