pckbc.c revision 1.26 1 /* $NetBSD: pckbc.c,v 1.26 2003/06/12 03:34:12 uwe 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.26 2003/06/12 03:34:12 uwe 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 #ifdef __HAVE_NWSCONS /* XXX: this port uses sys/dev/pckbc */
57 #include "pckbd.h"
58 #else /* ie: only md drivers attach to pckbc */
59 #define NPCKBD 0
60 #endif
61 #if (NPCKBD > 0)
62 #include <dev/pckbc/pckbdvar.h>
63 #endif
64 #if NRND > 0
65 #include <sys/rnd.h>
66 #endif
67
68 /* descriptor for one device command */
69 struct pckbc_devcmd {
70 TAILQ_ENTRY(pckbc_devcmd) next;
71 int flags;
72 #define KBC_CMDFLAG_SYNC 1 /* give descriptor back to caller */
73 #define KBC_CMDFLAG_SLOW 2
74 u_char cmd[4];
75 int cmdlen, cmdidx, retries;
76 u_char response[4];
77 int status, responselen, responseidx;
78 };
79
80 /* data per slave device */
81 struct pckbc_slotdata {
82 int polling; /* don't process data in interrupt handler */
83 int poll_data; /* data read from inr handler if polling */
84 int poll_stat; /* status read from inr handler if polling */
85 TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* active commands */
86 TAILQ_HEAD(, pckbc_devcmd) freequeue; /* free commands */
87 #define NCMD 5
88 struct pckbc_devcmd cmds[NCMD];
89 #if NRND > 0
90 rndsource_element_t rnd_source;
91 #endif
92 };
93
94 #define CMD_IN_QUEUE(q) (TAILQ_FIRST(&(q)->cmdqueue) != NULL)
95
96 void pckbc_init_slotdata __P((struct pckbc_slotdata *));
97 int pckbc_attach_slot __P((struct pckbc_softc *, pckbc_slot_t));
98 int pckbc_submatch __P((struct device *, struct cfdata *, void *));
99 int pckbcprint __P((void *, const char *));
100
101 struct pckbc_internal pckbc_consdata;
102 int pckbc_console_attached;
103
104 static int pckbc_console;
105 static struct pckbc_slotdata pckbc_cons_slotdata;
106
107 static int pckbc_wait_output __P((bus_space_tag_t, bus_space_handle_t));
108
109 static int pckbc_get8042cmd __P((struct pckbc_internal *));
110 static int pckbc_put8042cmd __P((struct pckbc_internal *));
111 static int pckbc_send_devcmd __P((struct pckbc_internal *, pckbc_slot_t,
112 u_char));
113 static void pckbc_poll_cmd1 __P((struct pckbc_internal *, pckbc_slot_t,
114 struct pckbc_devcmd *));
115
116 void pckbc_cleanqueue __P((struct pckbc_slotdata *));
117 void pckbc_cleanup __P((void *));
118 int pckbc_cmdresponse __P((struct pckbc_internal *, pckbc_slot_t, u_char));
119 void pckbc_start __P((struct pckbc_internal *, pckbc_slot_t));
120
121 const char * const pckbc_slot_names[] = { "kbd", "aux" };
122
123 #define KBC_DEVCMD_ACK 0xfa
124 #define KBC_DEVCMD_RESEND 0xfe
125
126 #define KBD_DELAY DELAY(8)
127
128 static inline int
129 pckbc_wait_output(iot, ioh_c)
130 bus_space_tag_t iot;
131 bus_space_handle_t ioh_c;
132 {
133 u_int i;
134
135 for (i = 100000; i; i--)
136 if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
137 KBD_DELAY;
138 return (1);
139 }
140 return (0);
141 }
142
143 int
144 pckbc_send_cmd(iot, ioh_c, val)
145 bus_space_tag_t iot;
146 bus_space_handle_t ioh_c;
147 u_char val;
148 {
149 if (!pckbc_wait_output(iot, ioh_c))
150 return (0);
151 bus_space_write_1(iot, ioh_c, 0, val);
152 return (1);
153 }
154
155 /*
156 * Note: the spl games here are to deal with some strange PC kbd controllers
157 * in some system configurations.
158 * This is not canonical way to handle polling input.
159 */
160 int
161 pckbc_poll_data1(pt, slot, checkaux)
162 pckbc_tag_t pt;
163 pckbc_slot_t slot;
164 int checkaux;
165 {
166 struct pckbc_internal *t = pt;
167 struct pckbc_slotdata *q = t->t_slotdata[slot];
168 int s;
169 u_char stat, c;
170 int i = 100000; /* if 1 port read takes 1us (?), this polls for 100ms */
171
172 s = splhigh();
173
174 if (q && q->polling && q->poll_data != -1 && q->poll_stat != -1) {
175 stat = q->poll_stat;
176 c = q->poll_data;
177 q->poll_data = -1;
178 q->poll_stat = -1;
179 goto process;
180 }
181
182 for (; i; i--) {
183 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
184 if (stat & KBS_DIB) {
185 KBD_DELAY;
186 c = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
187
188 process:
189 if (checkaux && (stat & 0x20)) { /* aux data */
190 if (slot != PCKBC_AUX_SLOT) {
191 #ifdef PCKBCDEBUG
192 printf("lost aux 0x%x\n", c);
193 #endif
194 continue;
195 }
196 } else {
197 if (slot == PCKBC_AUX_SLOT) {
198 #ifdef PCKBCDEBUG
199 printf("lost kbd 0x%x\n", c);
200 #endif
201 continue;
202 }
203 }
204 splx(s);
205 return (c);
206 }
207 }
208
209 splx(s);
210 return (-1);
211 }
212
213 /*
214 * Get the current command byte.
215 */
216 static int
217 pckbc_get8042cmd(t)
218 struct pckbc_internal *t;
219 {
220 bus_space_tag_t iot = t->t_iot;
221 bus_space_handle_t ioh_c = t->t_ioh_c;
222 int data;
223
224 if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
225 return (0);
226 data = pckbc_poll_data1(t, PCKBC_KBD_SLOT, t->t_haveaux);
227 if (data == -1)
228 return (0);
229 t->t_cmdbyte = data;
230 return (1);
231 }
232
233 /*
234 * Pass command byte to keyboard controller (8042).
235 */
236 static int
237 pckbc_put8042cmd(t)
238 struct pckbc_internal *t;
239 {
240 bus_space_tag_t iot = t->t_iot;
241 bus_space_handle_t ioh_d = t->t_ioh_d;
242 bus_space_handle_t ioh_c = t->t_ioh_c;
243
244 if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE))
245 return (0);
246 if (!pckbc_wait_output(iot, ioh_c))
247 return (0);
248 bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte);
249 return (1);
250 }
251
252 static int
253 pckbc_send_devcmd(t, slot, val)
254 struct pckbc_internal *t;
255 pckbc_slot_t slot;
256 u_char val;
257 {
258 bus_space_tag_t iot = t->t_iot;
259 bus_space_handle_t ioh_d = t->t_ioh_d;
260 bus_space_handle_t ioh_c = t->t_ioh_c;
261
262 if (slot == PCKBC_AUX_SLOT) {
263 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
264 return (0);
265 }
266 if (!pckbc_wait_output(iot, ioh_c))
267 return (0);
268 bus_space_write_1(iot, ioh_d, 0, val);
269 return (1);
270 }
271
272 int
273 pckbc_is_console(iot, addr)
274 bus_space_tag_t iot;
275 bus_addr_t addr;
276 {
277 if (pckbc_console && !pckbc_console_attached &&
278 pckbc_consdata.t_iot == iot &&
279 pckbc_consdata.t_addr == addr)
280 return (1);
281 return (0);
282 }
283
284 int
285 pckbc_submatch(parent, cf, aux)
286 struct device *parent;
287 struct cfdata *cf;
288 void *aux;
289 {
290 struct pckbc_attach_args *pa = aux;
291
292 if (cf->cf_loc[PCKBCCF_SLOT] != PCKBCCF_SLOT_DEFAULT &&
293 cf->cf_loc[PCKBCCF_SLOT] != pa->pa_slot)
294 return (0);
295 return (config_match(parent, cf, aux));
296 }
297
298 int
299 pckbc_attach_slot(sc, slot)
300 struct pckbc_softc *sc;
301 pckbc_slot_t slot;
302 {
303 struct pckbc_internal *t = sc->id;
304 struct pckbc_attach_args pa;
305 void *sdata;
306 int found;
307 int alloced = 0;
308
309 pa.pa_tag = t;
310 pa.pa_slot = slot;
311
312 if (t->t_slotdata[slot] == NULL) {
313 sdata = malloc(sizeof(struct pckbc_slotdata),
314 M_DEVBUF, M_NOWAIT);
315 if (sdata == NULL) {
316 printf("%s: no memory\n", sc->sc_dv.dv_xname);
317 return (0);
318 }
319 t->t_slotdata[slot] = sdata;
320 pckbc_init_slotdata(t->t_slotdata[slot]);
321 alloced++;
322 }
323
324 found = (config_found_sm((struct device *)sc, &pa,
325 pckbcprint, pckbc_submatch) != NULL);
326
327 if (!found && alloced) {
328 free(t->t_slotdata[slot], M_DEVBUF);
329 t->t_slotdata[slot] = NULL;
330 }
331
332 #if NRND > 0
333 if (found && (t->t_slotdata[slot] != NULL))
334 rnd_attach_source(&t->t_slotdata[slot]->rnd_source,
335 sc->subname[slot], RND_TYPE_TTY, 0);
336 #endif
337 return (found);
338 }
339
340 void
341 pckbc_attach(sc)
342 struct pckbc_softc *sc;
343 {
344 struct pckbc_internal *t;
345 bus_space_tag_t iot;
346 bus_space_handle_t ioh_d, ioh_c;
347 int res;
348 u_char cmdbits = 0;
349
350 t = sc->id;
351 iot = t->t_iot;
352 ioh_d = t->t_ioh_d;
353 ioh_c = t->t_ioh_c;
354
355 /* flush */
356 (void) pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
357
358 /* set initial cmd byte */
359 if (!pckbc_put8042cmd(t)) {
360 printf("kbc: cmd word write error\n");
361 return;
362 }
363
364 /*
365 * XXX Don't check the keyboard port. There are broken keyboard controllers
366 * which don't pass the test but work normally otherwise.
367 */
368 #if 0
369 /*
370 * check kbd port ok
371 */
372 if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
373 return;
374 res = pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
375
376 /*
377 * Normally, we should get a "0" here.
378 * But there are keyboard controllers behaving differently.
379 */
380 if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
381 #ifdef PCKBCDEBUG
382 if (res != 0)
383 printf("kbc: returned %x on kbd slot test\n", res);
384 #endif
385 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
386 cmdbits |= KC8_KENABLE;
387 } else {
388 printf("kbc: kbd port test: %x\n", res);
389 return;
390 }
391 #else
392 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
393 cmdbits |= KC8_KENABLE;
394 #endif /* 0 */
395
396 /*
397 * Check aux port ok.
398 * Avoid KBC_AUXTEST because it hangs some older controllers
399 * (eg UMC880?).
400 */
401 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
402 printf("kbc: aux echo error 1\n");
403 goto nomouse;
404 }
405 if (!pckbc_wait_output(iot, ioh_c)) {
406 printf("kbc: aux echo error 2\n");
407 goto nomouse;
408 }
409 bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
410 res = pckbc_poll_data1(t, PCKBC_AUX_SLOT, 1);
411 if (res != -1) {
412 /*
413 * In most cases, the 0x5a gets echoed.
414 * Some older controllers (Gateway 2000 circa 1993)
415 * return 0xfe here.
416 * We are satisfied if there is anything in the
417 * aux output buffer.
418 */
419 t->t_haveaux = 1;
420 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
421 cmdbits |= KC8_MENABLE;
422 }
423 #ifdef PCKBCDEBUG
424 else
425 printf("kbc: aux echo test failed\n");
426 #endif
427
428 nomouse:
429 /* enable needed interrupts */
430 t->t_cmdbyte |= cmdbits;
431 if (!pckbc_put8042cmd(t))
432 printf("kbc: cmd word write error\n");
433 }
434
435 int
436 pckbcprint(aux, pnp)
437 void *aux;
438 const char *pnp;
439 {
440 struct pckbc_attach_args *pa = aux;
441
442 if (!pnp)
443 aprint_normal(" (%s slot)", pckbc_slot_names[pa->pa_slot]);
444 return (QUIET);
445 }
446
447 void
448 pckbc_init_slotdata(q)
449 struct pckbc_slotdata *q;
450 {
451 int i;
452 TAILQ_INIT(&q->cmdqueue);
453 TAILQ_INIT(&q->freequeue);
454
455 for (i = 0; i < NCMD; i++) {
456 TAILQ_INSERT_TAIL(&q->freequeue, &(q->cmds[i]), next);
457 }
458 q->polling = 0;
459 }
460
461 void
462 pckbc_flush(self, slot)
463 pckbc_tag_t self;
464 pckbc_slot_t slot;
465 {
466 struct pckbc_internal *t = self;
467
468 (void) pckbc_poll_data1(t, slot, t->t_haveaux);
469 }
470
471 int
472 pckbc_poll_data(self, slot)
473 pckbc_tag_t self;
474 pckbc_slot_t slot;
475 {
476 struct pckbc_internal *t = self;
477 struct pckbc_slotdata *q = t->t_slotdata[slot];
478 int c;
479
480 c = pckbc_poll_data1(t, slot, t->t_haveaux);
481 if (c != -1 && q && CMD_IN_QUEUE(q)) {
482 /* we jumped into a running command - try to
483 deliver the response */
484 if (pckbc_cmdresponse(t, slot, c))
485 return (-1);
486 }
487 return (c);
488 }
489
490 /*
491 * switch scancode translation on / off
492 * return nonzero on success
493 */
494 int
495 pckbc_xt_translation(self, slot, on)
496 pckbc_tag_t self;
497 pckbc_slot_t slot;
498 int on;
499 {
500 struct pckbc_internal *t = self;
501 int ison;
502
503 if (slot != PCKBC_KBD_SLOT) {
504 /* translation only for kbd slot */
505 if (on)
506 return (0);
507 else
508 return (1);
509 }
510
511 ison = t->t_cmdbyte & KC8_TRANS;
512 if ((on && ison) || (!on && !ison))
513 return (1);
514
515 t->t_cmdbyte ^= KC8_TRANS;
516 if (!pckbc_put8042cmd(t))
517 return (0);
518
519 /* read back to be sure */
520 if (!pckbc_get8042cmd(t))
521 return (0);
522
523 ison = t->t_cmdbyte & KC8_TRANS;
524 if ((on && ison) || (!on && !ison))
525 return (1);
526 return (0);
527 }
528
529 static const struct pckbc_portcmd {
530 u_char cmd_en, cmd_dis;
531 } pckbc_portcmd[2] = {
532 {
533 KBC_KBDENABLE, KBC_KBDDISABLE,
534 }, {
535 KBC_AUXENABLE, KBC_AUXDISABLE,
536 }
537 };
538
539 void
540 pckbc_slot_enable(self, slot, on)
541 pckbc_tag_t self;
542 pckbc_slot_t slot;
543 int on;
544 {
545 struct pckbc_internal *t = (struct pckbc_internal *)self;
546 const struct pckbc_portcmd *cmd;
547
548 cmd = &pckbc_portcmd[slot];
549
550 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
551 on ? cmd->cmd_en : cmd->cmd_dis))
552 printf("pckbc_slot_enable(%d) failed\n", on);
553 }
554
555 void
556 pckbc_set_poll(self, slot, on)
557 pckbc_tag_t self;
558 pckbc_slot_t slot;
559 int on;
560 {
561 struct pckbc_internal *t = (struct pckbc_internal *)self;
562
563 t->t_slotdata[slot]->polling = on;
564
565 if (on) {
566 t->t_slotdata[slot]->poll_data = -1;
567 t->t_slotdata[slot]->poll_stat = -1;
568 } else {
569 int s;
570
571 /*
572 * If disabling polling on a device that's been configured,
573 * make sure there are no bytes left in the FIFO, holding up
574 * the interrupt line. Otherwise we won't get any further
575 * interrupts.
576 */
577 if (t->t_sc) {
578 s = spltty();
579 pckbcintr(t->t_sc);
580 splx(s);
581 }
582 }
583 }
584
585 /*
586 * Pass command to device, poll for ACK and data.
587 * to be called at spltty()
588 */
589 static void
590 pckbc_poll_cmd1(t, slot, cmd)
591 struct pckbc_internal *t;
592 pckbc_slot_t slot;
593 struct pckbc_devcmd *cmd;
594 {
595 int i, c = 0;
596
597 while (cmd->cmdidx < cmd->cmdlen) {
598 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
599 printf("pckbc_cmd: send error\n");
600 cmd->status = EIO;
601 return;
602 }
603 for (i = 10; i; i--) { /* 1s ??? */
604 c = pckbc_poll_data1(t, slot, t->t_haveaux);
605 if (c != -1)
606 break;
607 }
608
609 if (c == KBC_DEVCMD_ACK) {
610 cmd->cmdidx++;
611 continue;
612 }
613 if (c == KBC_DEVCMD_RESEND) {
614 #ifdef PCKBCDEBUG
615 printf("pckbc_cmd: RESEND\n");
616 #endif
617 if (cmd->retries++ < 5)
618 continue;
619 else {
620 #ifdef PCKBCDEBUG
621 printf("pckbc: cmd failed\n");
622 #endif
623 cmd->status = EIO;
624 return;
625 }
626 }
627 if (c == -1) {
628 #ifdef PCKBCDEBUG
629 printf("pckbc_cmd: timeout\n");
630 #endif
631 cmd->status = EIO;
632 return;
633 }
634 #ifdef PCKBCDEBUG
635 printf("pckbc_cmd: lost 0x%x\n", c);
636 #endif
637 }
638
639 while (cmd->responseidx < cmd->responselen) {
640 if (cmd->flags & KBC_CMDFLAG_SLOW)
641 i = 100; /* 10s ??? */
642 else
643 i = 10; /* 1s ??? */
644 while (i--) {
645 c = pckbc_poll_data1(t, slot, t->t_haveaux);
646 if (c != -1)
647 break;
648 }
649 if (c == -1) {
650 #ifdef PCKBCDEBUG
651 printf("pckbc_cmd: no data\n");
652 #endif
653 cmd->status = ETIMEDOUT;
654 return;
655 } else
656 cmd->response[cmd->responseidx++] = c;
657 }
658 }
659
660 /* for use in autoconfiguration */
661 int
662 pckbc_poll_cmd(self, slot, cmd, len, responselen, respbuf, slow)
663 pckbc_tag_t self;
664 pckbc_slot_t slot;
665 u_char *cmd;
666 int len, responselen;
667 u_char *respbuf;
668 int slow;
669 {
670 struct pckbc_internal *t = self;
671 struct pckbc_devcmd nc;
672
673 if ((len > 4) || (responselen > 4))
674 return (EINVAL);
675
676 memset(&nc, 0, sizeof(nc));
677 memcpy(nc.cmd, cmd, len);
678 nc.cmdlen = len;
679 nc.responselen = responselen;
680 nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0);
681
682 pckbc_poll_cmd1(t, slot, &nc);
683
684 if (nc.status == 0 && respbuf)
685 memcpy(respbuf, nc.response, responselen);
686
687 return (nc.status);
688 }
689
690 /*
691 * Clean up a command queue, throw away everything.
692 */
693 void
694 pckbc_cleanqueue(q)
695 struct pckbc_slotdata *q;
696 {
697 struct pckbc_devcmd *cmd;
698 #ifdef PCKBCDEBUG
699 int i;
700 #endif
701
702 while ((cmd = TAILQ_FIRST(&q->cmdqueue))) {
703 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
704 #ifdef PCKBCDEBUG
705 printf("pckbc_cleanqueue: removing");
706 for (i = 0; i < cmd->cmdlen; i++)
707 printf(" %02x", cmd->cmd[i]);
708 printf("\n");
709 #endif
710 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
711 }
712 }
713
714 /*
715 * Timeout error handler: clean queues and data port.
716 * XXX could be less invasive.
717 */
718 void
719 pckbc_cleanup(self)
720 void *self;
721 {
722 struct pckbc_internal *t = self;
723 int s;
724
725 printf("pckbc: command timeout\n");
726
727 s = spltty();
728
729 if (t->t_slotdata[PCKBC_KBD_SLOT])
730 pckbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]);
731 if (t->t_slotdata[PCKBC_AUX_SLOT])
732 pckbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]);
733
734 while (bus_space_read_1(t->t_iot, t->t_ioh_c, 0) & KBS_DIB) {
735 KBD_DELAY;
736 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
737 }
738
739 /* reset KBC? */
740
741 splx(s);
742 }
743
744 /*
745 * Pass command to device during normal operation.
746 * to be called at spltty()
747 */
748 void
749 pckbc_start(t, slot)
750 struct pckbc_internal *t;
751 pckbc_slot_t slot;
752 {
753 struct pckbc_slotdata *q = t->t_slotdata[slot];
754 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
755
756 if (q->polling) {
757 do {
758 pckbc_poll_cmd1(t, slot, cmd);
759 if (cmd->status)
760 printf("pckbc_start: command error\n");
761
762 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
763 if (cmd->flags & KBC_CMDFLAG_SYNC)
764 wakeup(cmd);
765 else {
766 callout_stop(&t->t_cleanup);
767 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
768 }
769 cmd = TAILQ_FIRST(&q->cmdqueue);
770 } while (cmd);
771 return;
772 }
773
774 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
775 printf("pckbc_start: send error\n");
776 /* XXX what now? */
777 return;
778 }
779 }
780
781 /*
782 * Handle command responses coming in asynchonously,
783 * return nonzero if valid response.
784 * to be called at spltty()
785 */
786 int
787 pckbc_cmdresponse(t, slot, data)
788 struct pckbc_internal *t;
789 pckbc_slot_t slot;
790 u_char data;
791 {
792 struct pckbc_slotdata *q = t->t_slotdata[slot];
793 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
794 #ifdef DIAGNOSTIC
795 if (!cmd)
796 panic("pckbc_cmdresponse: no active command");
797 #endif
798 if (cmd->cmdidx < cmd->cmdlen) {
799 if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND)
800 return (0);
801
802 if (data == KBC_DEVCMD_RESEND) {
803 if (cmd->retries++ < 5) {
804 /* try again last command */
805 goto restart;
806 } else {
807 #ifdef PCKBCDEBUG
808 printf("pckbc: cmd failed\n");
809 #endif
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 (!(stat & KBS_DIB))
949 break;
950
951 served = 1;
952
953 slot = (t->t_haveaux && (stat & 0x20)) ?
954 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
955 q = t->t_slotdata[slot];
956
957 if (!q) {
958 /* XXX do something for live insertion? */
959 printf("pckbcintr: no dev for slot %d\n", slot);
960 KBD_DELAY;
961 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
962 continue;
963 }
964
965 KBD_DELAY;
966 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
967
968 #if NRND > 0
969 rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
970 #endif
971
972 if (q->polling) {
973 q->poll_data = data;
974 q->poll_stat = stat;
975 break; /* pckbc_poll_data() will get it */
976 }
977
978 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
979 continue;
980
981 if (sc->inputhandler[slot])
982 (*sc->inputhandler[slot])(sc->inputarg[slot], data);
983 #ifdef PCKBCDEBUG
984 else
985 printf("pckbcintr: slot %d lost %d\n", slot, data);
986 #endif
987 }
988
989 return (served);
990 }
991
992 int
993 pckbc_cnattach(iot, addr, cmd_offset, slot)
994 bus_space_tag_t iot;
995 bus_addr_t addr;
996 bus_size_t cmd_offset;
997 pckbc_slot_t slot;
998 {
999 bus_space_handle_t ioh_d, ioh_c;
1000 #ifdef PCKBC_CNATTACH_SELFTEST
1001 int reply;
1002 #endif
1003 int res = 0;
1004
1005 if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
1006 return (ENXIO);
1007 if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
1008 bus_space_unmap(iot, ioh_d, 1);
1009 return (ENXIO);
1010 }
1011
1012 memset(&pckbc_consdata, 0, sizeof(pckbc_consdata));
1013 pckbc_consdata.t_iot = iot;
1014 pckbc_consdata.t_ioh_d = ioh_d;
1015 pckbc_consdata.t_ioh_c = ioh_c;
1016 pckbc_consdata.t_addr = addr;
1017 callout_init(&pckbc_consdata.t_cleanup);
1018
1019 /* flush */
1020 (void) pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT, 0);
1021
1022 #ifdef PCKBC_CNATTACH_SELFTEST
1023 /*
1024 * In some machines (e.g. netwinder) pckbc refuses to talk at
1025 * all until we request a self-test.
1026 */
1027 if (!pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST)) {
1028 printf("kbc: unable to request selftest\n");
1029 res = EIO;
1030 goto out;
1031 }
1032
1033 reply = pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT, 0);
1034 if (reply != 0x55) {
1035 printf("kbc: selftest returned 0x%02x\n", reply);
1036 res = EIO;
1037 goto out;
1038 }
1039 #endif /* PCKBC_CNATTACH_SELFTEST */
1040
1041 /* init cmd byte, enable ports */
1042 pckbc_consdata.t_cmdbyte = KC8_CPU;
1043 if (!pckbc_put8042cmd(&pckbc_consdata)) {
1044 printf("kbc: cmd word write error\n");
1045 res = EIO;
1046 goto out;
1047 }
1048
1049 #if (NPCKBD > 0)
1050 res = pckbd_cnattach(&pckbc_consdata, slot);
1051 #else
1052 /*
1053 * XXX This should be replaced with the `notyet' case
1054 * XXX when all of the old PC-style console drivers
1055 * XXX have gone away. When that happens, all of
1056 * XXX the pckbc_machdep_cnattach() should be purged,
1057 * XXX as well.
1058 */
1059 #ifdef notyet
1060 res = ENXIO;
1061 #else
1062 res = pckbc_machdep_cnattach(&pckbc_consdata, slot);
1063 #endif
1064 #endif /* NPCKBD > 0 */
1065
1066 out:
1067 if (res) {
1068 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
1069 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
1070 } else {
1071 pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
1072 pckbc_init_slotdata(&pckbc_cons_slotdata);
1073 pckbc_console = 1;
1074 }
1075
1076 return (res);
1077 }
1078