xref: /netbsd-src/sys/dev/ic/pckbc.c (revision 23c8222edbfb0f0932d88a8351d3a0cf817dfb9e)
1 /* $NetBSD: pckbc.c,v 1.32 2004/03/24 17:26:53 drochner Exp $ */
2 
3 /*
4  * Copyright (c) 2004 Ben Harris.
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/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: pckbc.c,v 1.32 2004/03/24 17:26:53 drochner Exp $");
31 
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/callout.h>
35 #include <sys/kernel.h>
36 #include <sys/proc.h>
37 #include <sys/device.h>
38 #include <sys/malloc.h>
39 #include <sys/errno.h>
40 #include <sys/queue.h>
41 #include <sys/lock.h>
42 
43 #include <machine/bus.h>
44 
45 #include <dev/ic/i8042reg.h>
46 #include <dev/ic/pckbcvar.h>
47 
48 #include <dev/pckbport/pckbportvar.h>
49 
50 #include "rnd.h"
51 #include "locators.h"
52 
53 #if NRND > 0
54 #include <sys/rnd.h>
55 #endif
56 
57 /* data per slave device */
58 struct pckbc_slotdata {
59 	int polling;	/* don't process data in interrupt handler */
60 	int poll_data;	/* data read from inr handler if polling */
61 	int poll_stat;	/* status read from inr handler if polling */
62 #if NRND > 0
63 	rndsource_element_t	rnd_source;
64 #endif
65 };
66 
67 static void pckbc_init_slotdata __P((struct pckbc_slotdata *));
68 static int pckbc_attach_slot __P((struct pckbc_softc *, pckbc_slot_t));
69 
70 struct pckbc_internal pckbc_consdata;
71 int pckbc_console_attached;
72 
73 static int pckbc_console;
74 static struct pckbc_slotdata pckbc_cons_slotdata;
75 
76 static int pckbc_xt_translation __P((void *, pckbport_slot_t, int));
77 static int pckbc_send_devcmd __P((void *, pckbport_slot_t, u_char));
78 static void pckbc_slot_enable __P((void *, pckbport_slot_t, int));
79 static void pckbc_intr_establish __P((void *, pckbport_slot_t));
80 static void pckbc_set_poll __P((void *,	pckbc_slot_t, int on));
81 
82 static int pckbc_wait_output __P((bus_space_tag_t, bus_space_handle_t));
83 
84 static int pckbc_get8042cmd __P((struct pckbc_internal *));
85 static int pckbc_put8042cmd __P((struct pckbc_internal *));
86 
87 void pckbc_cleanqueue __P((struct pckbc_slotdata *));
88 void pckbc_cleanup __P((void *));
89 int pckbc_cmdresponse __P((struct pckbc_internal *, pckbc_slot_t, u_char));
90 void pckbc_start __P((struct pckbc_internal *, pckbc_slot_t));
91 
92 const char * const pckbc_slot_names[] = { "kbd", "aux" };
93 
94 static struct pckbport_accessops const pckbc_ops = {
95 	pckbc_xt_translation,
96 	pckbc_send_devcmd,
97 	pckbc_poll_data1,
98 	pckbc_slot_enable,
99 	pckbc_intr_establish,
100 	pckbc_set_poll
101 };
102 
103 #define	KBD_DELAY	DELAY(8)
104 
105 static inline int
106 pckbc_wait_output(iot, ioh_c)
107 	bus_space_tag_t iot;
108 	bus_space_handle_t ioh_c;
109 {
110 	u_int i;
111 
112 	for (i = 100000; i; i--)
113 		if (!(bus_space_read_1(iot, ioh_c, 0) & KBS_IBF)) {
114 			KBD_DELAY;
115 			return (1);
116 		}
117 	return (0);
118 }
119 
120 int
121 pckbc_send_cmd(iot, ioh_c, val)
122 	bus_space_tag_t iot;
123 	bus_space_handle_t ioh_c;
124 	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 /*
133  * Note: the spl games here are to deal with some strange PC kbd controllers
134  * in some system configurations.
135  * This is not canonical way to handle polling input.
136  */
137 int
138 pckbc_poll_data1(pt, slot)
139 	void *pt;
140 	pckbc_slot_t slot;
141 {
142 	struct pckbc_internal *t = pt;
143 	struct pckbc_slotdata *q = t->t_slotdata[slot];
144 	int s;
145 	u_char stat, c;
146 	int i = 100000; /* if 1 port read takes 1us (?), this polls for 100ms */
147 	int checkaux = t->t_haveaux;
148 
149 	s = splhigh();
150 
151 	if (q && q->polling && q->poll_data != -1 && q->poll_stat != -1) {
152 		stat	= q->poll_stat;
153 		c	= q->poll_data;
154 		q->poll_data = -1;
155 		q->poll_stat = -1;
156 		goto process;
157 	}
158 
159 	for (; i; i--) {
160 		stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
161 		if (stat & KBS_DIB) {
162 			KBD_DELAY;
163 			c = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
164 
165 		    process:
166 			if (checkaux && (stat & 0x20)) { /* aux data */
167 				if (slot != PCKBC_AUX_SLOT) {
168 #ifdef PCKBCDEBUG
169 					printf("lost aux 0x%x\n", c);
170 #endif
171 					continue;
172 				}
173 			} else {
174 				if (slot == PCKBC_AUX_SLOT) {
175 #ifdef PCKBCDEBUG
176 					printf("lost kbd 0x%x\n", c);
177 #endif
178 					continue;
179 				}
180 			}
181 			splx(s);
182 			return (c);
183 		}
184 	}
185 
186 	splx(s);
187 	return (-1);
188 }
189 
190 /*
191  * Get the current command byte.
192  */
193 static int
194 pckbc_get8042cmd(t)
195 	struct pckbc_internal *t;
196 {
197 	bus_space_tag_t iot = t->t_iot;
198 	bus_space_handle_t ioh_c = t->t_ioh_c;
199 	int data;
200 
201 	if (!pckbc_send_cmd(iot, ioh_c, K_RDCMDBYTE))
202 		return (0);
203 	data = pckbc_poll_data1(t, PCKBC_KBD_SLOT);
204 	if (data == -1)
205 		return (0);
206 	t->t_cmdbyte = data;
207 	return (1);
208 }
209 
210 /*
211  * Pass command byte to keyboard controller (8042).
212  */
213 static int
214 pckbc_put8042cmd(t)
215 	struct pckbc_internal *t;
216 {
217 	bus_space_tag_t iot = t->t_iot;
218 	bus_space_handle_t ioh_d = t->t_ioh_d;
219 	bus_space_handle_t ioh_c = t->t_ioh_c;
220 
221 	if (!pckbc_send_cmd(iot, ioh_c, K_LDCMDBYTE))
222 		return (0);
223 	if (!pckbc_wait_output(iot, ioh_c))
224 		return (0);
225 	bus_space_write_1(iot, ioh_d, 0, t->t_cmdbyte);
226 	return (1);
227 }
228 
229 static int
230 pckbc_send_devcmd(pt, slot, val)
231 	void *pt;
232 	pckbc_slot_t slot;
233 	u_char val;
234 {
235 	struct pckbc_internal *t = pt;
236 	bus_space_tag_t iot = t->t_iot;
237 	bus_space_handle_t ioh_d = t->t_ioh_d;
238 	bus_space_handle_t ioh_c = t->t_ioh_c;
239 
240 	if (slot == PCKBC_AUX_SLOT) {
241 		if (!pckbc_send_cmd(iot, ioh_c, KBC_AUXWRITE))
242 			return (0);
243 	}
244 	if (!pckbc_wait_output(iot, ioh_c))
245 		return (0);
246 	bus_space_write_1(iot, ioh_d, 0, val);
247 	return (1);
248 }
249 
250 int
251 pckbc_is_console(iot, addr)
252 	bus_space_tag_t iot;
253 	bus_addr_t addr;
254 {
255 	if (pckbc_console && !pckbc_console_attached &&
256 	    pckbc_consdata.t_iot == iot &&
257 	    pckbc_consdata.t_addr == addr)
258 		return (1);
259 	return (0);
260 }
261 
262 static int
263 pckbc_attach_slot(sc, slot)
264 	struct pckbc_softc *sc;
265 	pckbc_slot_t slot;
266 {
267 	struct pckbc_internal *t = sc->id;
268 	struct pckbc_attach_args pa;
269 	void *sdata;
270 	struct device *child;
271 	int alloced = 0;
272 
273 	pa.pa_tag = t;
274 	pa.pa_slot = slot;
275 
276 	if (t->t_slotdata[slot] == NULL) {
277 		sdata = malloc(sizeof(struct pckbc_slotdata),
278 		    M_DEVBUF, M_NOWAIT);
279 		if (sdata == NULL) {
280 			printf("%s: no memory\n", sc->sc_dv.dv_xname);
281 			return (0);
282 		}
283 		t->t_slotdata[slot] = sdata;
284 		pckbc_init_slotdata(t->t_slotdata[slot]);
285 		alloced++;
286 	}
287 
288 	child = pckbport_attach_slot(&sc->sc_dv, t->t_pt, slot);
289 
290 	if (child == NULL && alloced) {
291 		free(t->t_slotdata[slot], M_DEVBUF);
292 		t->t_slotdata[slot] = NULL;
293 	}
294 
295 #if NRND > 0
296 	if (child != NULL && t->t_slotdata[slot] != NULL)
297 		rnd_attach_source(&t->t_slotdata[slot]->rnd_source,
298 		    child->dv_xname, RND_TYPE_TTY, 0);
299 #endif
300 	return child != NULL;
301 }
302 
303 void
304 pckbc_attach(sc)
305 	struct pckbc_softc *sc;
306 {
307 	struct pckbc_internal *t;
308 	bus_space_tag_t iot;
309 	bus_space_handle_t ioh_d, ioh_c;
310 	int res;
311 	u_char cmdbits = 0;
312 
313 	t = sc->id;
314 	iot = t->t_iot;
315 	ioh_d = t->t_ioh_d;
316 	ioh_c = t->t_ioh_c;
317 
318 	t->t_pt = pckbport_attach(t, &pckbc_ops);
319 	if (t->t_pt == NULL) {
320 		aprint_error(": attach failed\n");
321 		return;
322 	}
323 
324 	/* flush */
325 	(void) pckbc_poll_data1(t, PCKBC_KBD_SLOT);
326 
327 	/* set initial cmd byte */
328 	if (!pckbc_put8042cmd(t)) {
329 		printf("kbc: cmd word write error\n");
330 		return;
331 	}
332 
333 /*
334  * XXX Don't check the keyboard port. There are broken keyboard controllers
335  * which don't pass the test but work normally otherwise.
336  */
337 #if 0
338 	/*
339 	 * check kbd port ok
340 	 */
341 	if (!pckbc_send_cmd(iot, ioh_c, KBC_KBDTEST))
342 		return;
343 	res = pckbc_poll_data1(t, PCKBC_KBD_SLOT, 0);
344 
345 	/*
346 	 * Normally, we should get a "0" here.
347 	 * But there are keyboard controllers behaving differently.
348 	 */
349 	if (res == 0 || res == 0xfa || res == 0x01 || res == 0xab) {
350 #ifdef PCKBCDEBUG
351 		if (res != 0)
352 			printf("kbc: returned %x on kbd slot test\n", res);
353 #endif
354 		if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
355 			cmdbits |= KC8_KENABLE;
356 	} else {
357 		printf("kbc: kbd port test: %x\n", res);
358 		return;
359 	}
360 #else
361 	if (pckbc_attach_slot(sc, PCKBC_KBD_SLOT))
362 		cmdbits |= KC8_KENABLE;
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 	t->t_haveaux = 1;
379 	bus_space_write_1(iot, ioh_d, 0, 0x5a); /* a random value */
380 	res = pckbc_poll_data1(t, PCKBC_AUX_SLOT);
381 	if (res != -1) {
382 		/*
383 		 * In most cases, the 0x5a gets echoed.
384 		 * Some older controllers (Gateway 2000 circa 1993)
385 		 * return 0xfe here.
386 		 * We are satisfied if there is anything in the
387 		 * aux output buffer.
388 		 */
389 		if (pckbc_attach_slot(sc, PCKBC_AUX_SLOT))
390 			cmdbits |= KC8_MENABLE;
391 	} else {
392 #ifdef PCKBCDEBUG
393 		printf("kbc: aux echo test failed\n");
394 #endif
395 		t->t_haveaux = 0;
396 	}
397 
398 nomouse:
399 	/* enable needed interrupts */
400 	t->t_cmdbyte |= cmdbits;
401 	if (!pckbc_put8042cmd(t))
402 		printf("kbc: cmd word write error\n");
403 }
404 
405 static void
406 pckbc_init_slotdata(q)
407 	struct pckbc_slotdata *q;
408 {
409 
410 	q->polling = 0;
411 }
412 
413 /*
414  * switch scancode translation on / off
415  * return nonzero on success
416  */
417 static int
418 pckbc_xt_translation(self, slot, on)
419 	void *self;
420 	pckbc_slot_t slot;
421 	int on;
422 {
423 	struct pckbc_internal *t = self;
424 	int ison;
425 
426 	if (slot != PCKBC_KBD_SLOT) {
427 		/* translation only for kbd slot */
428 		if (on)
429 			return (0);
430 		else
431 			return (1);
432 	}
433 
434 	ison = t->t_cmdbyte & KC8_TRANS;
435 	if ((on && ison) || (!on && !ison))
436 		return (1);
437 
438 	t->t_cmdbyte ^= KC8_TRANS;
439 	if (!pckbc_put8042cmd(t))
440 		return (0);
441 
442 	/* read back to be sure */
443 	if (!pckbc_get8042cmd(t))
444 		return (0);
445 
446 	ison = t->t_cmdbyte & KC8_TRANS;
447 	if ((on && ison) || (!on && !ison))
448 		return (1);
449 	return (0);
450 }
451 
452 static const struct pckbc_portcmd {
453 	u_char cmd_en, cmd_dis;
454 } pckbc_portcmd[2] = {
455 	{
456 		KBC_KBDENABLE, KBC_KBDDISABLE,
457 	}, {
458 		KBC_AUXENABLE, KBC_AUXDISABLE,
459 	}
460 };
461 
462 void
463 pckbc_slot_enable(self, slot, on)
464 	void *self;
465 	pckbc_slot_t slot;
466 	int on;
467 {
468 	struct pckbc_internal *t = (struct pckbc_internal *)self;
469 	const struct pckbc_portcmd *cmd;
470 
471 	cmd = &pckbc_portcmd[slot];
472 
473 	if (!pckbc_send_cmd(t->t_iot, t->t_ioh_c,
474 			    on ? cmd->cmd_en : cmd->cmd_dis))
475 		printf("pckbc_slot_enable(%d) failed\n", on);
476 }
477 
478 static void
479 pckbc_set_poll(self, slot, on)
480 	void *self;
481 	pckbc_slot_t slot;
482 	int on;
483 {
484 	struct pckbc_internal *t = (struct pckbc_internal *)self;
485 
486 	t->t_slotdata[slot]->polling = on;
487 
488 	if (on) {
489 		t->t_slotdata[slot]->poll_data = -1;
490 		t->t_slotdata[slot]->poll_stat = -1;
491 	} else {
492                 int s;
493 
494                 /*
495                  * If disabling polling on a device that's been configured,
496                  * make sure there are no bytes left in the FIFO, holding up
497                  * the interrupt line.  Otherwise we won't get any further
498                  * interrupts.
499                  */
500 		if (t->t_sc) {
501 			s = spltty();
502 			pckbcintr(t->t_sc);
503 			splx(s);
504 		}
505 	}
506 }
507 
508 static void
509 pckbc_intr_establish(pt, slot)
510 	void *pt;
511 	pckbport_slot_t slot;
512 {
513 	struct pckbc_internal *t = pt;
514 
515 	(*t->t_sc->intr_establish)(t->t_sc, slot);
516 }
517 
518 int
519 pckbcintr_hard(vsc)
520 	void *vsc;
521 {
522 	struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
523 	struct pckbc_internal *t = sc->id;
524 	u_char stat;
525 	pckbc_slot_t slot;
526 	struct pckbc_slotdata *q;
527 	int served = 0, data, next, s;
528 
529 	for(;;) {
530 		stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
531 		if (!(stat & KBS_DIB))
532 			break;
533 
534 		served = 1;
535 
536 		slot = (t->t_haveaux && (stat & 0x20)) ?
537 		    PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
538 		q = t->t_slotdata[slot];
539 
540 		if (!q) {
541 			/* XXX do something for live insertion? */
542 			printf("pckbcintr: no dev for slot %d\n", slot);
543 			KBD_DELAY;
544 			(void) bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
545 			continue;
546 		}
547 
548 		KBD_DELAY;
549 		data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
550 
551 #if NRND > 0
552 		rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
553 #endif
554 
555 		if (q->polling) {
556 			q->poll_data = data;
557 			q->poll_stat = stat;
558 			break; /* pckbc_poll_data() will get it */
559 		}
560 
561 #if 0 /* XXXBJH */
562 		if (CMD_IN_QUEUE(q) && pckbc_cmdresponse(t, slot, data))
563 			continue;
564 #endif
565 
566 		s = splhigh();
567 		next = (t->rbuf_write+1) % PCKBC_RBUF_SIZE;
568 		if (next == t->rbuf_read) {
569 			splx(s);
570 			break;
571 		}
572 		t->rbuf[t->rbuf_write].data = data;
573 		t->rbuf[t->rbuf_write].slot = slot;
574 		t->rbuf_write = next;
575 		splx(s);
576 	}
577 
578 	return (served);
579 }
580 
581 void
582 pckbcintr_soft(vsc)
583 	void *vsc;
584 {
585 	struct pckbc_softc *sc = vsc;
586 	struct pckbc_internal *t = sc->id;
587 	int data, slot, s;
588 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
589 	int st;
590 
591 	st = spltty();
592 #endif
593 
594 	s = splhigh();
595 	while (t->rbuf_read != t->rbuf_write) {
596 		slot = t->rbuf[t->rbuf_read].slot;
597 		data = t->rbuf[t->rbuf_read].data;
598 		t->rbuf_read = (t->rbuf_read+1) % PCKBC_RBUF_SIZE;
599 		splx(s);
600 		pckbportintr(t->t_pt, slot, data);
601 		s = splhigh();
602 	}
603 	splx(s);
604 
605 
606 #ifndef __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS
607 	splx(st);
608 #endif
609 }
610 
611 int
612 pckbcintr(vsc)
613 	void *vsc;
614 {
615 	struct pckbc_softc *sc = (struct pckbc_softc *)vsc;
616 	struct pckbc_internal *t = sc->id;
617 	u_char stat;
618 	pckbc_slot_t slot;
619 	struct pckbc_slotdata *q;
620 	int served = 0, data;
621 
622 	for(;;) {
623 		stat = bus_space_read_1(t->t_iot, t->t_ioh_c, 0);
624 		if (!(stat & KBS_DIB))
625 			break;
626 
627 		served = 1;
628 
629 		slot = (t->t_haveaux && (stat & 0x20)) ?
630 		    PCKBC_AUX_SLOT : PCKBC_KBD_SLOT;
631 		q = t->t_slotdata[slot];
632 
633 		KBD_DELAY;
634 		data = bus_space_read_1(t->t_iot, t->t_ioh_d, 0);
635 
636 #if NRND > 0
637 		rnd_add_uint32(&q->rnd_source, (stat<<8)|data);
638 #endif
639 
640 		pckbportintr(t->t_pt, slot, data);
641 	}
642 
643 	return (served);
644 }
645 
646 int
647 pckbc_cnattach(iot, addr, cmd_offset, slot)
648 	bus_space_tag_t iot;
649 	bus_addr_t addr;
650 	bus_size_t cmd_offset;
651 	pckbc_slot_t slot;
652 {
653 	bus_space_handle_t ioh_d, ioh_c;
654 #ifdef PCKBC_CNATTACH_SELFTEST
655 	int reply;
656 #endif
657 	int res = 0;
658 
659 	if (bus_space_map(iot, addr + KBDATAP, 1, 0, &ioh_d))
660                 return (ENXIO);
661 	if (bus_space_map(iot, addr + cmd_offset, 1, 0, &ioh_c)) {
662 		bus_space_unmap(iot, ioh_d, 1);
663                 return (ENXIO);
664 	}
665 
666 	memset(&pckbc_consdata, 0, sizeof(pckbc_consdata));
667 	pckbc_consdata.t_iot = iot;
668 	pckbc_consdata.t_ioh_d = ioh_d;
669 	pckbc_consdata.t_ioh_c = ioh_c;
670 	pckbc_consdata.t_addr = addr;
671 	callout_init(&pckbc_consdata.t_cleanup);
672 
673 	/* flush */
674 	(void) pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
675 
676 #ifdef PCKBC_CNATTACH_SELFTEST
677 	/*
678 	 * In some machines (e.g. netwinder) pckbc refuses to talk at
679 	 * all until we request a self-test.
680 	 */
681 	if (!pckbc_send_cmd(iot, ioh_c, KBC_SELFTEST)) {
682 		printf("kbc: unable to request selftest\n");
683 		res = EIO;
684 		goto out;
685 	}
686 
687 	reply = pckbc_poll_data1(&pckbc_consdata, PCKBC_KBD_SLOT);
688 	if (reply != 0x55) {
689 		printf("kbc: selftest returned 0x%02x\n", reply);
690 		res = EIO;
691 		goto out;
692 	}
693 #endif /* PCKBC_CNATTACH_SELFTEST */
694 
695 	/* init cmd byte, enable ports */
696 	pckbc_consdata.t_cmdbyte = KC8_CPU;
697 	if (!pckbc_put8042cmd(&pckbc_consdata)) {
698 		printf("kbc: cmd word write error\n");
699 		res = EIO;
700 		goto out;
701 	}
702 
703 	res = pckbport_cnattach(&pckbc_consdata, &pckbc_ops, slot);
704 
705   out:
706 	if (res) {
707 		bus_space_unmap(iot, pckbc_consdata.t_ioh_d, 1);
708 		bus_space_unmap(iot, pckbc_consdata.t_ioh_c, 1);
709 	} else {
710 		pckbc_consdata.t_slotdata[slot] = &pckbc_cons_slotdata;
711 		pckbc_init_slotdata(&pckbc_cons_slotdata);
712 		pckbc_console = 1;
713 	}
714 
715 	return (res);
716 }
717