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