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