1 /* $NetBSD: ukbd.c,v 1.104 2009/07/11 18:26:58 jakllsch Exp $ */
4 * Copyright (c) 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Lennart Augustsson (lennart@augustsson.net) at
9 * Carlstedt Research & Technology.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
34 * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.104 2009/07/11 18:26:58 jakllsch Exp $");
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/callout.h>
43 #include <sys/kernel.h>
44 #include <sys/device.h>
45 #include <sys/ioctl.h>
47 #include <sys/select.h>
49 #include <sys/vnode.h>
52 #include <dev/usb/usb.h>
53 #include <dev/usb/usbhid.h>
55 #include <dev/usb/usbdi.h>
56 #include <dev/usb/usbdi_util.h>
57 #include <dev/usb/usbdevs.h>
58 #include <dev/usb/usb_quirks.h>
59 #include <dev/usb/uhidev.h>
60 #include <dev/usb/hid.h>
61 #include <dev/usb/ukbdvar.h>
63 #include <dev/wscons/wsconsio.h>
64 #include <dev/wscons/wskbdvar.h>
65 #include <dev/wscons/wsksymdef.h>
66 #include <dev/wscons/wsksymvar.h>
68 #include "opt_ukbd_layout.h"
69 #include "opt_wsdisplay_compat.h"
73 #define DPRINTF(x) if (ukbddebug) logprintf x
74 #define DPRINTFN(n,x) if (ukbddebug>(n)) logprintf x
82 #define MAXMOD 8 /* max 32 */
86 u_int8_t keycode
[MAXKEYCODE
];
91 #define CODEMASK 0x0ff
93 #if defined(__NetBSD__) && defined(WSDISPLAY_COMPAT_RAWKBD)
94 #define NN 0 /* no translation */
96 * Translate USB keycodes to US keyboard XT scancodes.
97 * Scancodes >= 0x80 represent EXTENDED keycodes.
99 * See http://www.microsoft.com/whdc/archive/scancode.mspx
101 * Note: a real pckbd(4) has more complexity in it's
102 * protocol for some keys than this translation implements.
104 Static
const u_int8_t ukbd_trtab
[256] = {
105 NN
, NN
, NN
, NN
, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */
106 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */
107 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */
108 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */
109 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */
110 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */
111 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */
112 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */
113 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xb7, 0x46, /* 40 - 47 */
114 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */
115 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */
116 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */
117 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, NN
, 0x59, /* 60 - 67 */
118 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, NN
, /* 68 - 6f */
119 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* 70 - 77 */
120 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* 78 - 7f */
121 NN
, NN
, NN
, NN
, NN
, 0x7e, NN
, 0x73, /* 80 - 87 */
122 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN
, NN
, NN
, /* 88 - 8f */
123 NN
, NN
, 0x78, 0x77, 0x76, NN
, NN
, NN
, /* 90 - 97 */
124 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* 98 - 9f */
125 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* a0 - a7 */
126 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* a8 - af */
127 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* b0 - b7 */
128 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* b8 - bf */
129 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* c0 - c7 */
130 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* c8 - cf */
131 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* d0 - d7 */
132 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* d8 - df */
133 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* e0 - e7 */
134 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* e8 - ef */
135 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* f0 - f7 */
136 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* f8 - ff */
138 #endif /* defined(__NetBSD__) && defined(WSDISPLAY_COMPAT_RAWKBD) */
140 #define KEY_ERROR 0x01
142 #define MAXKEYS (MAXMOD+2*MAXKEYCODE)
145 struct uhidev sc_hdev
;
147 struct ukbd_data sc_ndata
;
148 struct ukbd_data sc_odata
;
149 struct hid_location sc_modloc
[MAXMOD
];
156 struct hid_location sc_keycodeloc
;
161 int sc_console_keyboard
; /* we are the console keyboard */
163 char sc_debounce
; /* for quirk handling */
164 usb_callout_t sc_delay
; /* for quirk handling */
165 struct ukbd_data sc_data
; /* for quirk handling */
167 struct hid_location sc_numloc
;
168 struct hid_location sc_capsloc
;
169 struct hid_location sc_scroloc
;
171 #if defined(__NetBSD__)
172 device_t sc_wskbddev
;
174 #if defined(WSDISPLAY_COMPAT_RAWKBD)
176 #if defined(UKBD_REPEAT)
177 usb_callout_t sc_rawrepeat_ch
;
178 #define REP_DELAY1 400
179 #define REP_DELAYN 100
181 char sc_rep
[MAXKEYS
];
182 #endif /* defined(UKBD_REPEAT) */
183 #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */
188 u_int16_t sc_pollchars
[MAXKEYS
];
189 #endif /* defined(__NetBSD__) */
195 #define UKBDTRACESIZE 64
196 struct ukbdtraceinfo
{
201 struct ukbdtraceinfo ukbdtracedata
[UKBDTRACESIZE
];
202 int ukbdtraceindex
= 0;
204 void ukbdtracedump(void);
209 for (i
= 0; i
< UKBDTRACESIZE
; i
++) {
210 struct ukbdtraceinfo
*p
=
211 &ukbdtracedata
[(i
+ukbdtraceindex
)%UKBDTRACESIZE
];
212 printf("%"PRIu64
".%06"PRIu64
": mod=0x%02x key0=0x%02x key1=0x%02x "
213 "key2=0x%02x key3=0x%02x\n",
214 p
->tv
.tv_sec
, (uint64_t)p
->tv
.tv_usec
,
215 p
->ud
.modifiers
, p
->ud
.keycode
[0], p
->ud
.keycode
[1],
216 p
->ud
.keycode
[2], p
->ud
.keycode
[3]);
221 #define UKBDUNIT(dev) (minor(dev))
222 #define UKBD_CHUNK 128 /* chunk size for read */
223 #define UKBD_BSIZE 1020 /* buffer size */
225 Static
int ukbd_is_console
;
227 Static
void ukbd_cngetc(void *, u_int
*, int *);
228 Static
void ukbd_cnpollc(void *, int);
230 #if defined(__NetBSD__)
231 const struct wskbd_consops ukbd_consops
= {
238 Static
const char *ukbd_parse_desc(struct ukbd_softc
*sc
);
240 Static
void ukbd_intr(struct uhidev
*addr
, void *ibuf
, u_int len
);
241 Static
void ukbd_decode(struct ukbd_softc
*sc
, struct ukbd_data
*ud
);
242 Static
void ukbd_delayed_decode(void *addr
);
244 Static
int ukbd_enable(void *, int);
245 Static
void ukbd_set_leds(void *, int);
247 #if defined(__NetBSD__)
248 Static
int ukbd_ioctl(void *, u_long
, void *, int, struct lwp
*);
249 #if defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT)
250 Static
void ukbd_rawrepeat(void *v
);
253 const struct wskbd_accessops ukbd_accessops
= {
259 extern const struct wscons_keydesc ukbd_keydesctab
[];
261 const struct wskbd_mapdata ukbd_keymapdata
= {
263 #if defined(UKBD_LAYOUT)
265 #elif defined(PCKBD_LAYOUT)
273 static int ukbd_match(device_t
, cfdata_t
, void *);
274 static void ukbd_attach(device_t
, device_t
, void *);
275 static int ukbd_detach(device_t
, int);
276 static int ukbd_activate(device_t
, enum devact
);
277 static void ukbd_childdet(device_t
, device_t
);
279 extern struct cfdriver ukbd_cd
;
281 CFATTACH_DECL2_NEW(ukbd
, sizeof(struct ukbd_softc
), ukbd_match
, ukbd_attach
,
282 ukbd_detach
, ukbd_activate
, NULL
, ukbd_childdet
);
285 ukbd_match(device_t parent
, cfdata_t match
, void *aux
)
287 struct uhidev_attach_arg
*uha
= aux
;
291 uhidev_get_report_desc(uha
->parent
, &desc
, &size
);
292 if (!hid_is_collection(desc
, size
, uha
->reportid
,
293 HID_USAGE2(HUP_GENERIC_DESKTOP
, HUG_KEYBOARD
)))
294 return (UMATCH_NONE
);
296 return (UMATCH_IFACECLASS
);
300 ukbd_attach(device_t parent
, device_t self
, void *aux
)
302 struct ukbd_softc
*sc
= device_private(self
);
303 struct uhidev_attach_arg
*uha
= aux
;
305 const char *parseerr
;
306 #if defined(__NetBSD__)
307 struct wskbddev_attach_args a
;
312 sc
->sc_hdev
.sc_dev
= self
;
313 sc
->sc_hdev
.sc_intr
= ukbd_intr
;
314 sc
->sc_hdev
.sc_parent
= uha
->parent
;
315 sc
->sc_hdev
.sc_report_id
= uha
->reportid
;
317 if (!pmf_device_register(self
, NULL
, NULL
)) {
319 aprint_error_dev(self
, "couldn't establish power handler\n");
322 parseerr
= ukbd_parse_desc(sc
);
323 if (parseerr
!= NULL
) {
325 aprint_error_dev(self
, "attach failed, %s\n", parseerr
);
326 USB_ATTACH_ERROR_RETURN
;
330 aprint_normal(": %d modifier keys, %d key codes", sc
->sc_nmod
,
335 qflags
= usbd_get_quirks(uha
->parent
->sc_udev
)->uq_flags
;
336 sc
->sc_debounce
= (qflags
& UQ_SPUR_BUT_UP
) != 0;
339 * Remember if we're the console keyboard.
341 * XXX This always picks the first keyboard on the
342 * first USB bus, but what else can we really do?
344 if ((sc
->sc_console_keyboard
= ukbd_is_console
) != 0) {
345 /* Don't let any other keyboard have it. */
349 if (sc
->sc_console_keyboard
) {
350 DPRINTF(("ukbd_attach: console keyboard sc=%p\n", sc
));
351 wskbd_cnattach(&ukbd_consops
, sc
, &ukbd_keymapdata
);
355 a
.console
= sc
->sc_console_keyboard
;
357 a
.keymap
= &ukbd_keymapdata
;
359 a
.accessops
= &ukbd_accessops
;
363 usb_callout_init(sc
->sc_rawrepeat_ch
);
366 usb_callout_init(sc
->sc_delay
);
368 /* Flash the leds; no real purpose, just shows we're alive. */
369 ukbd_set_leds(sc
, WSKBD_LED_SCROLL
| WSKBD_LED_NUM
| WSKBD_LED_CAPS
);
370 usbd_delay_ms(uha
->parent
->sc_udev
, 400);
371 ukbd_set_leds(sc
, 0);
373 sc
->sc_wskbddev
= config_found(self
, &a
, wskbddevprint
);
375 USB_ATTACH_SUCCESS_RETURN
;
379 ukbd_enable(void *v
, int on
)
381 struct ukbd_softc
*sc
= v
;
383 if (on
&& sc
->sc_dying
)
386 /* Should only be called to change state */
387 if (sc
->sc_enabled
== on
) {
389 printf("ukbd_enable: %s: bad call on=%d\n",
390 USBDEVNAME(sc
->sc_hdev
.sc_dev
), on
);
395 DPRINTF(("ukbd_enable: sc=%p on=%d\n", sc
, on
));
398 return (uhidev_open(&sc
->sc_hdev
));
400 uhidev_close(&sc
->sc_hdev
);
407 ukbd_childdet(device_t self
, device_t child
)
409 struct ukbd_softc
*sc
= device_private(self
);
411 KASSERT(sc
->sc_wskbddev
== child
);
412 sc
->sc_wskbddev
= NULL
;
416 ukbd_activate(device_t self
, enum devact act
)
418 struct ukbd_softc
*sc
= device_private(self
);
421 case DVACT_DEACTIVATE
:
430 ukbd_detach(device_t self
, int flags
)
432 struct ukbd_softc
*sc
= device_private(self
);
435 DPRINTF(("ukbd_detach: sc=%p flags=%d\n", sc
, flags
));
437 pmf_device_deregister(self
);
439 if (sc
->sc_console_keyboard
) {
442 * XXX Should probably disconnect our consops,
443 * XXX and either notify some other keyboard that
444 * XXX it can now be the console, or if there aren't
445 * XXX any more USB keyboards, set ukbd_is_console
446 * XXX back to 1 so that the next USB keyboard attached
447 * XXX to the system will get it.
449 panic("ukbd_detach: console keyboard");
452 * Disconnect our consops and set ukbd_is_console
453 * back to 1 so that the next USB keyboard attached
454 * to the system will get it.
455 * XXX Should notify some other keyboard that it can be
456 * XXX console, if there are any other keyboards.
458 printf("%s: was console keyboard\n",
459 USBDEVNAME(sc
->sc_hdev
.sc_dev
));
464 /* No need to do reference counting of ukbd, wskbd has all the goo. */
465 if (sc
->sc_wskbddev
!= NULL
)
466 rv
= config_detach(sc
->sc_wskbddev
, flags
);
468 /* The console keyboard does not get a disable call, so check pipe. */
469 if (sc
->sc_hdev
.sc_state
& UHIDEV_OPEN
)
470 uhidev_close(&sc
->sc_hdev
);
476 ukbd_intr(struct uhidev
*addr
, void *ibuf
, u_int len
)
478 struct ukbd_softc
*sc
= (struct ukbd_softc
*)addr
;
479 struct ukbd_data
*ud
= &sc
->sc_ndata
;
484 printf("ukbd_intr: data");
485 for (i
= 0; i
< len
; i
++)
486 printf(" 0x%02x", ((u_char
*)ibuf
)[i
]);
492 for (i
= 0; i
< sc
->sc_nmod
; i
++)
493 if (hid_get_data(ibuf
, &sc
->sc_modloc
[i
]))
494 ud
->modifiers
|= sc
->sc_mods
[i
].mask
;
495 memcpy(ud
->keycode
, (char *)ibuf
+ sc
->sc_keycodeloc
.pos
/ 8,
498 if (sc
->sc_debounce
&& !sc
->sc_polling
) {
500 * Some keyboards have a peculiar quirk. They sometimes
501 * generate a key up followed by a key down for the same
502 * key after about 10 ms.
503 * We avoid this bug by holding off decoding for 20 ms.
506 usb_callout(sc
->sc_delay
, hz
/ 50, ukbd_delayed_decode
, sc
);
508 } else if (sc
->sc_console_keyboard
&& !sc
->sc_polling
) {
510 * For the console keyboard we can't deliver CTL-ALT-ESC
511 * from the interrupt routine. Doing so would start
512 * polling from inside the interrupt routine and that
516 usb_callout(sc
->sc_delay
, 1, ukbd_delayed_decode
, sc
);
524 ukbd_delayed_decode(void *addr
)
526 struct ukbd_softc
*sc
= addr
;
528 ukbd_decode(sc
, &sc
->sc_data
);
532 ukbd_decode(struct ukbd_softc
*sc
, struct ukbd_data
*ud
)
535 u_int16_t ibuf
[MAXKEYS
]; /* chars events */
539 #define ADDKEY(c) ibuf[nkeys++] = (c)
543 * Keep a trace of the last events. Using printf changes the
544 * timing, so this can be useful sometimes.
547 struct ukbdtraceinfo
*p
= &ukbdtracedata
[ukbdtraceindex
];
548 p
->unit
= device_unit(sc
->sc_hdev
.sc_dev
);
551 if (++ukbdtraceindex
>= UKBDTRACESIZE
)
557 DPRINTF((" at %"PRIu64
".%06"PRIu64
" mod=0x%02x key0=0x%02x key1=0x%02x "
558 "key2=0x%02x key3=0x%02x\n",
559 tv
.tv_sec
, (uint64_t)tv
.tv_usec
,
560 ud
->modifiers
, ud
->keycode
[0], ud
->keycode
[1],
561 ud
->keycode
[2], ud
->keycode
[3]));
565 if (ud
->keycode
[0] == KEY_ERROR
) {
566 DPRINTF(("ukbd_intr: KEY_ERROR\n"));
571 omod
= sc
->sc_odata
.modifiers
;
573 for (i
= 0; i
< sc
->sc_nmod
; i
++)
574 if (( mod
& sc
->sc_mods
[i
].mask
) !=
575 (omod
& sc
->sc_mods
[i
].mask
))
576 ADDKEY(sc
->sc_mods
[i
].key
|
577 (mod
& sc
->sc_mods
[i
].mask
579 if (memcmp(ud
->keycode
, sc
->sc_odata
.keycode
, sc
->sc_nkeycode
) != 0) {
580 /* Check for released keys. */
581 for (i
= 0; i
< sc
->sc_nkeycode
; i
++) {
582 key
= sc
->sc_odata
.keycode
[i
];
585 for (j
= 0; j
< sc
->sc_nkeycode
; j
++)
586 if (key
== ud
->keycode
[j
])
588 DPRINTFN(3,("ukbd_intr: relse key=0x%02x\n", key
));
589 ADDKEY(key
| RELEASE
);
594 /* Check for pressed keys. */
595 for (i
= 0; i
< sc
->sc_nkeycode
; i
++) {
596 key
= ud
->keycode
[i
];
599 for (j
= 0; j
< sc
->sc_nkeycode
; j
++)
600 if (key
== sc
->sc_odata
.keycode
[j
])
602 DPRINTFN(2,("ukbd_intr: press key=0x%02x\n", key
));
613 if (sc
->sc_polling
) {
614 DPRINTFN(1,("ukbd_intr: pollchar = 0x%03x\n", ibuf
[0]));
615 memcpy(sc
->sc_pollchars
, ibuf
, nkeys
* sizeof(u_int16_t
));
616 sc
->sc_npollchar
= nkeys
;
619 #ifdef WSDISPLAY_COMPAT_RAWKBD
621 u_char cbuf
[MAXKEYS
* 2];
625 for (npress
= i
= j
= 0; i
< nkeys
; i
++) {
627 c
= ukbd_trtab
[key
& CODEMASK
];
634 cbuf
[j
-1] |= (key
& RELEASE
) ? 0x80 : 0;
643 #if defined(UKBD_REPEAT)
645 /* remember pressed keys for autorepeat */
647 sc
->sc_rep
[npress
++] = 0xe0;
648 sc
->sc_rep
[npress
++] = c
& 0x7f;
651 DPRINTFN(1,("ukbd_intr: raw = %s0x%02x\n",
652 c
& 0x80 ? "0xe0 " : "",
657 wskbd_rawinput(sc
->sc_wskbddev
, cbuf
, j
);
660 usb_uncallout(sc
->sc_rawrepeat_ch
, ukbd_rawrepeat
, sc
);
662 sc
->sc_nrep
= npress
;
663 usb_callout(sc
->sc_rawrepeat_ch
,
664 hz
* REP_DELAY1
/ 1000, ukbd_rawrepeat
, sc
);
672 for (i
= 0; i
< nkeys
; i
++) {
674 wskbd_input(sc
->sc_wskbddev
,
675 key
&RELEASE
? WSCONS_EVENT_KEY_UP
: WSCONS_EVENT_KEY_DOWN
,
682 ukbd_set_leds(void *v
, int leds
)
684 struct ukbd_softc
*sc
= v
;
687 DPRINTF(("ukbd_set_leds: sc=%p leds=%d, sc_leds=%d\n",
688 sc
, leds
, sc
->sc_leds
));
693 if (sc
->sc_leds
== leds
)
697 /* XXX not really right */
698 if ((leds
& WSKBD_LED_SCROLL
) && sc
->sc_scroloc
.size
== 1)
699 res
|= 1 << sc
->sc_scroloc
.pos
;
700 if ((leds
& WSKBD_LED_NUM
) && sc
->sc_numloc
.size
== 1)
701 res
|= 1 << sc
->sc_numloc
.pos
;
702 if ((leds
& WSKBD_LED_CAPS
) && sc
->sc_capsloc
.size
== 1)
703 res
|= 1 << sc
->sc_capsloc
.pos
;
704 uhidev_set_report_async(&sc
->sc_hdev
, UHID_OUTPUT_REPORT
, &res
, 1);
707 #if defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT)
709 ukbd_rawrepeat(void *v
)
711 struct ukbd_softc
*sc
= v
;
715 wskbd_rawinput(sc
->sc_wskbddev
, sc
->sc_rep
, sc
->sc_nrep
);
717 usb_callout(sc
->sc_rawrepeat_ch
, hz
* REP_DELAYN
/ 1000,
720 #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT) */
723 ukbd_ioctl(void *v
, u_long cmd
, void *data
, int flag
,
726 struct ukbd_softc
*sc
= v
;
730 *(int *)data
= WSKBD_TYPE_USB
;
732 case WSKBDIO_SETLEDS
:
733 ukbd_set_leds(v
, *(int *)data
);
735 case WSKBDIO_GETLEDS
:
736 *(int *)data
= sc
->sc_leds
;
738 #if defined(WSDISPLAY_COMPAT_RAWKBD)
739 case WSKBDIO_SETMODE
:
740 DPRINTF(("ukbd_ioctl: set raw = %d\n", *(int *)data
));
741 sc
->sc_rawkbd
= *(int *)data
== WSKBD_RAW
;
742 #if defined(UKBD_REPEAT)
743 usb_uncallout(sc
->sc_rawrepeat_ch
, ukbd_rawrepeat
, sc
);
748 return (EPASSTHROUGH
);
752 * This is a hack to work around some broken ports that don't call
753 * cnpollc() before cngetc().
755 static int pollenter
, warned
;
757 /* Console interface. */
759 ukbd_cngetc(void *v
, u_int
*type
, int *data
)
761 struct ukbd_softc
*sc
= v
;
765 if (pollenter
== 0) {
768 "This port is broken, it does not call cnpollc() before calling cngetc().\n"
769 "This should be fixed, but it will work anyway (for now).\n");
777 DPRINTFN(0,("ukbd_cngetc: enter\n"));
779 while(sc
->sc_npollchar
<= 0)
780 usbd_dopoll(sc
->sc_hdev
.sc_parent
->sc_iface
);
782 c
= sc
->sc_pollchars
[0];
784 memcpy(sc
->sc_pollchars
, sc
->sc_pollchars
+1,
785 sc
->sc_npollchar
* sizeof(u_int16_t
));
786 *type
= c
& RELEASE
? WSCONS_EVENT_KEY_UP
: WSCONS_EVENT_KEY_DOWN
;
787 *data
= c
& CODEMASK
;
788 DPRINTFN(0,("ukbd_cngetc: return 0x%02x\n", c
));
794 ukbd_cnpollc(void *v
, int on
)
796 struct ukbd_softc
*sc
= v
;
797 usbd_device_handle dev
;
799 DPRINTFN(2,("ukbd_cnpollc: sc=%p on=%d\n", v
, on
));
801 usbd_interface2device_handle(sc
->sc_hdev
.sc_parent
->sc_iface
, &dev
);
803 sc
->sc_spl
= splusb();
809 usbd_set_polling(dev
, on
);
817 * XXX USB requires too many parts of the kernel to be running
818 * XXX in order to work, so we can't do much for the console
819 * XXX keyboard until autconfiguration has run its course.
826 ukbd_parse_desc(struct ukbd_softc
*sc
)
834 uhidev_get_report_desc(sc
->sc_hdev
.sc_parent
, &desc
, &size
);
837 d
= hid_start_parse(desc
, size
, hid_input
);
838 while (hid_get_item(d
, &h
)) {
839 /*printf("ukbd: id=%d kind=%d usage=0x%x flags=0x%x pos=%d size=%d cnt=%d\n",
840 h.report_ID, h.kind, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count);*/
841 if (h
.kind
!= hid_input
|| (h
.flags
& HIO_CONST
) ||
842 HID_GET_USAGE_PAGE(h
.usage
) != HUP_KEYBOARD
||
843 h
.report_ID
!= sc
->sc_hdev
.sc_report_id
)
845 DPRINTF(("ukbd: imod=%d usage=0x%x flags=0x%x pos=%d size=%d "
847 h
.usage
, h
.flags
, h
.loc
.pos
, h
.loc
.size
, h
.loc
.count
));
848 if (h
.flags
& HIO_VARIABLE
) {
850 return ("bad modifier size");
853 sc
->sc_modloc
[imod
] = h
.loc
;
854 sc
->sc_mods
[imod
].mask
= 1 << imod
;
855 sc
->sc_mods
[imod
].key
= HID_GET_USAGE(h
.usage
);
858 return ("too many modifier keys");
862 return ("key code size != 8");
863 if (h
.loc
.count
> MAXKEYCODE
)
864 return ("too many key codes");
865 if (h
.loc
.pos
% 8 != 0)
866 return ("key codes not on byte boundary");
867 if (sc
->sc_nkeycode
!= 0)
868 return ("multiple key code arrays\n");
869 sc
->sc_keycodeloc
= h
.loc
;
870 sc
->sc_nkeycode
= h
.loc
.count
;
876 hid_locate(desc
, size
, HID_USAGE2(HUP_LEDS
, HUD_LED_NUM_LOCK
),
877 sc
->sc_hdev
.sc_report_id
, hid_output
, &sc
->sc_numloc
, NULL
);
878 hid_locate(desc
, size
, HID_USAGE2(HUP_LEDS
, HUD_LED_CAPS_LOCK
),
879 sc
->sc_hdev
.sc_report_id
, hid_output
, &sc
->sc_capsloc
, NULL
);
880 hid_locate(desc
, size
, HID_USAGE2(HUP_LEDS
, HUD_LED_SCROLL_LOCK
),
881 sc
->sc_hdev
.sc_report_id
, hid_output
, &sc
->sc_scroloc
, NULL
);