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