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