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