pckbc.c revision 1.20 1 /* $NetBSD: pckbc.c,v 1.20 2001/12/15 13:23:22 soren Exp $ */
2
3 /*
4 * Copyright (c) 1998
5 * Matthias Drochner. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the NetBSD Project
18 * by Matthias Drochner.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: pckbc.c,v 1.20 2001/12/15 13:23:22 soren Exp $");
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/callout.h>
40 #include <sys/kernel.h>
41 #include <sys/proc.h>
42 #include <sys/device.h>
43 #include <sys/malloc.h>
44 #include <sys/errno.h>
45 #include <sys/queue.h>
46 #include <sys/lock.h>
47
48 #include <machine/bus.h>
49
50 #include <dev/ic/i8042reg.h>
51 #include <dev/ic/pckbcvar.h>
52
53 #include "rnd.h"
54 #include "locators.h"
55
56 /* XXX for pcconskbd_cnattach() prototype */
57 #ifdef __BROKEN_HAS_PCCONS
58 #include <machine/pccons.h>
59 #endif
60
61 #include "pckbd.h"
62
63 #if (NPCKBD > 0)
64 #include <dev/pckbc/pckbdvar.h>
65 #endif
66 #if NRND > 0
67 #include <sys/rnd.h>
68 #endif
69
70 /* descriptor for one device command */
71 struct pckbc_devcmd {
72 TAILQ_ENTRY(pckbc_devcmd) next;
73 int flags;
74 #define KBC_CMDFLAG_SYNC 1 /* give descriptor back to caller */
75 #define KBC_CMDFLAG_SLOW 2
76 u_char cmd[4];
77 int cmdlen, cmdidx, retries;
78 u_char response[4];
79 int status, responselen, responseidx;
80 };
81
82 /* data per slave device */
83 struct pckbc_slotdata {
84 int polling; /* don't process data in interrupt handler */
85 int poll_data; /* data read from inr handler if polling */
86 int poll_stat; /* status read from inr handler if polling */
87 TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* active commands */
88 TAILQ_HEAD(, pckbc_devcmd) freequeue; /* free commands */
89 #define NCMD 5
90 struct pckbc_devcmd cmds[NCMD];
91 #if NRND > 0
92 rndsource_element_t rnd_source;
93 #endif
94 };
95
96 #define CMD_IN_QUEUE(q) (TAILQ_FIRST(&(q)->cmdqueue) != NULL)
97
98 void pckbc_init_slotdata __P((struct pckbc_slotdata *));
99 int pckbc_attach_slot __P((struct pckbc_softc *, pckbc_slot_t));
100 int pckbc_submatch __P((struct device *, struct cfdata *, void *));
101 int pckbcprint __P((void *, const char *));
102
103 struct pckbc_internal pckbc_consdata;
104 int pckbc_console_attached;
105
106 static int pckbc_console;
107 static struct pckbc_slotdata pckbc_cons_slotdata;
108
109 static int pckbc_wait_output __P((bus_space_tag_t, bus_space_handle_t));
110
111 static int pckbc_get8042cmd __P((struct pckbc_internal *));
112 static int pckbc_put8042cmd __P((struct pckbc_internal *));
113 static int pckbc_send_devcmd __P((struct pckbc_internal *, pckbc_slot_t,
114 u_char));
115 static void pckbc_poll_cmd1 __P((struct pckbc_internal *, pckbc_slot_t,
116 struct pckbc_devcmd *));
117
118 void pckbc_cleanqueue __P((struct pckbc_slotdata *));
119 void pckbc_cleanup __P((void *));
120 int pckbc_cmdresponse __P((struct pckbc_internal *, pckbc_slot_t, u_char));
121 void pckbc_start __P((struct pckbc_internal *, pckbc_slot_t));
122
123 const char * const pckbc_slot_names[] = { "kbd", "aux" };
124
125 #define KBC_DEVCMD_ACK 0xfa
126 #define KBC_DEVCMD_RESEND 0xfe
127
128 #define KBD_DELAY DELAY(8)
129
130 static inline int
131 pckbc_wait_output(iot, ioh_c)
132 bus_space_tag_t iot;
133 bus_space_handle_t ioh_c;
134 {
135 u_int i;
136
137 for (i = 100000; i; i--)
138 if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
139 KBD_DELAY;
140 return (1);
141 }
142 return (0);
143 }
144
145 int
146 pckbc_send_cmd(iot, ioh_c, val)
147 bus_space_tag_t iot;
148 bus_space_handle_t ioh_c;
149 u_char val;
150 {
151 if (!pckbc_wait_output(iot, ioh_c))
152 return (0);
153 bus_space_write_1(iot, ioh_c, 0, val);
154 return (1);
155 }
156
157 /*
158 * Note: the spl games here are to deal with some strange PC kbd controllers
159 * in some system configurations.
160 * This is not canonical way to handle polling input.
161 */
162 int
163 pckbc_poll_data1(pt, slot, checkaux)
164 pckbc_tag_t pt;
165 pckbc_slot_t slot;
166 int checkaux;
167 {
168 struct pckbc_internal *t = pt;
169 struct pckbc_slotdata *q = t->t_slotdata[slot];
170 int i, s;
171 u_char stat, c;
172
173 s = splhigh();
174
175 if (q && q->polling && q->poll_data != -1 && q->poll_stat != -1) {
176 stat = q->poll_stat;
177 c = q->poll_data;
178 q->poll_data = -1;
179 q->poll_stat = -1;
180 goto process;
181 }
182
183 /* if 1 port read takes 1us (?), this polls for 100ms */
184 for (i = 100000; i; i--) {
185 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
186 if (stat & KBS_DIB) {
187 KBD_DELAY;
188 c = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
189
190 process:
191 if (checkaux && (stat & 0x20)) { /* aux data */
192 if (slot != PCKBC_AUX_SLOT) {
193 #ifdef PCKBCDEBUG
194 printf("lost aux 0x%x\n", c);
195 #endif
196 continue;
197 }
198 } else {
199 if (slot == PCKBC_AUX_SLOT) {
200 #ifdef PCKBCDEBUG
201 printf("lost kbd 0x%x\n", c);
202 #endif
203 continue;
204 }
205 }
206 splx(s);
207 return (c);
208 }
209 }
210
211 splx(s);
212 return (-1);
213 }
214
215 /*
216 * Get the current command byte.
217 */
218 static int
219 pckbc_get8042cmd(t)
220 struct pckbc_internal *t;
221 {
222 bus_space_tag_t iot = t->t_iot;
223 bus_space_handle_t ioh_c = t->t_ioh_c;
224 int data;
225
226 if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
227 return (0);
228 data = pckbc_poll_data1(t, PCKBC_KBD_SLOT, t->t_haveaux);
229 if (data == -1)
230 return (0);
231 t->t_cmdbyte = data;
232 return (1);
233 }
234
235 /*
236 * Pass command byte to keyboard controller (8042).
237 */
238 static int
239 pckbc_put8042cmd(t)
240 struct pckbc_internal *t;
241 {
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 (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE))
247 return (0);
248 if (!pckbc_wait_output(iot, ioh_c))
249 return (0);
250 bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte);
251 return (1);
252 }
253
254 static int
255 pckbc_send_devcmd(t, slot, val)
256 struct pckbc_internal *t;
257 pckbc_slot_t slot;
258 u_char val;
259 {
260 bus_space_tag_t iot = t->t_iot;
261 bus_space_handle_t ioh_d = t->t_ioh_d;
262 bus_space_handle_t ioh_c = t->t_ioh_c;
263
264 if (slot == PCKBC_AUX_SLOT) {
265 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
266 return (0);
267 }
268 if (!pckbc_wait_output(iot, ioh_c))
269 return (0);
270 bus_space_write_1(iot, ioh_d, 0, val);
271 return (1);
272 }
273
274 int
275 pckbc_is_console(iot, addr)
276 bus_space_tag_t iot;
277 bus_addr_t addr;
278 {
279 if (pckbc_console && !pckbc_console_attached &&
280 pckbc_consdata.t_iot == iot &&
281 pckbc_consdata.t_addr == addr)
282 return (1);
283 return (0);
284 }
285
286 int
287 pckbc_submatch(parent, cf, aux)
288 struct device *parent;
289 struct cfdata *cf;
290 void *aux;
291 {
292 struct pckbc_attach_args *pa = aux;
293
294 if (cf->cf_loc[PCKBCCF_SLOT] != PCKBCCF_SLOT_DEFAULT &&
295 cf->cf_loc[PCKBCCF_SLOT] != pa->pa_slot)
296 return (0);
297 return ((*cf->cf_attach->ca_match)(parent, cf, aux));
298 }
299
300 int
301 pckbc_attach_slot(sc, slot)
302 struct pckbc_softc *sc;
303 pckbc_slot_t slot;
304 {
305 struct pckbc_internal *t = sc->id;
306 struct pckbc_attach_args pa;
307 void *sdata;
308 int found;
309 int alloced = 0;
310
311 pa.pa_tag = t;
312 pa.pa_slot = slot;
313
314 if (t->t_slotdata[slot] == NULL) {
315 sdata = malloc(sizeof(struct pckbc_slotdata),
316 M_DEVBUF, M_NOWAIT);
317 if (sdata == NULL) {
318 printf("%s: no memory\n", sc->sc_dv.dv_xname);
319 return (0);
320 }
321 t->t_slotdata[slot] = sdata;
322 pckbc_init_slotdata(t->t_slotdata[slot]);
323 alloced++;
324 }
325
326 found = (config_found_sm((struct device *)sc, &pa,
327 pckbcprint, pckbc_submatch) != NULL);
328
329 if (!found && alloced) {
330 free(t->t_slotdata[slot], M_DEVBUF);
331 t->t_slotdata[slot] = NULL;
332 }
333
334 #if NRND > 0
335 if (found && (t->t_slotdata[slot] != NULL))
336 rnd_attach_source(&t->t_slotdata[slot]->rnd_source,
337 sc->subname[slot], RND_TYPE_TTY, 0);
338 #endif
339 return (found);
340 }
341
342 void
343 pckbc_attach(sc)
344 struct pckbc_softc *sc;
345 {
346 struct pckbc_internal *t;
347 bus_space_tag_t iot;
348 bus_space_handle_t ioh_d, ioh_c;
349 int res;
350 u_char cmdbits = 0;
351
352 t = sc->id;
353 iot = t->t_iot;
354 ioh_d = t->t_ioh_d;
355 ioh_c = t->t_ioh_c;
356
357 /* flush */
358 (void) pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
359
360 /* set initial cmd byte */
361 if (!pckbc_put8042cmd(t)) {
362 printf("kbc: cmd word write error\n");
363 return;
364 }
365
366 /*
367 * XXX Don't check the keyboard port. There are broken keyboard controllers
368 * which don't pass the test but work normally otherwise.
369 */
370 #if 0
371 /*
372 * check kbd port ok
373 */
374 if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
375 return;
376 res = pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
377
378 /*
379 * Normally, we should get a "0" here.
380 * But there are keyboard controllers behaving differently.
381 */
382 if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
383 #ifdef PCKBCDEBUG
384 if (res != 0)
385 printf("kbc: returned %x on kbd slot test\n", res);
386 #endif
387 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
388 cmdbits |= KC8_KENABLE;
389 } else {
390 printf("kbc: kbd port test: %x\n", res);
391 return;
392 }
393 #else
394 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
395 cmdbits |= KC8_KENABLE;
396 #endif /* 0 */
397
398 /*
399 * Check aux port ok.
400 * Avoid KBC_AUXTEST because it hangs some older controllers
401 * (eg UMC880?).
402 */
403 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
404 printf("kbc: aux echo error 1\n");
405 goto nomouse;
406 }
407 if (!pckbc_wait_output(iot, ioh_c)) {
408 printf("kbc: aux echo error 2\n");
409 goto nomouse;
410 }
411 bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
412 res = pckbc_poll_data1(t, PCKBC_AUX_SLOT, 1);
413 if (res != -1) {
414 /*
415 * In most cases, the 0x5a gets echoed.
416 * Some older controllers (Gateway 2000 circa 1993)
417 * return 0xfe here.
418 * We are satisfied if there is anything in the
419 * aux output buffer.
420 */
421 t->t_haveaux = 1;
422 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
423 cmdbits |= KC8_MENABLE;
424 }
425 #ifdef PCKBCDEBUG
426 else
427 printf("kbc: aux echo test failed\n");
428 #endif
429
430 nomouse:
431 /* enable needed interrupts */
432 t->t_cmdbyte |= cmdbits;
433 if (!pckbc_put8042cmd(t))
434 printf("kbc: cmd word write error\n");
435 }
436
437 int
438 pckbcprint(aux, pnp)
439 void *aux;
440 const char *pnp;
441 {
442 struct pckbc_attach_args *pa = aux;
443
444 if (!pnp)
445 printf(" (%s slot)", pckbc_slot_names[pa->pa_slot]);
446 return (QUIET);
447 }
448
449 void
450 pckbc_init_slotdata(q)
451 struct pckbc_slotdata *q;
452 {
453 int i;
454 TAILQ_INIT(&q->cmdqueue);
455 TAILQ_INIT(&q->freequeue);
456
457 for (i = 0; i < NCMD; i++) {
458 TAILQ_INSERT_TAIL(&q->freequeue, &(q->cmds[i]), next);
459 }
460 q->polling = 0;
461 }
462
463 void
464 pckbc_flush(self, slot)
465 pckbc_tag_t self;
466 pckbc_slot_t slot;
467 {
468 struct pckbc_internal *t = self;
469
470 (void) pckbc_poll_data1(t, slot, t->t_haveaux);
471 }
472
473 int
474 pckbc_poll_data(self, slot)
475 pckbc_tag_t self;
476 pckbc_slot_t slot;
477 {
478 struct pckbc_internal *t = self;
479 struct pckbc_slotdata *q = t->t_slotdata[slot];
480 int c;
481
482 c = pckbc_poll_data1(t, slot, t->t_haveaux);
483 if (c != -1 && q && CMD_IN_QUEUE(q)) {
484 /* we jumped into a running command - try to
485 deliver the response */
486 if (pckbc_cmdresponse(t, slot, c))
487 return (-1);
488 }
489 return (c);
490 }
491
492 /*
493 * switch scancode translation on / off
494 * return nonzero on success
495 */
496 int
497 pckbc_xt_translation(self, slot, on)
498 pckbc_tag_t self;
499 pckbc_slot_t slot;
500 int on;
501 {
502 struct pckbc_internal *t = self;
503 int ison;
504
505 if (slot != PCKBC_KBD_SLOT) {
506 /* translation only for kbd slot */
507 if (on)
508 return (0);
509 else
510 return (1);
511 }
512
513 ison = t->t_cmdbyte & KC8_TRANS;
514 if ((on && ison) || (!on && !ison))
515 return (1);
516
517 t->t_cmdbyte ^= KC8_TRANS;
518 if (!pckbc_put8042cmd(t))
519 return (0);
520
521 /* read back to be sure */
522 if (!pckbc_get8042cmd(t))
523 return (0);
524
525 ison = t->t_cmdbyte & KC8_TRANS;
526 if ((on && ison) || (!on && !ison))
527 return (1);
528 return (0);
529 }
530
531 static const struct pckbc_portcmd {
532 u_char cmd_en, cmd_dis;
533 } pckbc_portcmd[2] = {
534 {
535 KBC_KBDENABLE, KBC_KBDDISABLE,
536 }, {
537 KBC_AUXENABLE, KBC_AUXDISABLE,
538 }
539 };
540
541 void
542 pckbc_slot_enable(self, slot, on)
543 pckbc_tag_t self;
544 pckbc_slot_t slot;
545 int on;
546 {
547 struct pckbc_internal *t = (struct pckbc_internal *)self;
548 const struct pckbc_portcmd *cmd;
549
550 cmd = &pckbc_portcmd[slot];
551
552 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
553 on ? cmd->cmd_en : cmd->cmd_dis))
554 printf("pckbc_slot_enable(%d) failed\n", on);
555 }
556
557 void
558 pckbc_set_poll(self, slot, on)
559 pckbc_tag_t self;
560 pckbc_slot_t slot;
561 int on;
562 {
563 struct pckbc_internal *t = (struct pckbc_internal *)self;
564
565 t->t_slotdata[slot]->polling = on;
566
567 if (on) {
568 t->t_slotdata[slot]->poll_data = -1;
569 t->t_slotdata[slot]->poll_stat = -1;
570 } else {
571 int s;
572
573 /*
574 * If disabling polling on a device that's been configured,
575 * make sure there are no bytes left in the FIFO, holding up
576 * the interrupt line. Otherwise we won't get any further
577 * interrupts.
578 */
579 if (t->t_sc) {
580 s = spltty();
581 pckbcintr(t->t_sc);
582 splx(s);
583 }
584 }
585 }
586
587 /*
588 * Pass command to device, poll for ACK and data.
589 * to be called at spltty()
590 */
591 static void
592 pckbc_poll_cmd1(t, slot, cmd)
593 struct pckbc_internal *t;
594 pckbc_slot_t slot;
595 struct pckbc_devcmd *cmd;
596 {
597 int i, c = 0;
598
599 while (cmd->cmdidx < cmd->cmdlen) {
600 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
601 printf("pckbc_cmd: send error\n");
602 cmd->status = EIO;
603 return;
604 }
605 for (i = 10; i; i--) { /* 1s ??? */
606 c = pckbc_poll_data1(t, slot, t->t_haveaux);
607 if (c != -1)
608 break;
609 }
610
611 if (c == KBC_DEVCMD_ACK) {
612 cmd->cmdidx++;
613 continue;
614 }
615 if (c == KBC_DEVCMD_RESEND) {
616 #ifdef PCKBCDEBUG
617 printf("pckbc_cmd: RESEND\n");
618 #endif
619 if (cmd->retries++ < 5)
620 continue;
621 else {
622 #ifdef PCKBCDEBUG
623 printf("pckbc: cmd failed\n");
624 #endif
625 cmd->status = EIO;
626 return;
627 }
628 }
629 if (c == -1) {
630 #ifdef PCKBCDEBUG
631 printf("pckbc_cmd: timeout\n");
632 #endif
633 cmd->status = EIO;
634 return;
635 }
636 #ifdef PCKBCDEBUG
637 printf("pckbc_cmd: lost 0x%x\n", c);
638 #endif
639 }
640
641 while (cmd->responseidx < cmd->responselen) {
642 if (cmd->flags & KBC_CMDFLAG_SLOW)
643 i = 100; /* 10s ??? */
644 else
645 i = 10; /* 1s ??? */
646 while (i--) {
647 c = pckbc_poll_data1(t, slot, t->t_haveaux);
648 if (c != -1)
649 break;
650 }
651 if (c == -1) {
652 #ifdef PCKBCDEBUG
653 printf("pckbc_cmd: no data\n");
654 #endif
655 cmd->status = ETIMEDOUT;
656 return;
657 } else
658 cmd->response[cmd->responseidx++] = c;
659 }
660 }
661
662 /* for use in autoconfiguration */
663 int
664 pckbc_poll_cmd(self, slot, cmd, len, responselen, respbuf, slow)
665 pckbc_tag_t self;
666 pckbc_slot_t slot;
667 u_char *cmd;
668 int len, responselen;
669 u_char *respbuf;
670 int slow;
671 {
672 struct pckbc_internal *t = self;
673 struct pckbc_devcmd nc;
674
675 if ((len > 4) || (responselen > 4))
676 return (EINVAL);
677
678 memset(&nc, 0, sizeof(nc));
679 memcpy(nc.cmd, cmd, len);
680 nc.cmdlen = len;
681 nc.responselen = responselen;
682 nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0);
683
684 pckbc_poll_cmd1(t, slot, &nc);
685
686 if (nc.status == 0 && respbuf)
687 memcpy(respbuf, nc.response, responselen);
688
689 return (nc.status);
690 }
691
692 /*
693 * Clean up a command queue, throw away everything.
694 */
695 void
696 pckbc_cleanqueue(q)
697 struct pckbc_slotdata *q;
698 {
699 struct pckbc_devcmd *cmd;
700 #ifdef PCKBCDEBUG
701 int i;
702 #endif
703
704 while ((cmd = TAILQ_FIRST(&q->cmdqueue))) {
705 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
706 #ifdef PCKBCDEBUG
707 printf("pckbc_cleanqueue: removing");
708 for (i = 0; i < cmd->cmdlen; i++)
709 printf(" %02x", cmd->cmd[i]);
710 printf("\n");
711 #endif
712 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
713 }
714 }
715
716 /*
717 * Timeout error handler: clean queues and data port.
718 * XXX could be less invasive.
719 */
720 void
721 pckbc_cleanup(self)
722 void *self;
723 {
724 struct pckbc_internal *t = self;
725 int s;
726
727 printf("pckbc: command timeout\n");
728
729 s = spltty();
730
731 if (t->t_slotdata[PCKBC_KBD_SLOT])
732 pckbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]);
733 if (t->t_slotdata[PCKBC_AUX_SLOT])
734 pckbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]);
735
736 while (bus_space_read_1(t->t_iot, t->t_ioh_c, 0) & KBS_DIB) {
737 KBD_DELAY;
738 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
739 }
740
741 /* reset KBC? */
742
743 splx(s);
744 }
745
746 /*
747 * Pass command to device during normal operation.
748 * to be called at spltty()
749 */
750 void
751 pckbc_start(t, slot)
752 struct pckbc_internal *t;
753 pckbc_slot_t slot;
754 {
755 struct pckbc_slotdata *q = t->t_slotdata[slot];
756 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
757
758 if (q->polling) {
759 do {
760 pckbc_poll_cmd1(t, slot, cmd);
761 if (cmd->status)
762 printf("pckbc_start: command error\n");
763
764 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
765 if (cmd->flags & KBC_CMDFLAG_SYNC)
766 wakeup(cmd);
767 else {
768 callout_stop(&t->t_cleanup);
769 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
770 }
771 cmd = TAILQ_FIRST(&q->cmdqueue);
772 } while (cmd);
773 return;
774 }
775
776 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
777 printf("pckbc_start: send error\n");
778 /* XXX what now? */
779 return;
780 }
781 }
782
783 /*
784 * Handle command responses coming in asynchonously,
785 * return nonzero if valid response.
786 * to be called at spltty()
787 */
788 int
789 pckbc_cmdresponse(t, slot, data)
790 struct pckbc_internal *t;
791 pckbc_slot_t slot;
792 u_char data;
793 {
794 struct pckbc_slotdata *q = t->t_slotdata[slot];
795 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
796 #ifdef DIAGNOSTIC
797 if (!cmd)
798 panic("pckbc_cmdresponse: no active command");
799 #endif
800 if (cmd->cmdidx < cmd->cmdlen) {
801 if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND)
802 return (0);
803
804 if (data == KBC_DEVCMD_RESEND) {
805 if (cmd->retries++ < 5) {
806 /* try again last command */
807 goto restart;
808 } else {
809 printf("pckbc: cmd failed\n");
810 cmd->status = EIO;
811 /* dequeue */
812 }
813 } else {
814 if (++cmd->cmdidx < cmd->cmdlen)
815 goto restart;
816 if (cmd->responselen)
817 return (1);
818 /* else dequeue */
819 }
820 } else if (cmd->responseidx < cmd->responselen) {
821 cmd->response[cmd->responseidx++] = data;
822 if (cmd->responseidx < cmd->responselen)
823 return (1);
824 /* else dequeue */
825 } else
826 return (0);
827
828 /* dequeue: */
829 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
830 if (cmd->flags & KBC_CMDFLAG_SYNC)
831 wakeup(cmd);
832 else {
833 callout_stop(&t->t_cleanup);
834 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
835 }
836 if (!CMD_IN_QUEUE(q))
837 return (1);
838 restart:
839 pckbc_start(t, slot);
840 return (1);
841 }
842
843 /*
844 * Put command into the device's command queue, return zero or errno.
845 */
846 int
847 pckbc_enqueue_cmd(self, slot, cmd, len, responselen, sync, respbuf)
848 pckbc_tag_t self;
849 pckbc_slot_t slot;
850 u_char *cmd;
851 int len, responselen, sync;
852 u_char *respbuf;
853 {
854 struct pckbc_internal *t = self;
855 struct pckbc_slotdata *q = t->t_slotdata[slot];
856 struct pckbc_devcmd *nc;
857 int s, isactive, res = 0;
858
859 if ((len > 4) || (responselen > 4))
860 return (EINVAL);
861 s = spltty();
862 nc = TAILQ_FIRST(&q->freequeue);
863 if (nc) {
864 TAILQ_REMOVE(&q->freequeue, nc, next);
865 }
866 splx(s);
867 if (!nc)
868 return (ENOMEM);
869
870 memset(nc, 0, sizeof(*nc));
871 memcpy(nc->cmd, cmd, len);
872 nc->cmdlen = len;
873 nc->responselen = responselen;
874 nc->flags = (sync ? KBC_CMDFLAG_SYNC : 0);
875
876 s = spltty();
877
878 if (q->polling && sync) {
879 /*
880 * XXX We should poll until the queue is empty.
881 * But we don't come here normally, so make
882 * it simple and throw away everything.
883 */
884 pckbc_cleanqueue(q);
885 }
886
887 isactive = CMD_IN_QUEUE(q);
888 TAILQ_INSERT_TAIL(&q->cmdqueue, nc, next);
889 if (!isactive)
890 pckbc_start(t, slot);
891
892 if (q->polling)
893 res = (sync ? nc->status : 0);
894 else if (sync) {
895 if ((res = tsleep(nc, 0, "kbccmd", 1*hz))) {
896 TAILQ_REMOVE(&q->cmdqueue, nc, next);
897 pckbc_cleanup(t);
898 } else
899 res = nc->status;
900 } else
901 callout_reset(&t->t_cleanup, hz, pckbc_cleanup, t);
902
903 if (sync) {
904 if (respbuf)
905 memcpy(respbuf, nc->response, responselen);
906 TAILQ_INSERT_TAIL(&q->freequeue, nc, next);
907 }
908
909 splx(s);
910
911 return (res);
912 }
913
914 void
915 pckbc_set_inputhandler(self, slot, func, arg, name)
916 pckbc_tag_t self;
917 pckbc_slot_t slot;
918 pckbc_inputfcn func;
919 void *arg;
920 char *name;
921 {
922 struct pckbc_internal *t = (struct pckbc_internal *)self;
923 struct pckbc_softc *sc = t->t_sc;
924
925 if (slot >= PCKBC_NSLOTS)
926 panic("pckbc_set_inputhandler: bad slot %d", slot);
927
928 (*sc->intr_establish)(sc, slot);
929
930 sc->inputhandler[slot] = func;
931 sc->inputarg[slot] = arg;
932 sc->subname[slot] = name;
933 }
934
935 int
936 pckbcintr(vsc)
937 void *vsc;
938 {
939 struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
940 struct pckbc_internal *t = sc->id;
941 u_char stat;
942 pckbc_slot_t slot;
943 struct pckbc_slotdata *q;
944 int served = 0, data;
945
946 for(;;) {
947 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
948 #if 0
949 /* XXX soren XXX */
950 printf("pckbcintr %x\n", stat);
951 #endif
952 if (!(stat & KBS_DIB))
953 break;
954
955 served = 1;
956
957 slot = (t->t_haveaux && (stat & 0x20)) ?
958 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
959 q = t->t_slotdata[slot];
960
961 if (!q) {
962 /* XXX do something for live insertion? */
963 printf("pckbcintr: no dev for slot %d\n", slot);
964 KBD_DELAY;
965 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
966 continue;
967 }
968
969 KBD_DELAY;
970 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
971
972 #if NRND > 0
973 rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
974 #endif
975
976 if (q->polling) {
977 q->poll_data = data;
978 q->poll_stat = stat;
979 break; /* pckbc_poll_data() will get it */
980 }
981
982 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
983 continue;
984
985 if (sc->inputhandler[slot])
986 (*sc->inputhandler[slot])(sc->inputarg[slot], data);
987 #ifdef PCKBCDEBUG
988 else
989 printf("pckbcintr: slot %d lost %d\n", slot, data);
990 #endif
991 }
992
993 return (served);
994 }
995
996 int
997 pckbc_cnattach(iot, addr, cmd_offset, slot)
998 bus_space_tag_t iot;
999 bus_addr_t addr;
1000 bus_size_t cmd_offset;
1001 pckbc_slot_t slot;
1002 {
1003 bus_space_handle_t ioh_d, ioh_c;
1004 int res = 0;
1005
1006 if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
1007 return (ENXIO);
1008 if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
1009 bus_space_unmap(iot, ioh_d, 1);
1010 return (ENXIO);
1011 }
1012
1013 memset(&pckbc_consdata, 0, sizeof(pckbc_consdata));
1014 pckbc_consdata.t_iot = iot;
1015 pckbc_consdata.t_ioh_d = ioh_d;
1016 pckbc_consdata.t_ioh_c = ioh_c;
1017 pckbc_consdata.t_addr = addr;
1018 callout_init(&pckbc_consdata.t_cleanup);
1019
1020 /* flush */
1021 (void) pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT, 0);
1022
1023 /* selftest? */
1024
1025 /* init cmd byte, enable ports */
1026 pckbc_consdata.t_cmdbyte = KC8_CPU;
1027 if (!pckbc_put8042cmd(&pckbc_consdata)) {
1028 printf("kbc: cmd word write error\n");
1029 res = EIO;
1030 }
1031
1032 if (!res) {
1033 #if (NPCKBD > 0)
1034 res = pckbd_cnattach(&pckbc_consdata, slot);
1035 #else
1036 /*
1037 * XXX This should be removed when all of the old
1038 * PC-style console drivers have gone away.
1039 */
1040 #ifdef __BROKEN_HAS_PCCONS
1041 res = pcconskbd_cnattach(&pckbc_consdata, slot);
1042 #else
1043 res = ENXIO;
1044 #endif
1045 #endif /* NPCKBD > 0 */
1046 }
1047
1048 if (res) {
1049 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
1050 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
1051 } else {
1052 pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
1053 pckbc_init_slotdata(&pckbc_cons_slotdata);
1054 pckbc_console = 1;
1055 }
1056
1057 return (res);
1058 }
1059