xref: /openbsd/sys/dev/ic/pckbc.c (revision 8bdbbfa3)
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