1 /* $NetBSD: btkbd.c,v 1.10 2008/09/09 03:54:56 cube 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 * Copyright (c) 2006 Itronix Inc.
35 * All rights reserved.
37 * Written by Iain Hibbert for Itronix Inc.
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
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. The name of Itronix Inc. may not be used to endorse
48 * or promote products derived from this software without specific
49 * prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
53 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
54 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY
55 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
56 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
57 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
58 * ON ANY THEORY OF LIABILITY, WHETHER IN
59 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61 * POSSIBILITY OF SUCH DAMAGE.
65 * based on dev/usb/ukbd.c
68 #include <sys/cdefs.h>
69 __KERNEL_RCSID(0, "$NetBSD: btkbd.c,v 1.10 2008/09/09 03:54:56 cube Exp $");
71 #include <sys/param.h>
72 #include <sys/callout.h>
74 #include <sys/device.h>
75 #include <sys/kernel.h>
77 #include <sys/systm.h>
79 #include <netbt/bluetooth.h>
81 #include <dev/bluetooth/bthid.h>
82 #include <dev/bluetooth/bthidev.h>
84 #include <dev/usb/hid.h>
85 #include <dev/usb/usb.h>
86 #include <dev/usb/usbhid.h>
88 #include <dev/wscons/wsconsio.h>
89 #include <dev/wscons/wskbdvar.h>
90 #include <dev/wscons/wsksymdef.h>
91 #include <dev/wscons/wsksymvar.h>
93 #include "opt_wsdisplay_compat.h"
94 #include "opt_btkbd.h"
97 #define MAXMOD 8 /* max 32 */
98 #define MAXKEYS (MAXMOD + (2 * MAXKEYCODE))
102 uint8_t keycode
[MAXKEYCODE
];
111 struct bthidev sc_hidev
; /* device+ */
112 device_t sc_wskbd
; /* child */
115 int (*sc_output
) /* output method */
116 (struct bthidev
*, uint8_t *, int);
119 struct btkbd_data sc_odata
;
120 struct btkbd_data sc_ndata
;
124 struct hid_location sc_modloc
[MAXMOD
];
125 struct btkbd_mod sc_mods
[MAXMOD
];
128 struct hid_location sc_keycodeloc
;
131 struct hid_location sc_numloc
;
132 struct hid_location sc_capsloc
;
133 struct hid_location sc_scroloc
;
136 #ifdef WSDISPLAY_COMPAT_RAWKBD
141 char sc_rep
[MAXKEYS
];
146 /* autoconf(9) methods */
147 static int btkbd_match(device_t
, cfdata_t
, void *);
148 static void btkbd_attach(device_t
, device_t
, void *);
149 static int btkbd_detach(device_t
, int);
151 CFATTACH_DECL_NEW(btkbd
, sizeof(struct btkbd_softc
),
152 btkbd_match
, btkbd_attach
, btkbd_detach
, NULL
);
154 /* wskbd(4) accessops */
155 static int btkbd_enable(void *, int);
156 static void btkbd_set_leds(void *, int);
157 static int btkbd_ioctl(void *, unsigned long, void *, int, struct lwp
*);
159 static const struct wskbd_accessops btkbd_accessops
= {
165 /* wskbd(4) keymap data */
166 extern const struct wscons_keydesc ukbd_keydesctab
[];
168 const struct wskbd_mapdata btkbd_keymapdata
= {
170 #if defined(BTKBD_LAYOUT)
172 #elif defined(PCKBD_LAYOUT)
180 static void btkbd_input(struct bthidev
*, uint8_t *, int);
182 /* internal prototypes */
183 static const char *btkbd_parse_desc(struct btkbd_softc
*, int, const void *, int);
185 #ifdef WSDISPLAY_COMPAT_RAWKBD
187 static void btkbd_repeat(void *);
191 /*****************************************************************************
193 * btkbd autoconf(9) routines
197 btkbd_match(device_t self
, cfdata_t cfdata
, void *aux
)
199 struct bthidev_attach_args
*ba
= aux
;
201 if (hid_is_collection(ba
->ba_desc
, ba
->ba_dlen
, ba
->ba_id
,
202 HID_USAGE2(HUP_GENERIC_DESKTOP
, HUG_KEYBOARD
)))
209 btkbd_attach(device_t parent
, device_t self
, void *aux
)
211 struct btkbd_softc
*sc
= device_private(self
);
212 struct bthidev_attach_args
*ba
= aux
;
213 struct wskbddev_attach_args wska
;
216 sc
->sc_output
= ba
->ba_output
;
217 ba
->ba_input
= btkbd_input
;
219 parserr
= btkbd_parse_desc(sc
, ba
->ba_id
, ba
->ba_desc
, ba
->ba_dlen
);
220 if (parserr
!= NULL
) {
221 aprint_error("%s\n", parserr
);
227 #ifdef WSDISPLAY_COMPAT_RAWKBD
229 callout_init(&sc
->sc_repeat
, 0);
230 callout_setfunc(&sc
->sc_repeat
, btkbd_repeat
, sc
);
235 wska
.keymap
= &btkbd_keymapdata
;
236 wska
.accessops
= &btkbd_accessops
;
237 wska
.accesscookie
= sc
;
239 sc
->sc_wskbd
= config_found(self
, &wska
, wskbddevprint
);
243 btkbd_detach(device_t self
, int flags
)
245 struct btkbd_softc
*sc
= device_private(self
);
248 #ifdef WSDISPLAY_COMPAT_RAWKBD
250 callout_stop(&sc
->sc_repeat
);
251 KASSERT(!callout_invoking(&sc
->sc_repeat
));
252 callout_destroy(&sc
->sc_repeat
);
256 if (sc
->sc_wskbd
!= NULL
) {
257 err
= config_detach(sc
->sc_wskbd
, flags
);
265 btkbd_parse_desc(struct btkbd_softc
*sc
, int id
, const void *desc
, int dlen
)
273 d
= hid_start_parse(desc
, dlen
, hid_input
);
274 while (hid_get_item(d
, &h
)) {
275 if (h
.kind
!= hid_input
|| (h
.flags
& HIO_CONST
) ||
276 HID_GET_USAGE_PAGE(h
.usage
) != HUP_KEYBOARD
||
280 if (h
.flags
& HIO_VARIABLE
) {
282 return ("bad modifier size");
286 sc
->sc_modloc
[imod
] = h
.loc
;
287 sc
->sc_mods
[imod
].mask
= 1 << imod
;
288 sc
->sc_mods
[imod
].key
= HID_GET_USAGE(h
.usage
);
291 return ("too many modifier keys");
295 return ("key code size != 8");
297 if (h
.loc
.count
> MAXKEYCODE
)
298 return ("too many key codes");
300 if (h
.loc
.pos
% 8 != 0)
301 return ("key codes not on byte boundary");
303 if (sc
->sc_nkeycode
!= 0)
304 return ("multiple key code arrays\n");
306 sc
->sc_keycodeloc
= h
.loc
;
307 sc
->sc_nkeycode
= h
.loc
.count
;
313 hid_locate(desc
, dlen
, HID_USAGE2(HUP_LEDS
, HUD_LED_NUM_LOCK
),
314 id
, hid_output
, &sc
->sc_numloc
, NULL
);
316 hid_locate(desc
, dlen
, HID_USAGE2(HUP_LEDS
, HUD_LED_CAPS_LOCK
),
317 id
, hid_output
, &sc
->sc_capsloc
, NULL
);
319 hid_locate(desc
, dlen
, HID_USAGE2(HUP_LEDS
, HUD_LED_SCROLL_LOCK
),
320 id
, hid_output
, &sc
->sc_scroloc
, NULL
);
325 /*****************************************************************************
331 btkbd_enable(void *self
, int on
)
333 struct btkbd_softc
*sc
= self
;
340 btkbd_set_leds(void *self
, int leds
)
342 struct btkbd_softc
*sc
= self
;
345 if (sc
->sc_leds
== leds
)
351 * This is not totally correct, since we did not check the
352 * report size from the descriptor but for keyboards it should
353 * just be a single byte with the relevant bits set.
356 if ((leds
& WSKBD_LED_SCROLL
) && sc
->sc_scroloc
.size
== 1)
357 report
|= 1 << sc
->sc_scroloc
.pos
;
359 if ((leds
& WSKBD_LED_NUM
) && sc
->sc_numloc
.size
== 1)
360 report
|= 1 << sc
->sc_numloc
.pos
;
362 if ((leds
& WSKBD_LED_CAPS
) && sc
->sc_capsloc
.size
== 1)
363 report
|= 1 << sc
->sc_capsloc
.pos
;
366 (*sc
->sc_output
)(&sc
->sc_hidev
, &report
, sizeof(report
));
370 btkbd_ioctl(void *self
, unsigned long cmd
, void *data
, int flag
,
373 struct btkbd_softc
*sc
= self
;
377 *(int *)data
= WSKBD_TYPE_BLUETOOTH
;
380 case WSKBDIO_SETLEDS
:
381 btkbd_set_leds(sc
, *(int *)data
);
384 case WSKBDIO_GETLEDS
:
385 *(int *)data
= sc
->sc_leds
;
388 #ifdef WSDISPLAY_COMPAT_RAWKBD
389 case WSKBDIO_SETMODE
:
390 sc
->sc_rawkbd
= (*(int *)data
== WSKBD_RAW
);
392 callout_stop(&sc
->sc_repeat
);
404 /*****************************************************************************
406 * btkbd input routine, called from our parent
409 #ifdef WSDISPLAY_COMPAT_RAWKBD
410 #define NN 0 /* no translation */
412 * Translate USB keycodes to US keyboard XT scancodes.
413 * Scancodes >= 0x80 represent EXTENDED keycodes.
415 * See http://www.microsoft.com/HWDEV/TECH/input/Scancode.asp
417 static const u_int8_t btkbd_trtab
[256] = {
418 NN
, NN
, NN
, NN
, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */
419 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */
420 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */
421 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */
422 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */
423 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */
424 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */
425 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */
426 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xaa, 0x46, /* 40 - 47 */
427 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */
428 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */
429 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */
430 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, NN
, 0x59, /* 60 - 67 */
431 0x5d, 0x5e, 0x5f, NN
, NN
, NN
, NN
, NN
, /* 68 - 6f */
432 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* 70 - 77 */
433 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* 78 - 7f */
434 NN
, NN
, NN
, NN
, NN
, 0x7e, NN
, 0x73, /* 80 - 87 */
435 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN
, NN
, NN
, /* 88 - 8f */
436 NN
, NN
, 0x78, 0x77, 0x76, NN
, NN
, NN
, /* 90 - 97 */
437 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* 98 - 9f */
438 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* a0 - a7 */
439 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* a8 - af */
440 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* b0 - b7 */
441 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* b8 - bf */
442 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* c0 - c7 */
443 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* c8 - cf */
444 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* d0 - d7 */
445 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* d8 - df */
446 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* e0 - e7 */
447 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* e8 - ef */
448 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* f0 - f7 */
449 NN
, NN
, NN
, NN
, NN
, NN
, NN
, NN
, /* f8 - ff */
453 #define KEY_ERROR 0x01
455 #define RELEASE 0x100
456 #define CODEMASK 0x0ff
457 #define ADDKEY(c) ibuf[nkeys++] = (c)
458 #define REP_DELAY1 400
459 #define REP_DELAYN 100
462 btkbd_input(struct bthidev
*self
, uint8_t *data
, int len
)
464 struct btkbd_softc
*sc
= (struct btkbd_softc
*)self
;
465 struct btkbd_data
*ud
= &sc
->sc_ndata
;
466 uint16_t ibuf
[MAXKEYS
];
472 if (sc
->sc_wskbd
== NULL
|| sc
->sc_enabled
== 0)
475 /* extract key modifiers */
477 for (i
= 0 ; i
< sc
->sc_nmod
; i
++)
478 if (hid_get_data(data
, &sc
->sc_modloc
[i
]))
479 ud
->modifiers
|= sc
->sc_mods
[i
].mask
;
481 /* extract keycodes */
482 memcpy(ud
->keycode
, data
+ (sc
->sc_keycodeloc
.pos
/ 8),
485 if (ud
->keycode
[0] == KEY_ERROR
)
490 omod
= sc
->sc_odata
.modifiers
;
492 for (i
= 0 ; i
< sc
->sc_nmod
; i
++)
493 if ((mod
& sc
->sc_mods
[i
].mask
) !=
494 (omod
& sc
->sc_mods
[i
].mask
))
495 ADDKEY(sc
->sc_mods
[i
].key
|
496 (mod
& sc
->sc_mods
[i
].mask
499 if (memcmp(ud
->keycode
, sc
->sc_odata
.keycode
, sc
->sc_nkeycode
) != 0) {
500 /* Check for released keys. */
501 for (i
= 0 ; i
< sc
->sc_nkeycode
; i
++) {
502 key
= sc
->sc_odata
.keycode
[i
];
506 for (j
= 0 ; j
< sc
->sc_nkeycode
; j
++)
507 if (key
== ud
->keycode
[j
])
510 ADDKEY(key
| RELEASE
);
516 /* Check for pressed keys. */
517 for (i
= 0 ; i
< sc
->sc_nkeycode
; i
++) {
518 key
= ud
->keycode
[i
];
522 for (j
= 0; j
< sc
->sc_nkeycode
; j
++)
523 if (key
== sc
->sc_odata
.keycode
[j
])
536 #ifdef WSDISPLAY_COMPAT_RAWKBD
538 u_char cbuf
[MAXKEYS
* 2];
542 for (npress
= i
= j
= 0 ; i
< nkeys
; i
++) {
544 c
= btkbd_trtab
[key
& CODEMASK
];
556 /* remember pressed keys for autorepeat */
558 sc
->sc_rep
[npress
++] = 0xe0;
560 sc
->sc_rep
[npress
++] = c
& 0x7f;
568 wskbd_rawinput(sc
->sc_wskbd
, cbuf
, j
);
571 callout_stop(&sc
->sc_repeat
);
573 sc
->sc_nrep
= npress
;
574 callout_schedule(&sc
->sc_repeat
, hz
* REP_DELAY1
/ 1000);
582 for (i
= 0 ; i
< nkeys
; i
++) {
584 wskbd_input(sc
->sc_wskbd
,
585 key
& RELEASE
? WSCONS_EVENT_KEY_UP
: WSCONS_EVENT_KEY_DOWN
,
591 #ifdef WSDISPLAY_COMPAT_RAWKBD
594 btkbd_repeat(void *arg
)
596 struct btkbd_softc
*sc
= arg
;
600 wskbd_rawinput(sc
->sc_wskbd
, sc
->sc_rep
, sc
->sc_nrep
);
602 callout_schedule(&sc
->sc_repeat
, hz
* REP_DELAYN
/ 1000);