1 /* $OpenBSD: pckbc.c,v 1.55 2023/08/26 15:01:00 jmc Exp $ */
2 /* $NetBSD: pckbc.c,v 1.5 2000/06/09 04:58:35 soda Exp $ */
3
4 /*
5 * Copyright (c) 1998
6 * Matthias Drochner. All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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/device.h>
34 #include <sys/malloc.h>
35 #include <sys/errno.h>
36 #include <sys/queue.h>
37
38 #include <machine/bus.h>
39 #include <machine/cpu.h>
40
41 #include <dev/ic/i8042reg.h>
42 #include <dev/ic/pckbcvar.h>
43
44 #include "pckbd.h"
45
46 #if NPCKBD > 0
47 #include <dev/pckbc/pckbdvar.h>
48 #endif
49
50 #ifdef PCKBCDEBUG
51 #define DPRINTF(x...) do { printf(x); } while (0);
52 #else
53 #define DPRINTF(x...)
54 #endif
55
56 /* descriptor for one device command */
57 struct pckbc_devcmd {
58 TAILQ_ENTRY(pckbc_devcmd) next;
59 int flags;
60 #define KBC_CMDFLAG_SYNC 1 /* give descriptor back to caller */
61 #define KBC_CMDFLAG_SLOW 2
62 #define KBC_CMDFLAG_QUEUED 4 /* descriptor on cmdqueue */
63 u_char cmd[4];
64 int cmdlen, cmdidx, retries;
65 u_char response[4];
66 int status, responselen, responseidx;
67 };
68
69 /* data per slave device */
70 struct pckbc_slotdata {
71 int polling; /* don't read data port in interrupt handler */
72 TAILQ_HEAD(, pckbc_devcmd) cmdqueue; /* active commands */
73 TAILQ_HEAD(, pckbc_devcmd) freequeue; /* free commands */
74 #define NCMD 5
75 struct pckbc_devcmd cmds[NCMD];
76 };
77
78 #define CMD_IN_QUEUE(q) (!TAILQ_EMPTY(&(q)->cmdqueue))
79
80 void pckbc_init_slotdata(struct pckbc_slotdata *);
81 int pckbc_attach_slot(struct pckbc_softc *, pckbc_slot_t, int);
82 int pckbc_submatch_locators(struct device *, void *, void *);
83 int pckbc_submatch(struct device *, void *, void *);
84 int pckbcprint(void *, const char *);
85
86 struct pckbc_internal pckbc_consdata;
87 int pckbc_console_attached;
88
89 int pckbc_console;
90 static struct pckbc_slotdata pckbc_cons_slotdata;
91
92 static int pckbc_wait_output(bus_space_tag_t, bus_space_handle_t);
93
94 static int pckbc_get8042cmd(struct pckbc_internal *);
95 static int pckbc_put8042cmd(struct pckbc_internal *);
96 static int pckbc_send_devcmd(struct pckbc_internal *, pckbc_slot_t,
97 u_char);
98 static void pckbc_poll_cmd1(struct pckbc_internal *, pckbc_slot_t,
99 struct pckbc_devcmd *);
100
101 void pckbc_cleanqueues(struct pckbc_internal *);
102 void pckbc_cleanqueue(struct pckbc_slotdata *);
103 void pckbc_cleanup(void *);
104 void pckbc_poll(void *);
105 int pckbc_cmdresponse(struct pckbc_internal *, pckbc_slot_t, u_char);
106 void pckbc_start(struct pckbc_internal *, pckbc_slot_t);
107 int pckbcintr_internal(struct pckbc_internal *, struct pckbc_softc *);
108
109 const char *pckbc_slot_names[] = { "kbd", "aux" };
110
111 #define KBC_DEVCMD_ACK 0xfa
112 #define KBC_DEVCMD_RESEND 0xfe
113 #define KBC_DEVCMD_BAT_DONE 0xaa
114 #define KBC_DEVCMD_BAT_FAIL 0xfc
115
116 #define KBD_DELAY DELAY(8)
117
118 static inline int
pckbc_wait_output(bus_space_tag_t iot,bus_space_handle_t ioh_c)119 pckbc_wait_output(bus_space_tag_t iot, bus_space_handle_t ioh_c)
120 {
121 u_int i;
122
123 for (i = 100000; i; i--)
124 if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
125 KBD_DELAY;
126 return (1);
127 }
128 return (0);
129 }
130
131 int
pckbc_send_cmd(bus_space_tag_t iot,bus_space_handle_t ioh_c,u_char val)132 pckbc_send_cmd(bus_space_tag_t iot, bus_space_handle_t ioh_c, u_char val)
133 {
134 if (!pckbc_wait_output(iot, ioh_c))
135 return (0);
136 bus_space_write_1(iot, ioh_c, 0, val);
137 return (1);
138 }
139
140 int
pckbc_poll_data1(bus_space_tag_t iot,bus_space_handle_t ioh_d,bus_space_handle_t ioh_c,pckbc_slot_t slot,int checkaux)141 pckbc_poll_data1(bus_space_tag_t iot, bus_space_handle_t ioh_d,
142 bus_space_handle_t ioh_c, pckbc_slot_t slot, int checkaux)
143 {
144 int i;
145 u_char stat;
146
147 /* polls for ~100ms */
148 for (i = 100; i; i--, delay(1000)) {
149 stat = bus_space_read_1(iot, ioh_c, 0);
150 if (stat & KBS_DIB) {
151 register u_char c;
152
153 KBD_DELAY;
154 CPU_BUSY_CYCLE();
155 c = bus_space_read_1(iot, ioh_d, 0);
156 if (checkaux && (stat & KBS_AUXDATA)) {
157 if (slot != PCKBC_AUX_SLOT) {
158 DPRINTF("lost aux 0x%x\n", c);
159 continue;
160 }
161 } else {
162 if (slot == PCKBC_AUX_SLOT) {
163 DPRINTF("lost kbd 0x%x\n", c);
164 continue;
165 } else if (stat & KBS_AUXDATA) {
166 DPRINTF("discard aux data 0x%x\n", c);
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(struct pckbc_internal * t)180 pckbc_get8042cmd(struct pckbc_internal *t)
181 {
182 bus_space_tag_t iot = t->t_iot;
183 bus_space_handle_t ioh_d = t->t_ioh_d;
184 bus_space_handle_t ioh_c = t->t_ioh_c;
185 int data;
186
187 if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
188 return (0);
189 data = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT,
190 t->t_haveaux);
191 if (data == -1)
192 return (0);
193 t->t_cmdbyte = data;
194 return (1);
195 }
196
197 /*
198 * Pass command byte to keyboard controller (8042).
199 */
200 static int
pckbc_put8042cmd(struct pckbc_internal * t)201 pckbc_put8042cmd(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
pckbc_send_devcmd(struct pckbc_internal * t,pckbc_slot_t slot,u_char val)216 pckbc_send_devcmd(struct pckbc_internal *t, pckbc_slot_t slot, u_char val)
217 {
218 bus_space_tag_t iot = t->t_iot;
219 bus_space_handle_t ioh_d = t->t_ioh_d;
220 bus_space_handle_t ioh_c = t->t_ioh_c;
221
222 if (slot == PCKBC_AUX_SLOT) {
223 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
224 return (0);
225 }
226 if (!pckbc_wait_output(iot, ioh_c))
227 return (0);
228 bus_space_write_1(iot, ioh_d, 0, val);
229 return (1);
230 }
231
232 int
pckbc_is_console(bus_space_tag_t iot,bus_addr_t addr)233 pckbc_is_console(bus_space_tag_t iot, bus_addr_t addr)
234 {
235 if (pckbc_console && !pckbc_console_attached &&
236 pckbc_consdata.t_iot == iot &&
237 pckbc_consdata.t_addr == addr)
238 return (1);
239 return (0);
240 }
241
242 int
pckbc_submatch_locators(struct device * parent,void * match,void * aux)243 pckbc_submatch_locators(struct device *parent, void *match, void *aux)
244 {
245 struct cfdata *cf = match;
246 struct pckbc_attach_args *pa = aux;
247
248 if (cf->cf_loc[PCKBCCF_SLOT] != PCKBCCF_SLOT_DEFAULT &&
249 cf->cf_loc[PCKBCCF_SLOT] != pa->pa_slot)
250 return (0);
251 return (1);
252 }
253
254 int
pckbc_submatch(struct device * parent,void * match,void * aux)255 pckbc_submatch(struct device *parent, void *match, void *aux)
256 {
257 struct cfdata *cf = match;
258
259 if (pckbc_submatch_locators(parent, match, aux) == 0)
260 return (0);
261 return ((*cf->cf_attach->ca_match)(parent, cf, aux));
262 }
263
264 int
pckbc_attach_slot(struct pckbc_softc * sc,pckbc_slot_t slot,int force)265 pckbc_attach_slot(struct pckbc_softc *sc, pckbc_slot_t slot, int force)
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, pckbcprint,
274 force ? pckbc_submatch_locators : pckbc_submatch) != NULL);
275
276 if ((found || slot == PCKBC_AUX_SLOT) && !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 if (!found && slot == PCKBC_AUX_SLOT) {
284 /*
285 * Some machines don't handle disabling the aux slot
286 * completely and still generate data when the mouse is
287 * moved, so setup a dummy interrupt handler to discard
288 * this slot's data.
289 */
290 pckbc_set_inputhandler(t, PCKBC_AUX_SLOT, NULL, sc,
291 NULL);
292 found = 1;
293 }
294 }
295 return (found);
296 }
297
298 void
pckbc_attach(struct pckbc_softc * sc,int flags)299 pckbc_attach(struct pckbc_softc *sc, int flags)
300 {
301 struct pckbc_internal *t;
302 bus_space_tag_t iot;
303 bus_space_handle_t ioh_d, ioh_c;
304 int haskbd = 0, res;
305 u_char cmdbits = 0;
306
307 t = sc->id;
308 iot = t->t_iot;
309 ioh_d = t->t_ioh_d;
310 ioh_c = t->t_ioh_c;
311
312 if (pckbc_console == 0) {
313 timeout_set(&t->t_cleanup, pckbc_cleanup, t);
314 timeout_set(&t->t_poll, pckbc_poll, t);
315 }
316
317 /* flush */
318 (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
319
320 /* set initial cmd byte */
321 if (!pckbc_put8042cmd(t)) {
322 #if defined(__i386__) || defined(__amd64__)
323 if (!ISSET(flags, PCKBCF_FORCE_KEYBOARD_PRESENT)) {
324 pckbc_release_console();
325 return;
326 }
327 #endif
328 printf("kbc: cmd word write error\n");
329 return;
330 }
331
332 /*
333 * XXX Don't check the keyboard port. There are broken keyboard controllers
334 * which don't pass the test but work normally otherwise.
335 */
336 #if 0
337 /*
338 * check kbd port ok
339 */
340 if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
341 return;
342 res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
343
344 /*
345 * Normally, we should get a "0" here.
346 * But there are keyboard controllers behaving differently.
347 */
348 if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
349 #ifdef PCKBCDEBUG
350 if (res != 0)
351 printf("kbc: returned %x on kbd slot test\n", res);
352 #endif
353 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT, 0)) {
354 cmdbits |= KC8_KENABLE;
355 haskbd = 1;
356 }
357 } else {
358 printf("kbc: kbd port test: %x\n", res);
359 return;
360 }
361 #else
362 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT, 0)) {
363 cmdbits |= KC8_KENABLE;
364 haskbd = 1;
365 }
366 #endif /* 0 */
367
368 /*
369 * Check aux port ok.
370 * Avoid KBC_AUXTEST because it hangs some older controllers
371 * (eg UMC880?).
372 */
373 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXECHO)) {
374 printf("kbc: aux echo error 1\n");
375 goto nomouse;
376 }
377 if (!pckbc_wait_output(iot, ioh_c)) {
378 printf("kbc: aux echo error 2\n");
379 goto nomouse;
380 }
381 bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
382 res = pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_AUX_SLOT, 1);
383
384 if (ISSET(t->t_flags, PCKBC_NEED_AUXWRITE)) {
385 /*
386 * The following code is necessary to find the aux port on the
387 * oqo-1 machine, among others. However if confuses old
388 * (non-ps/2) keyboard controllers (at least UMC880x again).
389 */
390 if (res == -1) {
391 /* Read of aux echo timed out, try again */
392 if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
393 goto nomouse;
394 if (!pckbc_wait_output(iot, ioh_c))
395 goto nomouse;
396 bus_space_write_1(iot, ioh_d, 0, 0x5a);
397 res = pckbc_poll_data1(iot, ioh_d, ioh_c,
398 PCKBC_AUX_SLOT, 1);
399 DPRINTF("kbc: aux echo: %x\n", res);
400 }
401 }
402
403 if (res != -1) {
404 /*
405 * In most cases, the 0x5a gets echoed.
406 * Some old controllers (Gateway 2000 circa 1993)
407 * return 0xfe here.
408 * We are satisfied if there is anything in the
409 * aux output buffer.
410 */
411 DPRINTF("kbc: aux echo: %x\n", res);
412 t->t_haveaux = 1;
413 if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT, 0))
414 cmdbits |= KC8_MENABLE;
415 }
416 #ifdef PCKBCDEBUG
417 else
418 printf("kbc: aux echo test failed\n");
419 #endif
420
421 #if defined(__i386__) || defined(__amd64__)
422 if (haskbd == 0 && !ISSET(flags, PCKBCF_FORCE_KEYBOARD_PRESENT)) {
423 if (t->t_haveaux) {
424 if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT, 1))
425 cmdbits |= KC8_KENABLE;
426 } else {
427 pckbc_release_console();
428 }
429 }
430 #endif
431
432 nomouse:
433 /* enable needed interrupts */
434 t->t_cmdbyte |= cmdbits;
435 if (!pckbc_put8042cmd(t))
436 printf("kbc: cmd word write error\n");
437 }
438
439 int
pckbcprint(void * aux,const char * pnp)440 pckbcprint(void *aux, const char *pnp)
441 {
442 struct pckbc_attach_args *pa = aux;
443
444 if (!pnp)
445 printf(" (%s slot)", pckbc_slot_names[pa->pa_slot]);
446 return (QUIET);
447 }
448
449 void
pckbc_release_console(void)450 pckbc_release_console(void)
451 {
452 #if defined(__i386__) || defined(__amd64__)
453 /*
454 * If there is no keyboard present, yet we are the console,
455 * we might be on a legacy-free PC where the PS/2 emulated
456 * keyboard was elected as console, but went away as soon
457 * as the USB controller drivers attached.
458 *
459 * In that case, we want to release ourselves from console
460 * duties, unless we have been able to attach a mouse,
461 * which would mean this is a real PS/2 controller
462 * after all.
463 */
464 if (pckbc_console != 0) {
465 extern void wscn_input_init(int);
466
467 pckbc_console = 0;
468 wscn_input_init(1);
469 }
470 #endif
471 }
472
473 void
pckbc_init_slotdata(struct pckbc_slotdata * q)474 pckbc_init_slotdata(struct pckbc_slotdata *q)
475 {
476 int i;
477 TAILQ_INIT(&q->cmdqueue);
478 TAILQ_INIT(&q->freequeue);
479
480 for (i = 0; i < NCMD; i++) {
481 TAILQ_INSERT_TAIL(&q->freequeue, &(q->cmds[i]), next);
482 }
483 q->polling = 0;
484 }
485
486 void
pckbc_flush(pckbc_tag_t self,pckbc_slot_t slot)487 pckbc_flush(pckbc_tag_t self, pckbc_slot_t slot)
488 {
489 struct pckbc_internal *t = self;
490
491 (void) pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c,
492 slot, t->t_haveaux);
493 }
494
495 int
pckbc_poll_data(pckbc_tag_t self,pckbc_slot_t slot)496 pckbc_poll_data(pckbc_tag_t self, pckbc_slot_t slot)
497 {
498 struct pckbc_internal *t = self;
499 struct pckbc_slotdata *q = t->t_slotdata[slot];
500 int c;
501
502 c = pckbc_poll_data1(t->t_iot, t->t_ioh_d, t->t_ioh_c,
503 slot, t->t_haveaux);
504 if (c != -1 && q && CMD_IN_QUEUE(q)) {
505 /* we jumped into a running command - try to
506 deliver the response */
507 if (pckbc_cmdresponse(t, slot, c))
508 return (-1);
509 }
510 return (c);
511 }
512
513 /*
514 * set scancode translation on
515 */
516 int
pckbc_xt_translation(pckbc_tag_t self,int * table)517 pckbc_xt_translation(pckbc_tag_t self, int *table)
518 {
519 struct pckbc_internal *t = self;
520
521 #ifdef __sparc64__ /* only pckbc@ebus on sparc64 uses this */
522 if ((t->t_flags & PCKBC_CANT_TRANSLATE) != 0) {
523 /* Hardware lacks translation capability. Nothing to do! */
524 if (t->t_flags & PCKBC_FIXED_SET2)
525 *table = 2;
526 else /* PCKBC_FIXED_SET3 */
527 *table = 3;
528 return (-1);
529 }
530 #endif
531
532 if (t->t_cmdbyte & KC8_TRANS)
533 return (0);
534
535 t->t_cmdbyte |= KC8_TRANS;
536 if (!pckbc_put8042cmd(t))
537 return (-1);
538
539 /* read back to be sure */
540 if (!pckbc_get8042cmd(t))
541 return (-1);
542
543 return (t->t_cmdbyte & KC8_TRANS) ? (0) : (-1);
544 }
545
546 static struct pckbc_portcmd {
547 u_char cmd_en, cmd_dis;
548 } pckbc_portcmd[2] = {
549 {
550 KBC_KBDENABLE, KBC_KBDDISABLE,
551 }, {
552 KBC_AUXENABLE, KBC_AUXDISABLE,
553 }
554 };
555
556 void
pckbc_slot_enable(pckbc_tag_t self,pckbc_slot_t slot,int on)557 pckbc_slot_enable(pckbc_tag_t self, pckbc_slot_t slot, int on)
558 {
559 struct pckbc_internal *t = (struct pckbc_internal *)self;
560 struct pckbc_portcmd *cmd;
561
562 cmd = &pckbc_portcmd[slot];
563
564 if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
565 on ? cmd->cmd_en : cmd->cmd_dis))
566 printf("pckbc_slot_enable(%d) failed\n", on);
567
568 if (slot == PCKBC_KBD_SLOT) {
569 if (on)
570 timeout_add_sec(&t->t_poll, 1);
571 else
572 timeout_del(&t->t_poll);
573 }
574 }
575
576 void
pckbc_set_poll(pckbc_tag_t self,pckbc_slot_t slot,int on)577 pckbc_set_poll(pckbc_tag_t self, pckbc_slot_t slot, int on)
578 {
579 struct pckbc_internal *t = (struct pckbc_internal *)self;
580
581 t->t_slotdata[slot]->polling = on;
582
583 if (!on) {
584 int s;
585
586 /*
587 * If disabling polling on a device that's been configured,
588 * make sure there are no bytes left in the FIFO, holding up
589 * the interrupt line. Otherwise we won't get any further
590 * interrupts.
591 */
592 if (t->t_sc) {
593 s = spltty();
594 pckbcintr_internal(t, t->t_sc);
595 splx(s);
596 }
597 }
598 }
599
600 /*
601 * Pass command to device, poll for ACK and data.
602 * to be called at spltty()
603 */
604 static void
pckbc_poll_cmd1(struct pckbc_internal * t,pckbc_slot_t slot,struct pckbc_devcmd * cmd)605 pckbc_poll_cmd1(struct pckbc_internal *t, pckbc_slot_t slot,
606 struct pckbc_devcmd *cmd)
607 {
608 bus_space_tag_t iot = t->t_iot;
609 bus_space_handle_t ioh_d = t->t_ioh_d;
610 bus_space_handle_t ioh_c = t->t_ioh_c;
611 int i, c = 0;
612
613 while (cmd->cmdidx < cmd->cmdlen) {
614 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
615 printf("pckbc_cmd: send error\n");
616 cmd->status = EIO;
617 return;
618 }
619 for (i = 10; i; i--) { /* 1s ??? */
620 c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot,
621 t->t_haveaux);
622 if (c != -1)
623 break;
624 }
625
626 switch (c) {
627 case KBC_DEVCMD_ACK:
628 cmd->cmdidx++;
629 continue;
630 /*
631 * Some legacy free PCs keep returning Basic Assurance Test
632 * (BAT) instead of something usable, so fail gracefully.
633 */
634 case KBC_DEVCMD_RESEND:
635 case KBC_DEVCMD_BAT_DONE:
636 case KBC_DEVCMD_BAT_FAIL:
637 DPRINTF("pckbc_cmd: %s\n",
638 c == KBC_DEVCMD_RESEND ? "RESEND": "BAT");
639 if (cmd->retries++ < 5)
640 continue;
641
642 DPRINTF("pckbc_cmd: cmd failed\n");
643 cmd->status = ENXIO;
644 return;
645 case -1:
646 DPRINTF("pckbc_cmd: timeout\n");
647 cmd->status = EIO;
648 return;
649 default:
650 DPRINTF("pckbc_cmd: lost 0x%x\n", c);
651 }
652 }
653
654 while (cmd->responseidx < cmd->responselen) {
655 if (cmd->flags & KBC_CMDFLAG_SLOW)
656 i = 100; /* 10s ??? */
657 else
658 i = 10; /* 1s ??? */
659 while (i--) {
660 c = pckbc_poll_data1(iot, ioh_d, ioh_c, slot,
661 t->t_haveaux);
662 if (c != -1)
663 break;
664 }
665 if (c == -1) {
666 DPRINTF("pckbc_cmd: no data\n");
667 cmd->status = ETIMEDOUT;
668 return;
669 } else
670 cmd->response[cmd->responseidx++] = c;
671 }
672 }
673
674 /* for use in autoconfiguration */
675 int
pckbc_poll_cmd(pckbc_tag_t self,pckbc_slot_t slot,u_char * cmd,int len,int responselen,u_char * respbuf,int slow)676 pckbc_poll_cmd(pckbc_tag_t self, pckbc_slot_t slot, u_char *cmd, int len,
677 int responselen, u_char *respbuf, int slow)
678 {
679 struct pckbc_devcmd nc;
680
681 if ((len > 4) || (responselen > 4))
682 return (EINVAL);
683
684 bzero(&nc, sizeof(nc));
685 memcpy(nc.cmd, cmd, len);
686 nc.cmdlen = len;
687 nc.responselen = responselen;
688 nc.flags = (slow ? KBC_CMDFLAG_SLOW : 0);
689
690 pckbc_poll_cmd1(self, slot, &nc);
691
692 if (nc.status == 0 && respbuf)
693 memcpy(respbuf, nc.response, responselen);
694
695 return (nc.status);
696 }
697
698 /*
699 * Clean up a command queue, throw away everything.
700 */
701 void
pckbc_cleanqueue(struct pckbc_slotdata * q)702 pckbc_cleanqueue(struct pckbc_slotdata *q)
703 {
704 struct pckbc_devcmd *cmd;
705 #ifdef PCKBCDEBUG
706 int i;
707 #endif
708
709 while ((cmd = TAILQ_FIRST(&q->cmdqueue))) {
710 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
711 cmd->flags &= ~KBC_CMDFLAG_QUEUED;
712 #ifdef PCKBCDEBUG
713 printf("pckbc_cleanqueue: removing");
714 for (i = 0; i < cmd->cmdlen; i++)
715 printf(" %02x", cmd->cmd[i]);
716 printf("\n");
717 #endif
718 /*
719 * A synchronous command on the cmdqueue is currently owned by a
720 * sleeping proc. The same proc is responsible for putting it
721 * back on the freequeue once awake.
722 */
723 if (cmd->flags & KBC_CMDFLAG_SYNC)
724 continue;
725
726 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
727 }
728 }
729
730 void
pckbc_cleanqueues(struct pckbc_internal * t)731 pckbc_cleanqueues(struct pckbc_internal *t)
732 {
733 if (t->t_slotdata[PCKBC_KBD_SLOT])
734 pckbc_cleanqueue(t->t_slotdata[PCKBC_KBD_SLOT]);
735 if (t->t_slotdata[PCKBC_AUX_SLOT])
736 pckbc_cleanqueue(t->t_slotdata[PCKBC_AUX_SLOT]);
737 }
738
739 /*
740 * Timeout error handler: clean queues and data port.
741 * XXX could be less invasive.
742 */
743 void
pckbc_cleanup(void * self)744 pckbc_cleanup(void *self)
745 {
746 struct pckbc_internal *t = self;
747 int s;
748
749 printf("pckbc: command timeout\n");
750
751 s = spltty();
752
753 pckbc_cleanqueues(t);
754
755 while (bus_space_read_1(t->t_iot, t->t_ioh_c, 0) & KBS_DIB) {
756 KBD_DELAY;
757 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
758 }
759
760 /* reset KBC? */
761
762 splx(s);
763 }
764
765 /*
766 * Stop the keyboard controller when we are going to suspend
767 */
768 void
pckbc_stop(struct pckbc_softc * sc)769 pckbc_stop(struct pckbc_softc *sc)
770 {
771 struct pckbc_internal *t = sc->id;
772
773 timeout_del(&t->t_poll);
774 pckbc_cleanqueues(t);
775 timeout_del(&t->t_cleanup);
776 }
777
778 /*
779 * Reset the keyboard controller in a violent fashion; normally done
780 * after suspend/resume when we do not trust the machine.
781 */
782 void
pckbc_reset(struct pckbc_softc * sc)783 pckbc_reset(struct pckbc_softc *sc)
784 {
785 struct pckbc_internal *t = sc->id;
786 bus_space_tag_t iot = t->t_iot;
787 bus_space_handle_t ioh_d = t->t_ioh_d, ioh_c = t->t_ioh_c;
788
789 pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
790 /* KBC selftest */
791 if (pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST) == 0)
792 return;
793 pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
794 (void)pckbc_put8042cmd(t);
795 pckbcintr_internal(t->t_sc->id, t->t_sc);
796 }
797
798 /*
799 * Pass command to device during normal operation.
800 * to be called at spltty()
801 */
802 void
pckbc_start(struct pckbc_internal * t,pckbc_slot_t slot)803 pckbc_start(struct pckbc_internal *t, pckbc_slot_t slot)
804 {
805 struct pckbc_slotdata *q = t->t_slotdata[slot];
806 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
807
808 if (q->polling) {
809 do {
810 pckbc_poll_cmd1(t, slot, cmd);
811 if (cmd->status)
812 printf("pckbc_start: command error\n");
813
814 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
815 cmd->flags &= ~KBC_CMDFLAG_QUEUED;
816 if (cmd->flags & KBC_CMDFLAG_SYNC) {
817 wakeup(cmd);
818 } else {
819 timeout_del(&t->t_cleanup);
820 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
821 }
822 cmd = TAILQ_FIRST(&q->cmdqueue);
823 } while (cmd);
824 return;
825 }
826
827 if (!pckbc_send_devcmd(t, slot, cmd->cmd[cmd->cmdidx])) {
828 printf("pckbc_start: send error\n");
829 /* XXX what now? */
830 return;
831 }
832 }
833
834 /*
835 * Handle command responses coming in asynchronously,
836 * return nonzero if valid response.
837 * to be called at spltty()
838 */
839 int
pckbc_cmdresponse(struct pckbc_internal * t,pckbc_slot_t slot,u_char data)840 pckbc_cmdresponse(struct pckbc_internal *t, pckbc_slot_t slot, u_char data)
841 {
842 struct pckbc_slotdata *q = t->t_slotdata[slot];
843 struct pckbc_devcmd *cmd = TAILQ_FIRST(&q->cmdqueue);
844 #ifdef DIAGNOSTIC
845 if (!cmd)
846 panic("pckbc_cmdresponse: no active command");
847 #endif
848 if (cmd->cmdidx < cmd->cmdlen) {
849 if (data != KBC_DEVCMD_ACK && data != KBC_DEVCMD_RESEND)
850 return (0);
851
852 if (data == KBC_DEVCMD_RESEND) {
853 if (cmd->retries++ < 5) {
854 /* try again last command */
855 goto restart;
856 } else {
857 DPRINTF("pckbc: cmd failed\n");
858 cmd->status = ENXIO;
859 /* dequeue */
860 }
861 } else {
862 if (++cmd->cmdidx < cmd->cmdlen)
863 goto restart;
864 if (cmd->responselen)
865 return (1);
866 /* else dequeue */
867 }
868 } else if (cmd->responseidx < cmd->responselen) {
869 cmd->response[cmd->responseidx++] = data;
870 if (cmd->responseidx < cmd->responselen)
871 return (1);
872 /* else dequeue */
873 } else
874 return (0);
875
876 /* dequeue: */
877 TAILQ_REMOVE(&q->cmdqueue, cmd, next);
878 cmd->flags &= ~KBC_CMDFLAG_QUEUED;
879 if (cmd->flags & KBC_CMDFLAG_SYNC) {
880 wakeup(cmd);
881 } else {
882 timeout_del(&t->t_cleanup);
883 TAILQ_INSERT_TAIL(&q->freequeue, cmd, next);
884 }
885 cmd = TAILQ_FIRST(&q->cmdqueue);
886 if (cmd == NULL)
887 return (1);
888 restart:
889 pckbc_start(t, slot);
890 return (1);
891 }
892
893 /*
894 * Put command into the device's command queue, return zero or errno.
895 */
896 int
pckbc_enqueue_cmd(pckbc_tag_t self,pckbc_slot_t slot,u_char * cmd,int len,int responselen,int sync,u_char * respbuf)897 pckbc_enqueue_cmd(pckbc_tag_t self, pckbc_slot_t slot, u_char *cmd, int len,
898 int responselen, int sync, u_char *respbuf)
899 {
900 struct pckbc_internal *t = self;
901 struct pckbc_slotdata *q = t->t_slotdata[slot];
902 struct pckbc_devcmd *nc;
903 int s, isactive, res = 0;
904
905 if ((len > 4) || (responselen > 4))
906 return (EINVAL);
907 s = spltty();
908 nc = TAILQ_FIRST(&q->freequeue);
909 if (nc) {
910 TAILQ_REMOVE(&q->freequeue, nc, next);
911 }
912 splx(s);
913 if (!nc)
914 return (ENOMEM);
915
916 bzero(nc, sizeof(*nc));
917 memcpy(nc->cmd, cmd, len);
918 nc->cmdlen = len;
919 nc->responselen = responselen;
920 nc->flags = (sync ? KBC_CMDFLAG_SYNC : 0);
921
922 s = spltty();
923
924 if (q->polling && sync) {
925 /*
926 * XXX We should poll until the queue is empty.
927 * But we don't come here normally, so make
928 * it simple and throw away everything.
929 */
930 pckbc_cleanqueue(q);
931 }
932
933 isactive = CMD_IN_QUEUE(q);
934 nc->flags |= KBC_CMDFLAG_QUEUED;
935 TAILQ_INSERT_TAIL(&q->cmdqueue, nc, next);
936 if (!isactive)
937 pckbc_start(t, slot);
938
939 if (q->polling)
940 res = (sync ? nc->status : 0);
941 else if (sync) {
942 if ((res = tsleep_nsec(nc, 0, "kbccmd", SEC_TO_NSEC(1)))) {
943 pckbc_cleanup(t);
944 } else {
945 /*
946 * Under certain circumstances, such as during suspend,
947 * tsleep() becomes a no-op and the command is left on
948 * the cmdqueue.
949 */
950 if (nc->flags & KBC_CMDFLAG_QUEUED) {
951 TAILQ_REMOVE(&q->cmdqueue, nc, next);
952 nc->flags &= ~KBC_CMDFLAG_QUEUED;
953 }
954 res = nc->status;
955 }
956 } else
957 timeout_add_sec(&t->t_cleanup, 1);
958
959 if (sync) {
960 if (respbuf)
961 memcpy(respbuf, nc->response, responselen);
962 TAILQ_INSERT_TAIL(&q->freequeue, nc, next);
963 }
964
965 splx(s);
966
967 return (res);
968 }
969
970 void
pckbc_set_inputhandler(pckbc_tag_t self,pckbc_slot_t slot,pckbc_inputfcn func,void * arg,char * name)971 pckbc_set_inputhandler(pckbc_tag_t self, pckbc_slot_t slot, pckbc_inputfcn func,
972 void *arg, char *name)
973 {
974 struct pckbc_internal *t = (struct pckbc_internal *)self;
975 struct pckbc_softc *sc = t->t_sc;
976
977 if (slot >= PCKBC_NSLOTS)
978 panic("pckbc_set_inputhandler: bad slot %d", slot);
979
980 sc->inputhandler[slot] = func;
981 sc->inputarg[slot] = arg;
982 sc->subname[slot] = name;
983
984 if (pckbc_console && slot == PCKBC_KBD_SLOT)
985 timeout_add_sec(&t->t_poll, 1);
986 }
987
988 void
pckbc_poll(void * v)989 pckbc_poll(void *v)
990 {
991 struct pckbc_internal *t = v;
992 int s;
993
994 s = spltty();
995 (void)pckbcintr_internal(t, t->t_sc);
996 timeout_add_sec(&t->t_poll, 1);
997 splx(s);
998 }
999
1000 int
pckbcintr(void * vsc)1001 pckbcintr(void *vsc)
1002 {
1003 struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
1004
1005 return (pckbcintr_internal(sc->id, sc));
1006 }
1007
1008 int
pckbcintr_internal(struct pckbc_internal * t,struct pckbc_softc * sc)1009 pckbcintr_internal(struct pckbc_internal *t, struct pckbc_softc *sc)
1010 {
1011 u_char stat;
1012 pckbc_slot_t slot;
1013 struct pckbc_slotdata *q;
1014 int served = 0, data;
1015
1016 /* reschedule timeout further into the idle times */
1017 if (timeout_pending(&t->t_poll))
1018 timeout_add_sec(&t->t_poll, 1);
1019
1020 for(;;) {
1021 stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
1022 if (!(stat & KBS_DIB))
1023 break;
1024
1025 served = 1;
1026
1027 slot = (t->t_haveaux && (stat & KBS_AUXDATA)) ?
1028 PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
1029 q = t->t_slotdata[slot];
1030
1031 if (!q) {
1032 /* XXX do something for live insertion? */
1033 #ifdef PCKBCDEBUG
1034 printf("pckbcintr: no dev for slot %d\n", slot);
1035 #endif
1036 KBD_DELAY;
1037 (void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
1038 continue;
1039 }
1040
1041 if (q->polling)
1042 break; /* pckbc_poll_data() will get it */
1043
1044 KBD_DELAY;
1045 data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
1046
1047 if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
1048 continue;
1049
1050 if (sc != NULL) {
1051 if (sc->inputhandler[slot])
1052 (*sc->inputhandler[slot])(sc->inputarg[slot],
1053 data);
1054 #ifdef PCKBCDEBUG
1055 else
1056 printf("pckbcintr: slot %d lost %d\n",
1057 slot, data);
1058 #endif
1059 }
1060 }
1061
1062 return (served);
1063 }
1064
1065 int
pckbc_cnattach(bus_space_tag_t iot,bus_addr_t addr,bus_size_t cmd_offset,int flags)1066 pckbc_cnattach(bus_space_tag_t iot, bus_addr_t addr, bus_size_t cmd_offset,
1067 int flags)
1068 {
1069 bus_space_handle_t ioh_d, ioh_c;
1070 int res = 0;
1071
1072 if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
1073 return (ENXIO);
1074 if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
1075 bus_space_unmap(iot, ioh_d, 1);
1076 return (ENXIO);
1077 }
1078
1079 pckbc_consdata.t_iot = iot;
1080 pckbc_consdata.t_ioh_d = ioh_d;
1081 pckbc_consdata.t_ioh_c = ioh_c;
1082 pckbc_consdata.t_addr = addr;
1083 pckbc_consdata.t_flags = flags;
1084 timeout_set(&pckbc_consdata.t_cleanup, pckbc_cleanup, &pckbc_consdata);
1085 timeout_set(&pckbc_consdata.t_poll, pckbc_poll, &pckbc_consdata);
1086
1087 /* flush */
1088 (void) pckbc_poll_data1(iot, ioh_d, ioh_c, PCKBC_KBD_SLOT, 0);
1089
1090 /* selftest? */
1091
1092 /* init cmd byte, enable ports */
1093 pckbc_consdata.t_cmdbyte = KC8_CPU;
1094 if (!pckbc_put8042cmd(&pckbc_consdata)) {
1095 printf("kbc: cmd word write error\n");
1096 res = EIO;
1097 }
1098
1099 if (!res) {
1100 #if (NPCKBD > 0)
1101 res = pckbd_cnattach(&pckbc_consdata);
1102 #else
1103 res = ENXIO;
1104 #endif /* NPCKBD > 0 */
1105 }
1106
1107 if (res) {
1108 bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
1109 bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
1110 } else {
1111 pckbc_consdata.t_slotdata[PCKBC_KBD_SLOT] = &pckbc_cons_slotdata;
1112 pckbc_init_slotdata(&pckbc_cons_slotdata);
1113 pckbc_console = 1;
1114 }
1115
1116 return (res);
1117 }
1118
1119 struct cfdriver pckbc_cd = {
1120 NULL, "pckbc", DV_DULL
1121 };
1122