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