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