xref: /openbsd/sys/dev/pckbc/pckbd.c (revision 78b63d65)
1 /* $OpenBSD: pckbd.c,v 1.2 2001/02/02 20:19:04 aaron Exp $ */
2 /* $NetBSD: pckbd.c,v 1.24 2000/06/05 22:20:57 sommerfeld Exp $ */
3 
4 /*-
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Charles M. Hannum.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *        This product includes software developed by the NetBSD
22  *        Foundation, Inc. and its contributors.
23  * 4. Neither the name of The NetBSD Foundation nor the names of its
24  *    contributors may be used to endorse or promote products derived
25  *    from this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37  * POSSIBILITY OF SUCH DAMAGE.
38  */
39 
40 /*-
41  * Copyright (c) 1990 The Regents of the University of California.
42  * All rights reserved.
43  *
44  * This code is derived from software contributed to Berkeley by
45  * William Jolitz and Don Ahn.
46  *
47  * Redistribution and use in source and binary forms, with or without
48  * modification, are permitted provided that the following conditions
49  * are met:
50  * 1. Redistributions of source code must retain the above copyright
51  *    notice, this list of conditions and the following disclaimer.
52  * 2. Redistributions in binary form must reproduce the above copyright
53  *    notice, this list of conditions and the following disclaimer in the
54  *    documentation and/or other materials provided with the distribution.
55  * 3. All advertising materials mentioning features or use of this software
56  *    must display the following acknowledgement:
57  *	This product includes software developed by the University of
58  *	California, Berkeley and its contributors.
59  * 4. Neither the name of the University nor the names of its contributors
60  *    may be used to endorse or promote products derived from this software
61  *    without specific prior written permission.
62  *
63  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
64  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
65  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
66  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
67  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
68  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
69  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
70  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
71  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
72  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
73  * SUCH DAMAGE.
74  *
75  *	@(#)pccons.c	5.11 (Berkeley) 5/21/91
76  */
77 
78 /*
79  * code to work keyboard for PC-style console
80  */
81 
82 #include <sys/param.h>
83 #include <sys/systm.h>
84 #include <sys/device.h>
85 #include <sys/malloc.h>
86 #include <sys/ioctl.h>
87 
88 #include <machine/bus.h>
89 
90 #include <dev/isa/isavar.h>		/* XXX XXX XXX */
91 
92 #include <dev/ic/pckbcvar.h>
93 
94 #include <dev/pckbc/pckbdreg.h>
95 #include <dev/pckbc/pckbdvar.h>
96 #include <dev/pckbc/wskbdmap_mfii.h>
97 
98 #include <dev/wscons/wsconsio.h>
99 #include <dev/wscons/wskbdvar.h>
100 #include <dev/wscons/wsksymdef.h>
101 #include <dev/wscons/wsksymvar.h>
102 
103 #if defined(__i386__) || defined(__alpha__)
104 #include <sys/kernel.h> /* XXX for hz */
105 #endif
106 
107 struct pckbd_internal {
108 	int t_isconsole;
109 	pckbc_tag_t t_kbctag;
110 	pckbc_slot_t t_kbcslot;
111 
112 	int t_lastchar;
113 	int t_extended;
114 	int t_extended1;
115 
116 	struct pckbd_softc *t_sc; /* back pointer */
117 };
118 
119 struct pckbd_softc {
120         struct  device sc_dev;
121 
122 	struct pckbd_internal *id;
123 	int sc_enabled;
124 
125 	int sc_ledstate;
126 
127 	struct device *sc_wskbddev;
128 #ifdef WSDISPLAY_COMPAT_RAWKBD
129 	int rawkbd;
130 #endif
131 };
132 
133 static int pckbd_is_console __P((pckbc_tag_t, pckbc_slot_t));
134 
135 int pckbdprobe __P((struct device *, void *, void *));
136 void pckbdattach __P((struct device *, struct device *, void *));
137 
138 struct cfattach pckbd_ca = {
139 	sizeof(struct pckbd_softc), pckbdprobe, pckbdattach,
140 };
141 
142 int	pckbd_enable __P((void *, int));
143 void	pckbd_set_leds __P((void *, int));
144 int	pckbd_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
145 
146 const struct wskbd_accessops pckbd_accessops = {
147 	pckbd_enable,
148 	pckbd_set_leds,
149 	pckbd_ioctl,
150 };
151 
152 void	pckbd_cngetc __P((void *, u_int *, int *));
153 void	pckbd_cnpollc __P((void *, int));
154 void	pckbd_cnbell __P((void *, u_int, u_int, u_int));
155 
156 const struct wskbd_consops pckbd_consops = {
157 	pckbd_cngetc,
158 	pckbd_cnpollc,
159 	pckbd_cnbell,
160 };
161 
162 const struct wskbd_mapdata pckbd_keymapdata = {
163 	pckbd_keydesctab,
164 #ifdef PCKBD_LAYOUT
165 	PCKBD_LAYOUT,
166 #else
167 	KB_US,
168 #endif
169 };
170 
171 /*
172  * Hackish support for a bell on the PC Keyboard; when a suitable feeper
173  * is found, it attaches itself into the pckbd driver here.
174  */
175 void	(*pckbd_bell_fn) __P((void *, u_int, u_int, u_int, int));
176 void	*pckbd_bell_fn_arg;
177 
178 void	pckbd_bell __P((u_int, u_int, u_int, int));
179 
180 int	pckbd_set_xtscancode __P((pckbc_tag_t, pckbc_slot_t));
181 int	pckbd_init __P((struct pckbd_internal *, pckbc_tag_t, pckbc_slot_t,
182 			int));
183 void	pckbd_input __P((void *, int));
184 
185 static int	pckbd_decode __P((struct pckbd_internal *, int,
186 				  u_int *, int *));
187 static int	pckbd_led_encode __P((int));
188 static int	pckbd_led_decode __P((int));
189 
190 struct pckbd_internal pckbd_consdata;
191 
192 int
193 pckbd_set_xtscancode(kbctag, kbcslot)
194 	pckbc_tag_t kbctag;
195 	pckbc_slot_t kbcslot;
196 {
197 	u_char cmd[2];
198 	int res;
199 
200 	/*
201 	 * Some keyboard/8042 combinations do not seem to work if the keyboard
202 	 * is set to table 1; in fact, it would appear that some keyboards just
203 	 * ignore the command altogether.  So by default, we use the AT scan
204 	 * codes and have the 8042 translate them.  Unfortunately, this is
205 	 * known to not work on some PS/2 machines.  We try desparately to deal
206 	 * with this by checking the (lack of a) translate bit in the 8042 and
207 	 * attempting to set the keyboard to XT mode.  If this all fails, well,
208 	 * tough luck.
209 	 *
210 	 * XXX It would perhaps be a better choice to just use AT scan codes
211 	 * and not bother with this.
212 	 */
213 	if (pckbc_xt_translation(kbctag, kbcslot, 1)) {
214 		/* The 8042 is translating for us; use AT codes. */
215 		cmd[0] = KBC_SETTABLE;
216 		cmd[1] = 2;
217 		res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
218 		if (res) {
219 			u_char cmd[1];
220 #ifdef DEBUG
221 			printf("pckbd: error setting scanset 2\n");
222 #endif
223 			/*
224 			 * XXX at least one keyboard is reported to lock up
225 			 * if a "set table" is attempted, thus the "reset".
226 			 * XXX ignore errors, scanset 2 should be
227 			 * default anyway.
228 			 */
229 			cmd[0] = KBC_RESET;
230 			(void)pckbc_poll_cmd(kbctag, kbcslot, cmd, 1, 1, 0, 1);
231 			pckbc_flush(kbctag, kbcslot);
232 			res = 0;
233 		}
234 	} else {
235 		/* Stupid 8042; set keyboard to XT codes. */
236 		cmd[0] = KBC_SETTABLE;
237 		cmd[1] = 1;
238 		res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 2, 0, 0, 0);
239 #ifdef DEBUG
240 		if (res)
241 			printf("pckbd: error setting scanset 1\n");
242 #endif
243 	}
244 	return (res);
245 }
246 
247 static int
248 pckbd_is_console(tag, slot)
249 	pckbc_tag_t tag;
250 	pckbc_slot_t slot;
251 {
252 	return (pckbd_consdata.t_isconsole &&
253 		(tag == pckbd_consdata.t_kbctag) &&
254 		(slot == pckbd_consdata.t_kbcslot));
255 }
256 
257 /*
258  * these are both bad jokes
259  */
260 int
261 pckbdprobe(parent, match, aux)
262 	struct device *parent;
263 	void *match;
264 	void *aux;
265 {
266 	struct cfdata *cf = match;
267 	struct pckbc_attach_args *pa = aux;
268 	u_char cmd[1], resp[1];
269 	int res;
270 
271 	/*
272 	 * XXX There are rumours that a keyboard can be connected
273 	 * to the aux port as well. For me, this didn't work.
274 	 * For further experiments, allow it if explicitly
275 	 * wired in the config file.
276 	 */
277 	if ((pa->pa_slot != PCKBC_KBD_SLOT) &&
278 	    (cf->cf_loc[PCKBCCF_SLOT] == PCKBCCF_SLOT_DEFAULT))
279 		return (0);
280 
281 	/* Flush any garbage. */
282 	pckbc_flush(pa->pa_tag, pa->pa_slot);
283 
284 	/* Reset the keyboard. */
285 	cmd[0] = KBC_RESET;
286 	res = pckbc_poll_cmd(pa->pa_tag, pa->pa_slot, cmd, 1, 1, resp, 1);
287 	if (res) {
288 #ifdef DEBUG
289 		printf("pckbdprobe: reset error %d\n", res);
290 #endif
291 		/*
292 		 * There is probably no keyboard connected.
293 		 * Let the probe succeed if the keyboard is used
294 		 * as console input - it can be connected later.
295 		 */
296 		return (pckbd_is_console(pa->pa_tag, pa->pa_slot) ? 1 : 0);
297 	}
298 	if (resp[0] != KBR_RSTDONE) {
299 		printf("pckbdprobe: reset response 0x%x\n", resp[0]);
300 		return (0);
301 	}
302 
303 	/*
304 	 * Some keyboards seem to leave a second ack byte after the reset.
305 	 * This is kind of stupid, but we account for them anyway by just
306 	 * flushing the buffer.
307 	 */
308 	pckbc_flush(pa->pa_tag, pa->pa_slot);
309 
310 	if (pckbd_set_xtscancode(pa->pa_tag, pa->pa_slot))
311 		return (0);
312 
313 	return (2);
314 }
315 
316 void
317 pckbdattach(parent, self, aux)
318 	struct device *parent, *self;
319 	void *aux;
320 {
321 	struct pckbd_softc *sc = (void *)self;
322 	struct pckbc_attach_args *pa = aux;
323 	int isconsole;
324 	struct wskbddev_attach_args a;
325 
326 	printf("\n");
327 
328 	isconsole = pckbd_is_console(pa->pa_tag, pa->pa_slot);
329 
330 	if (isconsole) {
331 		sc->id = &pckbd_consdata;
332 		sc->sc_enabled = 1;
333 	} else {
334 		u_char cmd[1];
335 
336 		sc->id = malloc(sizeof(struct pckbd_internal),
337 				M_DEVBUF, M_WAITOK);
338 		(void) pckbd_init(sc->id, pa->pa_tag, pa->pa_slot, 0);
339 
340 		/* no interrupts until enabled */
341 		cmd[0] = KBC_DISABLE;
342 		(void) pckbc_poll_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
343 				      cmd, 1, 0, 0, 0);
344 		sc->sc_enabled = 0;
345 	}
346 
347 	sc->id->t_sc = sc;
348 
349 	pckbc_set_inputhandler(sc->id->t_kbctag, sc->id->t_kbcslot,
350 			       pckbd_input, sc, sc->sc_dev.dv_xname);
351 
352 	a.console = isconsole;
353 
354 	a.keymap = &pckbd_keymapdata;
355 
356 	a.accessops = &pckbd_accessops;
357 	a.accesscookie = sc;
358 
359 	/*
360 	 * Attach the wskbd, saving a handle to it.
361 	 * XXX XXX XXX
362 	 */
363 	sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
364 }
365 
366 int
367 pckbd_enable(v, on)
368 	void *v;
369 	int on;
370 {
371 	struct pckbd_softc *sc = v;
372 	u_char cmd[1];
373 	int res;
374 
375 	if (on) {
376 		if (sc->sc_enabled)
377 			return (EBUSY);
378 
379 		pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 1);
380 
381 		cmd[0] = KBC_ENABLE;
382 		res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
383 					cmd, 1, 0, 1, 0);
384 		if (res) {
385 			printf("pckbd_enable: command error\n");
386 			return (res);
387 		}
388 
389 		res = pckbd_set_xtscancode(sc->id->t_kbctag,
390 					   sc->id->t_kbcslot);
391 		if (res)
392 			return (res);
393 
394 		sc->sc_enabled = 1;
395 	} else {
396 		if (sc->id->t_isconsole)
397 			return (EBUSY);
398 
399 		cmd[0] = KBC_DISABLE;
400 		res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
401 					cmd, 1, 0, 1, 0);
402 		if (res) {
403 			printf("pckbd_disable: command error\n");
404 			return (res);
405 		}
406 
407 		pckbc_slot_enable(sc->id->t_kbctag, sc->id->t_kbcslot, 0);
408 
409 		sc->sc_enabled = 0;
410 	}
411 
412 	return (0);
413 }
414 
415 static int
416 pckbd_decode(id, datain, type, dataout)
417 	struct pckbd_internal *id;
418 	int datain;
419 	u_int *type;
420 	int *dataout;
421 {
422 	int key;
423 
424 	if (datain == KBR_EXTENDED0) {
425 		id->t_extended = 1;
426 		return(0);
427 	} else if (datain == KBR_EXTENDED1) {
428 		id->t_extended1 = 2;
429 		return(0);
430 	}
431 
432  	/* map extended keys to (unused) codes 128-254 */
433 	key = (datain & 0x7f) | (id->t_extended ? 0x80 : 0);
434 	id->t_extended = 0;
435 
436 	/*
437 	 * process BREAK key (EXT1 1D 45  EXT1 9D C5):
438 	 * map to (unused) code 7F
439 	 */
440 	if (id->t_extended1 == 2 && (datain == 0x1d || datain == 0x9d)) {
441 		id->t_extended1 = 1;
442 		return(0);
443 	} else if (id->t_extended1 == 1 &&
444 		   (datain == 0x45 || datain == 0xc5)) {
445 		id->t_extended1 = 0;
446 		key = 0x7f;
447 	} else if (id->t_extended1 > 0) {
448 		id->t_extended1 = 0;
449 	}
450 
451 	if (datain & 0x80) {
452 		id->t_lastchar = 0;
453 		*type = WSCONS_EVENT_KEY_UP;
454 	} else {
455 		/* Always ignore typematic keys */
456 		if (key == id->t_lastchar)
457 			return(0);
458 		id->t_lastchar = key;
459 		*type = WSCONS_EVENT_KEY_DOWN;
460 	}
461 
462 	*dataout = key;
463 	return(1);
464 }
465 
466 int
467 pckbd_init(t, kbctag, kbcslot, console)
468 	struct pckbd_internal *t;
469 	pckbc_tag_t kbctag;
470 	pckbc_slot_t kbcslot;
471 	int console;
472 {
473 	bzero(t, sizeof(struct pckbd_internal));
474 
475 	t->t_isconsole = console;
476 	t->t_kbctag = kbctag;
477 	t->t_kbcslot = kbcslot;
478 
479 	return (pckbd_set_xtscancode(kbctag, kbcslot));
480 }
481 
482 static int
483 pckbd_led_encode(led)
484 	int led;
485 {
486 	int res;
487 
488 	res = 0;
489 
490 	if (led & WSKBD_LED_SCROLL)
491 		res |= 0x01;
492 	if (led & WSKBD_LED_NUM)
493 		res |= 0x02;
494 	if (led & WSKBD_LED_CAPS)
495 		res |= 0x04;
496 	return(res);
497 }
498 
499 static int
500 pckbd_led_decode(led)
501 	int led;
502 {
503 	int res;
504 
505 	res = 0;
506 	if (led & 0x01)
507 		res |= WSKBD_LED_SCROLL;
508 	if (led & 0x02)
509 		res |= WSKBD_LED_NUM;
510 	if (led & 0x04)
511 		res |= WSKBD_LED_CAPS;
512 	return(res);
513 }
514 
515 void
516 pckbd_set_leds(v, leds)
517 	void *v;
518 	int leds;
519 {
520 	struct pckbd_softc *sc = v;
521 	u_char cmd[2];
522 
523 	cmd[0] = KBC_MODEIND;
524 	cmd[1] = pckbd_led_encode(leds);
525 	sc->sc_ledstate = cmd[1];
526 
527 	(void) pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
528 				 cmd, 2, 0, 0, 0);
529 }
530 
531 /*
532  * Got a console receive interrupt -
533  * the console processor wants to give us a character.
534  */
535 void
536 pckbd_input(vsc, data)
537 	void *vsc;
538 	int data;
539 {
540 	struct pckbd_softc *sc = vsc;
541 	int type, key;
542 
543 #ifdef WSDISPLAY_COMPAT_RAWKBD
544 	if (sc->rawkbd) {
545 		char d = data;
546 		wskbd_rawinput(sc->sc_wskbddev, &d, 1);
547 		return;
548 	}
549 #endif
550 	if (pckbd_decode(sc->id, data, &type, &key))
551 		wskbd_input(sc->sc_wskbddev, type, key);
552 }
553 
554 int
555 pckbd_ioctl(v, cmd, data, flag, p)
556 	void *v;
557 	u_long cmd;
558 	caddr_t data;
559 	int flag;
560 	struct proc *p;
561 {
562 	struct pckbd_softc *sc = v;
563 
564 	switch (cmd) {
565 	    case WSKBDIO_GTYPE:
566 		*(int *)data = WSKBD_TYPE_PC_XT;
567 		return 0;
568 	    case WSKBDIO_SETLEDS: {
569 		char cmd[2];
570 		int res;
571 		cmd[0] = KBC_MODEIND;
572 		cmd[1] = pckbd_led_encode(*(int *)data);
573 		sc->sc_ledstate = cmd[1];
574 		res = pckbc_enqueue_cmd(sc->id->t_kbctag, sc->id->t_kbcslot,
575 					cmd, 2, 0, 1, 0);
576 		return (res);
577 		}
578 	    case WSKBDIO_GETLEDS:
579 		*(int *)data = pckbd_led_decode(sc->sc_ledstate);
580 		return (0);
581 	    case WSKBDIO_COMPLEXBELL:
582 #define d ((struct wskbd_bell_data *)data)
583 		/*
584 		 * Keyboard can't beep directly; we have an
585 		 * externally-provided global hook to do this.
586 		 */
587 		pckbd_bell(d->pitch, d->period, d->volume, 0);
588 #undef d
589 		return (0);
590 #ifdef WSDISPLAY_COMPAT_RAWKBD
591 	    case WSKBDIO_SETMODE:
592 		sc->rawkbd = (*(int *)data == WSKBD_RAW);
593 		return (0);
594 #endif
595 	}
596 	return -1;
597 }
598 
599 void
600 pckbd_bell(pitch, period, volume, poll)
601 	u_int pitch, period, volume;
602 	int poll;
603 {
604 
605 	if (pckbd_bell_fn != NULL)
606 		(*pckbd_bell_fn)(pckbd_bell_fn_arg, pitch, period,
607 		    volume, poll);
608 }
609 
610 void
611 pckbd_hookup_bell(fn, arg)
612 	void (*fn) __P((void *, u_int, u_int, u_int, int));
613 	void *arg;
614 {
615 
616 	if (pckbd_bell_fn == NULL) {
617 		pckbd_bell_fn = fn;
618 		pckbd_bell_fn_arg = arg;
619 	}
620 }
621 
622 int
623 pckbd_cnattach(kbctag, kbcslot)
624 	pckbc_tag_t kbctag;
625 	int kbcslot;
626 {
627 	char cmd[1];
628 	int res;
629 
630 	res = pckbd_init(&pckbd_consdata, kbctag, kbcslot, 1);
631 #if 0 /* we allow the console to be attached if no keyboard is present */
632 	if (res)
633 		return (res);
634 #endif
635 
636 	/* Just to be sure. */
637 	cmd[0] = KBC_ENABLE;
638 	res = pckbc_poll_cmd(kbctag, kbcslot, cmd, 1, 0, 0, 0);
639 #if 0
640 	if (res)
641 		return (res);
642 #endif
643 
644 	wskbd_cnattach(&pckbd_consops, &pckbd_consdata, &pckbd_keymapdata);
645 
646 	return (0);
647 }
648 
649 /* ARGSUSED */
650 void
651 pckbd_cngetc(v, type, data)
652 	void *v;
653 	u_int *type;
654 	int *data;
655 {
656         struct pckbd_internal *t = v;
657 	int val;
658 
659 	for (;;) {
660 		val = pckbc_poll_data(t->t_kbctag, t->t_kbcslot);
661 		if ((val != -1) && pckbd_decode(t, val, type, data))
662 			return;
663 	}
664 }
665 
666 void
667 pckbd_cnpollc(v, on)
668 	void *v;
669         int on;
670 {
671 	struct pckbd_internal *t = v;
672 
673 	pckbc_set_poll(t->t_kbctag, t->t_kbcslot, on);
674 }
675 
676 void
677 pckbd_cnbell(v, pitch, period, volume)
678 	void *v;
679 	u_int pitch, period, volume;
680 {
681 
682 	pckbd_bell(pitch, period, volume, 1);
683 }
684 
685 struct cfdriver pckbd_cd = {
686 	NULL, "pckbd", DV_DULL
687 };
688