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