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