pckbc.c revision 1.17 1 /* $NetBSD: pckbc.c,v 1.17 2001/12/06 19:52:56 christos 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.17 2001/12/06 19:52:56 christos 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 i, s;
169 u_char stat, c;
170
171 s = splhigh();
172
173 if (q && q->polling && q->poll_data != -1 && q->poll_stat != -1) {
174 stat = q->poll_stat;
175 c = q->poll_data;
176 q->poll_data = -1;
177 q->poll_stat = -1;
178 goto process;
179 }
180
181 /* if 1 port read takes 1us (?), this polls for 100ms */
182 for (i = 100000; 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 ((*cf->cf_attach->ca_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 int found;
306 int alloced = 0;
307
308 pa.pa_tag = t;
309 pa.pa_slot = slot;
310
311 if (t->t_slotdata[slot] == NULL) {
312 t->t_slotdata[slot] = malloc(sizeof(struct pckbc_slotdata),
313 M_DEVBUF, M_NOWAIT);
314 pckbc_init_slotdata(t->t_slotdata[slot]);
315 alloced++;
316 }
317
318 found = (config_found_sm((struct device *)sc, &pa,
319 pckbcprint, pckbc_submatch) != NULL);
320
321 if (!found && alloced) {
322 free(t->t_slotdata[slot], M_DEVBUF);
323 t->t_slotdata[slot] = NULL;
324 }
325
326 #if NRND > 0
327 if (found && (t->t_slotdata[slot] != NULL))
328 rnd_attach_source(&t->t_slotdata[slot]->rnd_source,
329 sc->subname[slot], RND_TYPE_TTY, 0);
330 #endif
331 return (found);
332 }
333
334 void
335 pckbc_attach(sc)
336 struct pckbc_softc *sc;
337 {
338 struct pckbc_internal *t;
339 bus_space_tag_t iot;
340 bus_space_handle_t ioh_d, ioh_c;
341 int res;
342 u_char cmdbits = 0;
343
344 t = sc->id;
345 iot = t->t_iot;
346 ioh_d = t->t_ioh_d;
347 ioh_c = t->t_ioh_c;
348
349 /* flush */
350 (void) pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
351
352 /* set initial cmd byte */
353 if (!pckbc_put8042cmd(t)) {
354 printf("kbc: cmd word write error\n");
355 return;
356 }
357
358 /*
359 * XXX Don't check the keyboard port. There are broken keyboard controllers
360 * which don't pass the test but work normally otherwise.
361 */
362 #if 0
363 /*
364 * check kbd port ok
365 */
366 if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
367 return;
368 res = pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
369
370 /*
371 * Normally, we should get a "0" here.
372 * But there are keyboard controllers behaving differently.
373 */
374 if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
375 #ifdef PCKBCDEBUG
376 if (res != 0)
377 printf("kbc: returned %x on kbd slot test\n", res);
378 #endif
379 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
380 cmdbits |= KC8_KENABLE;
381 } else {
382 printf("kbc: kbd port test: %x\n", res);
383 return;
384 }
385 #else
386 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
387 cmdbits |= KC8_KENABLE;
388 #endif /* 0 */
389
390 /*
391 * Check aux port ok.
392 * Avoid KBC_AUXTEST because it hangs some older controllers
393 * (eg UMC880?).
394 */
395 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
396 printf("kbc: aux echo error 1\n");
397 goto nomouse;
398 }
399 if (!pckbc_wait_output(iot, ioh_c)) {
400 printf("kbc: aux echo error 2\n");
401 goto nomouse;
402 }
403 bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
404 res = pckbc_poll_data1(t, PCKBC_AUX_SLOT, 1);
405 if (res != -1) {
406 /*
407 * In most cases, the 0x5a gets echoed.
408 * Some older controllers (Gateway 2000 circa 1993)
409 * return 0xfe here.
410 * We are satisfied if there is anything in the
411 * aux output buffer.
412 */
413 t->t_haveaux = 1;
414 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
415 cmdbits |= KC8_MENABLE;
416 }
417 #ifdef PCKBCDEBUG
418 else
419 printf("kbc: aux echo test failed\n");
420 #endif
421
422 nomouse:
423 /* enable needed interrupts */
424 t->t_cmdbyte |= cmdbits;
425 if (!pckbc_put8042cmd(t))
426 printf("kbc: cmd word write error\n");
427 }
428
429 int
430 pckbcprint(aux, pnp)
431 void *aux;
432 const char *pnp;
433 {
434 struct pckbc_attach_args *pa = aux;
435
436 if (!pnp)
437 printf(" (%s slot)", pckbc_slot_names[pa->pa_slot]);
438 return (QUIET);
439 }
440
441 void
442 pckbc_init_slotdata(q)
443 struct pckbc_slotdata *q;
444 {
445 int i;
446 TAILQ_INIT(&q->cmdqueue);
447 TAILQ_INIT(&q->freequeue);
448
449 for (i = 0; i < NCMD; i++) {
450 TAILQ_INSERT_TAIL(&q->freequeue, &(q->cmds[i]), next);
451 }
452 q->polling = 0;
453 }
454
455 void
456 pckbc_flush(self, slot)
457 pckbc_tag_t self;
458 pckbc_slot_t slot;
459 {
460 struct pckbc_internal *t = self;
461
462 (void) pckbc_poll_data1(t, slot, t->t_haveaux);
463 }
464
465 int
466 pckbc_poll_data(self, slot)
467 pckbc_tag_t self;
468 pckbc_slot_t slot;
469 {
470 struct pckbc_internal *t = self;
471 struct pckbc_slotdata *q = t->t_slotdata[slot];
472 int c;
473
474 c = pckbc_poll_data1(t, slot, t->t_haveaux);
475 if (c != -1 && q && CMD_IN_QUEUE(q)) {
476 /* we jumped into a running command - try to
477 deliver the response */
478 if (pckbc_cmdresponse(t, slot, c))
479 return (-1);
480 }
481 return (c);
482 }
483
484 /*
485 * switch scancode translation on / off
486 * return nonzero on success
487 */
488 int
489 pckbc_xt_translation(self, slot, on)
490 pckbc_tag_t self;
491 pckbc_slot_t slot;
492 int on;
493 {
494 struct pckbc_internal *t = self;
495 int ison;
496
497 if (slot != PCKBC_KBD_SLOT) {
498 /* translation only for kbd slot */
499 if (on)
500 return (0);
501 else
502 return (1);
503 }
504
505 ison = t->t_cmdbyte & KC8_TRANS;
506 if ((on && ison) || (!on && !ison))
507 return (1);
508
509 t->t_cmdbyte ^= KC8_TRANS;
510 if (!pckbc_put8042cmd(t))
511 return (0);
512
513 /* read back to be sure */
514 if (!pckbc_get8042cmd(t))
515 return (0);
516
517 ison = t->t_cmdbyte & KC8_TRANS;
518 if ((on && ison) || (!on && !ison))
519 return (1);
520 return (0);
521 }
522
523 static const struct pckbc_portcmd {
524 u_char cmd_en, cmd_dis;
525 } pckbc_portcmd[2] = {
526 {
527 KBC_KBDENABLE, KBC_KBDDISABLE,
528 }, {
529 KBC_AUXENABLE, KBC_AUXDISABLE,
530 }
531 };
532
533 void
534 pckbc_slot_enable(self, slot, on)
535 pckbc_tag_t self;
536 pckbc_slot_t slot;
537 int on;
538 {
539 struct pckbc_internal *t = (struct pckbc_internal *)self;
540 const struct pckbc_portcmd *cmd;
541
542 cmd = &pckbc_portcmd[slot];
543
544 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
545 on ? cmd->cmd_en : cmd->cmd_dis))
546 printf("pckbc_slot_enable(%d) failed\n", on);
547 }
548
549 void
550 pckbc_set_poll(self, slot, on)
551 pckbc_tag_t self;
552 pckbc_slot_t slot;
553 int on;
554 {
555 struct pckbc_internal *t = (struct pckbc_internal *)self;
556
557 t->t_slotdata[slot]->polling = on;
558
559 if (on) {
560 t->t_slotdata[slot]->poll_data = -1;
561 t->t_slotdata[slot]->poll_stat = -1;
562 } else {
563 int s;
564
565 /*
566 * If disabling polling on a device that's been configured,
567 * make sure there are no bytes left in the FIFO, holding up
568 * the interrupt line. Otherwise we won't get any further
569 * interrupts.
570 */
571 if (t->t_sc) {
572 s = spltty();
573 pckbcintr(t->t_sc);
574 splx(s);
575 }
576 }
577 }
578
579 /*
580 * Pass command to device, poll for ACK and data.
581 * to be called at spltty()
582 */
583 static void
584 pckbc_poll_cmd1(t, slot, cmd)
585 struct pckbc_internal *t;
586 pckbc_slot_t slot;
587 struct pckbc_devcmd *cmd;
588 {
589 int i, c = 0;
590
591 while (cmd->cmdidx < cmd->cmdlen) {
592 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
593 printf("pckbc_cmd: send error\n");
594 cmd->status = EIO;
595 return;
596 }
597 for (i = 10; i; i--) { /* 1s ??? */
598 c = pckbc_poll_data1(t, slot, t->t_haveaux);
599 if (c != -1)
600 break;
601 }
602
603 if (c == KBC_DEVCMD_ACK) {
604 cmd->cmdidx++;
605 continue;
606 }
607 if (c == KBC_DEVCMD_RESEND) {
608 #ifdef PCKBCDEBUG
609 printf("pckbc_cmd: RESEND\n");
610 #endif
611 if (cmd->retries++ < 5)
612 continue;
613 else {
614 #ifdef PCKBCDEBUG
615 printf("pckbc: cmd failed\n");
616 #endif
617 cmd->status = EIO;
618 return;
619 }
620 }
621 if (c == -1) {
622 #ifdef PCKBCDEBUG
623 printf("pckbc_cmd: timeout\n");
624 #endif
625 cmd->status = EIO;
626 return;
627 }
628 #ifdef PCKBCDEBUG
629 printf("pckbc_cmd: lost 0x%x\n", c);
630 #endif
631 }
632
633 while (cmd->responseidx < cmd->responselen) {
634 if (cmd->flags & KBC_CMDFLAG_SLOW)
635 i = 100; /* 10s ??? */
636 else
637 i = 10; /* 1s ??? */
638 while (i--) {
639 c = pckbc_poll_data1(t, slot, t->t_haveaux);
640 if (c != -1)
641 break;
642 }
643 if (c == -1) {
644 #ifdef PCKBCDEBUG
645 printf("pckbc_cmd: no data\n");
646 #endif
647 cmd->status = ETIMEDOUT;
648 return;
649 } else
650 cmd->response[cmd->responseidx++] = c;
651 }
652 }
653
654 /* for use in autoconfiguration */
655 int
656 pckbc_poll_cmd(self, slot, cmd, len, responselen, respbuf, slow)
657 pckbc_tag_t self;
658 pckbc_slot_t slot;
659 u_char *cmd;
660 int len, responselen;
661 u_char *respbuf;
662 int slow;
663 {
664 struct pckbc_internal *t = self;
665 struct pckbc_devcmd nc;
666
667 if ((len > 4) || (responselen > 4))
668 return (EINVAL);
669
670 memset(&nc, 0, sizeof(nc));
671 memcpy(nc.cmd, cmd, len);
672 nc.cmdlen = len;
673 nc.responselen = responselen;
674 nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0);
675
676 pckbc_poll_cmd1(t, slot, &nc);
677
678 if (nc.status == 0 && respbuf)
679 memcpy(respbuf, nc.response, responselen);
680
681 return (nc.status);
682 }
683
684 /*
685 * Clean up a command queue, throw away everything.
686 */
687 void
688 pckbc_cleanqueue(q)
689 struct pckbc_slotdata *q;
690 {
691 struct pckbc_devcmd *cmd;
692 #ifdef PCKBCDEBUG
693 int i;
694 #endif
695
696 while ((cmd = TAILQ_FIRST(&q->cmdqueue))) {
697 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
698 #ifdef PCKBCDEBUG
699 printf("pckbc_cleanqueue: removing");
700 for (i = 0; i < cmd->cmdlen; i++)
701 printf(" %02x", cmd->cmd[i]);
702 printf("\n");
703 #endif
704 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
705 }
706 }
707
708 /*
709 * Timeout error handler: clean queues and data port.
710 * XXX could be less invasive.
711 */
712 void
713 pckbc_cleanup(self)
714 void *self;
715 {
716 struct pckbc_internal *t = self;
717 int s;
718
719 printf("pckbc: command timeout\n");
720
721 s = spltty();
722
723 if (t->t_slotdata[PCKBC_KBD_SLOT])
724 pckbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]);
725 if (t->t_slotdata[PCKBC_AUX_SLOT])
726 pckbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]);
727
728 while (bus_space_read_1(t->t_iot, t->t_ioh_c, 0) & KBS_DIB) {
729 KBD_DELAY;
730 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
731 }
732
733 /* reset KBC? */
734
735 splx(s);
736 }
737
738 /*
739 * Pass command to device during normal operation.
740 * to be called at spltty()
741 */
742 void
743 pckbc_start(t, slot)
744 struct pckbc_internal *t;
745 pckbc_slot_t slot;
746 {
747 struct pckbc_slotdata *q = t->t_slotdata[slot];
748 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
749
750 if (q->polling) {
751 do {
752 pckbc_poll_cmd1(t, slot, cmd);
753 if (cmd->status)
754 printf("pckbc_start: command error\n");
755
756 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
757 if (cmd->flags & KBC_CMDFLAG_SYNC)
758 wakeup(cmd);
759 else {
760 callout_stop(&t->t_cleanup);
761 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
762 }
763 cmd = TAILQ_FIRST(&q->cmdqueue);
764 } while (cmd);
765 return;
766 }
767
768 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
769 printf("pckbc_start: send error\n");
770 /* XXX what now? */
771 return;
772 }
773 }
774
775 /*
776 * Handle command responses coming in asynchonously,
777 * return nonzero if valid response.
778 * to be called at spltty()
779 */
780 int
781 pckbc_cmdresponse(t, slot, data)
782 struct pckbc_internal *t;
783 pckbc_slot_t slot;
784 u_char data;
785 {
786 struct pckbc_slotdata *q = t->t_slotdata[slot];
787 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
788 #ifdef DIAGNOSTIC
789 if (!cmd)
790 panic("pckbc_cmdresponse: no active command");
791 #endif
792 if (cmd->cmdidx < cmd->cmdlen) {
793 if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND)
794 return (0);
795
796 if (data == KBC_DEVCMD_RESEND) {
797 if (cmd->retries++ < 5) {
798 /* try again last command */
799 goto restart;
800 } else {
801 printf("pckbc: cmd failed\n");
802 cmd->status = EIO;
803 /* dequeue */
804 }
805 } else {
806 if (++cmd->cmdidx < cmd->cmdlen)
807 goto restart;
808 if (cmd->responselen)
809 return (1);
810 /* else dequeue */
811 }
812 } else if (cmd->responseidx < cmd->responselen) {
813 cmd->response[cmd->responseidx++] = data;
814 if (cmd->responseidx < cmd->responselen)
815 return (1);
816 /* else dequeue */
817 } else
818 return (0);
819
820 /* dequeue: */
821 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
822 if (cmd->flags & KBC_CMDFLAG_SYNC)
823 wakeup(cmd);
824 else {
825 callout_stop(&t->t_cleanup);
826 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
827 }
828 if (!CMD_IN_QUEUE(q))
829 return (1);
830 restart:
831 pckbc_start(t, slot);
832 return (1);
833 }
834
835 /*
836 * Put command into the device's command queue, return zero or errno.
837 */
838 int
839 pckbc_enqueue_cmd(self, slot, cmd, len, responselen, sync, respbuf)
840 pckbc_tag_t self;
841 pckbc_slot_t slot;
842 u_char *cmd;
843 int len, responselen, sync;
844 u_char *respbuf;
845 {
846 struct pckbc_internal *t = self;
847 struct pckbc_slotdata *q = t->t_slotdata[slot];
848 struct pckbc_devcmd *nc;
849 int s, isactive, res = 0;
850
851 if ((len > 4) || (responselen > 4))
852 return (EINVAL);
853 s = spltty();
854 nc = TAILQ_FIRST(&q->freequeue);
855 if (nc) {
856 TAILQ_REMOVE(&q->freequeue, nc, next);
857 }
858 splx(s);
859 if (!nc)
860 return (ENOMEM);
861
862 memset(nc, 0, sizeof(*nc));
863 memcpy(nc->cmd, cmd, len);
864 nc->cmdlen = len;
865 nc->responselen = responselen;
866 nc->flags = (sync ? KBC_CMDFLAG_SYNC : 0);
867
868 s = spltty();
869
870 if (q->polling && sync) {
871 /*
872 * XXX We should poll until the queue is empty.
873 * But we don't come here normally, so make
874 * it simple and throw away everything.
875 */
876 pckbc_cleanqueue(q);
877 }
878
879 isactive = CMD_IN_QUEUE(q);
880 TAILQ_INSERT_TAIL(&q->cmdqueue, nc, next);
881 if (!isactive)
882 pckbc_start(t, slot);
883
884 if (q->polling)
885 res = (sync ? nc->status : 0);
886 else if (sync) {
887 if ((res = tsleep(nc, 0, "kbccmd", 1*hz))) {
888 TAILQ_REMOVE(&q->cmdqueue, nc, next);
889 pckbc_cleanup(t);
890 } else
891 res = nc->status;
892 } else
893 callout_reset(&t->t_cleanup, hz, pckbc_cleanup, t);
894
895 if (sync) {
896 if (respbuf)
897 memcpy(respbuf, nc->response, responselen);
898 TAILQ_INSERT_TAIL(&q->freequeue, nc, next);
899 }
900
901 splx(s);
902
903 return (res);
904 }
905
906 void
907 pckbc_set_inputhandler(self, slot, func, arg, name)
908 pckbc_tag_t self;
909 pckbc_slot_t slot;
910 pckbc_inputfcn func;
911 void *arg;
912 char *name;
913 {
914 struct pckbc_internal *t = (struct pckbc_internal *)self;
915 struct pckbc_softc *sc = t->t_sc;
916
917 if (slot >= PCKBC_NSLOTS)
918 panic("pckbc_set_inputhandler: bad slot %d", slot);
919
920 (*sc->intr_establish)(sc, slot);
921
922 sc->inputhandler[slot] = func;
923 sc->inputarg[slot] = arg;
924 sc->subname[slot] = name;
925 }
926
927 int
928 pckbcintr(vsc)
929 void *vsc;
930 {
931 struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
932 struct pckbc_internal *t = sc->id;
933 u_char stat;
934 pckbc_slot_t slot;
935 struct pckbc_slotdata *q;
936 int served = 0, data;
937
938 for(;;) {
939 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
940 if (!(stat & KBS_DIB))
941 break;
942
943 served = 1;
944
945 slot = (t->t_haveaux && (stat & 0x20)) ?
946 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
947 q = t->t_slotdata[slot];
948
949 if (!q) {
950 /* XXX do something for live insertion? */
951 printf("pckbcintr: no dev for slot %d\n", slot);
952 KBD_DELAY;
953 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
954 continue;
955 }
956
957 KBD_DELAY;
958 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
959
960 #if NRND > 0
961 rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
962 #endif
963
964 if (q->polling) {
965 q->poll_data = data;
966 q->poll_stat = stat;
967 break; /* pckbc_poll_data() will get it */
968 }
969
970 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
971 continue;
972
973 if (sc->inputhandler[slot])
974 (*sc->inputhandler[slot])(sc->inputarg[slot], data);
975 #ifdef PCKBCDEBUG
976 else
977 printf("pckbcintr: slot %d lost %d\n", slot, data);
978 #endif
979 }
980
981 return (served);
982 }
983
984 int
985 pckbc_cnattach(iot, addr, cmd_offset, slot)
986 bus_space_tag_t iot;
987 bus_addr_t addr;
988 bus_size_t cmd_offset;
989 pckbc_slot_t slot;
990 {
991 bus_space_handle_t ioh_d, ioh_c;
992 int res = 0;
993
994 if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
995 return (ENXIO);
996 if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
997 bus_space_unmap(iot, ioh_d, 1);
998 return (ENXIO);
999 }
1000
1001 memset(&pckbc_consdata, 0, sizeof(pckbc_consdata));
1002 pckbc_consdata.t_iot = iot;
1003 pckbc_consdata.t_ioh_d = ioh_d;
1004 pckbc_consdata.t_ioh_c = ioh_c;
1005 pckbc_consdata.t_addr = addr;
1006 callout_init(&pckbc_consdata.t_cleanup);
1007
1008 /* flush */
1009 (void) pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT, 0);
1010
1011 /* selftest? */
1012
1013 /* init cmd byte, enable ports */
1014 pckbc_consdata.t_cmdbyte = KC8_CPU;
1015 if (!pckbc_put8042cmd(&pckbc_consdata)) {
1016 printf("kbc: cmd word write error\n");
1017 res = EIO;
1018 }
1019
1020 if (!res) {
1021 #if (NPCKBD > 0)
1022 res = pckbd_cnattach(&pckbc_consdata, slot);
1023 #else
1024 /*
1025 * XXX This should be replaced with the `notyet' case
1026 * XXX when all of the old PC-style console drivers
1027 * XXX have gone away. When that happens, all of
1028 * XXX the pckbc_machdep_cnattach() should be purged,
1029 * XXX as well.
1030 */
1031 #ifdef notyet
1032 res = ENXIO;
1033 #else
1034 res = pckbc_machdep_cnattach(&pckbc_consdata, slot);
1035 #endif
1036 #endif /* NPCKBD > 0 */
1037 }
1038
1039 if (res) {
1040 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
1041 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
1042 } else {
1043 pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
1044 pckbc_init_slotdata(&pckbc_cons_slotdata);
1045 pckbc_console = 1;
1046 }
1047
1048 return (res);
1049 }
1050