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