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