This source file includes following definitions.
- btkbd_match
- btkbd_attach
- btkbd_detach
- btkbd_parse_desc
- btkbd_enable
- btkbd_set_leds
- btkbd_ioctl
- btkbd_input
- btkbd_repeat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 #include <sys/param.h>
40 #include <sys/conf.h>
41 #include <sys/device.h>
42 #include <sys/kernel.h>
43 #include <sys/proc.h>
44 #include <sys/systm.h>
45
46 #include <netbt/bluetooth.h>
47
48 #include <dev/bluetooth/bthid.h>
49 #include <dev/bluetooth/bthidev.h>
50
51 #include <dev/usb/hid.h>
52 #include <dev/usb/usb.h>
53 #include <dev/usb/usbhid.h>
54
55 #include <dev/wscons/wsconsio.h>
56 #include <dev/wscons/wskbdvar.h>
57 #include <dev/wscons/wsksymdef.h>
58 #include <dev/wscons/wsksymvar.h>
59
60 #define MAXKEYCODE 6
61 #define MAXMOD 8
62 #define MAXKEYS (MAXMOD + (2 * MAXKEYCODE))
63
64 struct btkbd_data {
65 uint32_t modifiers;
66 uint8_t keycode[MAXKEYCODE];
67 };
68
69 struct btkbd_mod {
70 uint32_t mask;
71 uint8_t key;
72 };
73
74 struct btkbd_softc {
75 struct bthidev sc_hidev;
76 struct device *sc_wskbd;
77 int sc_enabled;
78
79 int (*sc_output)
80 (struct bthidev *, uint8_t *, int);
81
82
83 struct btkbd_data sc_odata;
84 struct btkbd_data sc_ndata;
85
86
87 int sc_nmod;
88 struct hid_location sc_modloc[MAXMOD];
89 struct btkbd_mod sc_mods[MAXMOD];
90
91 int sc_nkeycode;
92 struct hid_location sc_keycodeloc;
93
94
95 struct hid_location sc_numloc;
96 struct hid_location sc_capsloc;
97 struct hid_location sc_scroloc;
98 int sc_leds;
99
100 #ifdef WSDISPLAY_COMPAT_RAWKBD
101 int sc_rawkbd;
102 #ifdef BTKBD_REPEAT
103 struct timeout sc_repeat;
104 int sc_nrep;
105 char sc_rep[MAXKEYS];
106 #endif
107 #endif
108 };
109
110 int btkbd_match(struct device *, struct cfdata *, void *);
111 void btkbd_attach(struct device *, struct device *, void *);
112 int btkbd_detach(struct device *, int);
113
114 struct cfdriver btkbd_cd = {
115 NULL, "btkbd", DV_DULL
116 };
117
118 const struct cfattach btkbd_ca = {
119 sizeof(struct btkbd_softc),
120 btkbd_match,
121 btkbd_attach,
122 btkbd_detach,
123 };
124
125 int btkbd_enable(void *, int);
126 void btkbd_set_leds(void *, int);
127 int btkbd_ioctl(void *, unsigned long, void *, int, struct lwp *);
128
129 const struct wskbd_accessops btkbd_accessops = {
130 btkbd_enable,
131 btkbd_set_leds,
132 btkbd_ioctl
133 };
134
135
136 extern const struct wscons_keydesc ukbd_keydesctab[];
137
138 const struct wskbd_mapdata btkbd_keymapdata = {
139 ukbd_keydesctab,
140 #if defined(BTKBD_LAYOUT)
141 BTKBD_LAYOUT,
142 #elif defined(PCKBD_LAYOUT)
143 PCKBD_LAYOUT,
144 #else
145 KB_US,
146 #endif
147 };
148
149
150 void btkbd_input(struct bthidev *, uint8_t *, int);
151
152
153 const char *btkbd_parse_desc(struct btkbd_softc *, int, const void *, int);
154
155 #ifdef WSDISPLAY_COMPAT_RAWKBD
156 #ifdef BTKBD_REPEAT
157 void btkbd_repeat(void *);
158 #endif
159 #endif
160
161
162 int
163 btkbd_match(struct device *self, struct cfdata *cfdata, void *aux)
164 {
165 struct bthidev_attach_args *ba = aux;
166
167 if (hid_is_collection(ba->ba_desc, ba->ba_dlen, ba->ba_id,
168 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
169 return 1;
170
171 return 0;
172 }
173
174 void
175 btkbd_attach(struct device *parent, struct device *self, void *aux)
176 {
177 struct btkbd_softc *sc = (struct btkbd_softc *)self;
178 struct bthidev_attach_args *ba = aux;
179 struct wskbddev_attach_args wska;
180 const char *parserr;
181
182 sc->sc_output = ba->ba_output;
183 ba->ba_input = btkbd_input;
184
185 parserr = btkbd_parse_desc(sc, ba->ba_id, ba->ba_desc, ba->ba_dlen);
186 if (parserr != NULL) {
187 printf("%s\n", parserr);
188 return;
189 }
190
191 printf("\n");
192
193 #ifdef WSDISPLAY_COMPAT_RAWKBD
194 #ifdef BTKBD_REPEAT
195 timeout_set(&sc->sc_repeat, NULL, NULL);
196
197 #endif
198 #endif
199
200 wska.console = 0;
201 wska.keymap = &btkbd_keymapdata;
202 wska.accessops = &btkbd_accessops;
203 wska.accesscookie = sc;
204
205 sc->sc_wskbd = config_found((struct device *)sc, &wska, wskbddevprint);
206 }
207
208 int
209 btkbd_detach(struct device *self, int flags)
210 {
211 struct btkbd_softc *sc = (struct btkbd_softc *)self;
212 int err = 0;
213
214 #ifdef WSDISPLAY_COMPAT_RAWKBD
215 #ifdef BTKBD_REPEAT
216 timeout_del(&sc->sc_repeat);
217 #endif
218 #endif
219
220 if (sc->sc_wskbd != NULL) {
221 err = config_detach(sc->sc_wskbd, flags);
222 sc->sc_wskbd = NULL;
223 }
224
225 return err;
226 }
227
228 const char *
229 btkbd_parse_desc(struct btkbd_softc *sc, int id, const void *desc, int dlen)
230 {
231 struct hid_data *d;
232 struct hid_item h;
233 int imod;
234
235 imod = 0;
236 sc->sc_nkeycode = 0;
237 d = hid_start_parse(desc, dlen, hid_input);
238 while (hid_get_item(d, &h)) {
239 if (h.kind != hid_input || (h.flags & HIO_CONST) ||
240 HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD ||
241 h.report_ID != id)
242 continue;
243
244 if (h.flags & HIO_VARIABLE) {
245 if (h.loc.size != 1)
246 return ("bad modifier size");
247
248
249 if (imod < MAXMOD) {
250 sc->sc_modloc[imod] = h.loc;
251 sc->sc_mods[imod].mask = 1 << imod;
252 sc->sc_mods[imod].key = HID_GET_USAGE(h.usage);
253 imod++;
254 } else
255 return ("too many modifier keys");
256 } else {
257
258 if (h.loc.size != 8)
259 return ("key code size != 8");
260
261 if (h.loc.count > MAXKEYCODE)
262 return ("too many key codes");
263
264 if (h.loc.pos % 8 != 0)
265 return ("key codes not on byte boundary");
266
267 if (sc->sc_nkeycode != 0)
268 return ("multiple key code arrays\n");
269
270 sc->sc_keycodeloc = h.loc;
271 sc->sc_nkeycode = h.loc.count;
272 }
273 }
274 sc->sc_nmod = imod;
275 hid_end_parse(d);
276
277 hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK),
278 id, hid_output, &sc->sc_numloc, NULL);
279
280 hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK),
281 id, hid_output, &sc->sc_capsloc, NULL);
282
283 hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK),
284 id, hid_output, &sc->sc_scroloc, NULL);
285
286 return (NULL);
287 }
288
289 int
290 btkbd_enable(void *self, int on)
291 {
292 struct btkbd_softc *sc = (struct btkbd_softc *)self;
293
294 sc->sc_enabled = on;
295 return 0;
296 }
297
298 void
299 btkbd_set_leds(void *self, int leds)
300 {
301 struct btkbd_softc *sc = (struct btkbd_softc *)self;
302 uint8_t report;
303
304 if (sc->sc_leds == leds)
305 return;
306
307 sc->sc_leds = leds;
308
309
310
311
312
313
314 report = 0;
315 if ((leds & WSKBD_LED_SCROLL) && sc->sc_scroloc.size == 1)
316 report |= 1 << sc->sc_scroloc.pos;
317
318 if ((leds & WSKBD_LED_NUM) && sc->sc_numloc.size == 1)
319 report |= 1 << sc->sc_numloc.pos;
320
321 if ((leds & WSKBD_LED_CAPS) && sc->sc_capsloc.size == 1)
322 report |= 1 << sc->sc_capsloc.pos;
323
324 if (sc->sc_output)
325 (*sc->sc_output)(&sc->sc_hidev, &report, sizeof(report));
326 }
327
328 int
329 btkbd_ioctl(void *self, unsigned long cmd, void *data, int flag, struct lwp *l)
330 {
331 struct btkbd_softc *sc = (struct btkbd_softc *)self;
332
333 switch (cmd) {
334 case WSKBDIO_GTYPE:
335 *(int *)data = WSKBD_TYPE_BLUETOOTH;
336 break;
337
338 case WSKBDIO_SETLEDS:
339 btkbd_set_leds(sc, *(int *)data);
340 break;
341
342 case WSKBDIO_GETLEDS:
343 *(int *)data = sc->sc_leds;
344 break;
345
346 #ifdef WSDISPLAY_COMPAT_RAWKBD
347 case WSKBDIO_SETMODE:
348 sc->sc_rawkbd = (*(int *)data == WSKBD_RAW);
349 #ifdef BTKBD_REPEAT
350 timeout_del(&sc->sc_repeat);
351 #endif
352 break;
353 #endif
354
355 default:
356 return EPASSTHROUGH;
357 }
358
359 return 0;
360 }
361
362 #ifdef WSDISPLAY_COMPAT_RAWKBD
363 #define NN 0
364
365
366
367
368
369
370 const u_int8_t btkbd_trtab[256] = {
371 NN, NN, NN, NN, 0x1e, 0x30, 0x2e, 0x20,
372 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26,
373 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14,
374 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03,
375 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
376 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a,
377 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34,
378 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
379 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xaa, 0x46,
380 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd,
381 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e,
382 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47,
383 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, NN, 0x59,
384 0x5d, 0x5e, 0x5f, NN, NN, NN, NN, NN,
385 NN, NN, NN, NN, NN, NN, NN, NN,
386 NN, NN, NN, NN, NN, NN, NN, NN,
387 NN, NN, NN, NN, NN, 0x7e, NN, 0x73,
388 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN, NN, NN,
389 NN, NN, 0x78, 0x77, 0x76, NN, NN, NN,
390 NN, NN, NN, NN, NN, NN, NN, NN,
391 NN, NN, NN, NN, NN, NN, NN, NN,
392 NN, NN, NN, NN, NN, NN, NN, NN,
393 NN, NN, NN, NN, NN, NN, NN, NN,
394 NN, NN, NN, NN, NN, NN, NN, NN,
395 NN, NN, NN, NN, NN, NN, NN, NN,
396 NN, NN, NN, NN, NN, NN, NN, NN,
397 NN, NN, NN, NN, NN, NN, NN, NN,
398 NN, NN, NN, NN, NN, NN, NN, NN,
399 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc,
400 NN, NN, NN, NN, NN, NN, NN, NN,
401 NN, NN, NN, NN, NN, NN, NN, NN,
402 NN, NN, NN, NN, NN, NN, NN, NN,
403 };
404 #endif
405
406 #define KEY_ERROR 0x01
407 #define PRESS 0x000
408 #define RELEASE 0x100
409 #define CODEMASK 0x0ff
410 #define ADDKEY(c) ibuf[nkeys++] = (c)
411 #define REP_DELAY1 400
412 #define REP_DELAYN 100
413
414 void
415 btkbd_input(struct bthidev *self, uint8_t *data, int len)
416 {
417 struct btkbd_softc *sc = (struct btkbd_softc *)self;
418 struct btkbd_data *ud = &sc->sc_ndata;
419 uint16_t ibuf[MAXKEYS];
420 uint32_t mod, omod;
421 int nkeys, i, j;
422 int key;
423 int s;
424
425 if (sc->sc_wskbd == NULL || sc->sc_enabled == 0)
426 return;
427
428
429 ud->modifiers = 0;
430 for (i = 0 ; i < sc->sc_nmod ; i++)
431 if (hid_get_data(data, &sc->sc_modloc[i]))
432 ud->modifiers |= sc->sc_mods[i].mask;
433
434
435 memcpy(ud->keycode, data + (sc->sc_keycodeloc.pos / 8),
436 sc->sc_nkeycode);
437
438 if (ud->keycode[0] == KEY_ERROR)
439 return;
440
441 nkeys = 0;
442 mod = ud->modifiers;
443 omod = sc->sc_odata.modifiers;
444 if (mod != omod)
445 for (i = 0 ; i < sc->sc_nmod ; i++)
446 if ((mod & sc->sc_mods[i].mask) !=
447 (omod & sc->sc_mods[i].mask))
448 ADDKEY(sc->sc_mods[i].key |
449 (mod & sc->sc_mods[i].mask
450 ? PRESS : RELEASE));
451
452 if (memcmp(ud->keycode, sc->sc_odata.keycode, sc->sc_nkeycode) != 0) {
453
454 for (i = 0 ; i < sc->sc_nkeycode ; i++) {
455 key = sc->sc_odata.keycode[i];
456 if (key == 0)
457 continue;
458
459 for (j = 0 ; j < sc->sc_nkeycode ; j++)
460 if (key == ud->keycode[j])
461 goto rfound;
462
463 ADDKEY(key | RELEASE);
464
465 rfound:
466 ;
467 }
468
469
470 for (i = 0 ; i < sc->sc_nkeycode ; i++) {
471 key = ud->keycode[i];
472 if (key == 0)
473 continue;
474
475 for (j = 0; j < sc->sc_nkeycode; j++)
476 if (key == sc->sc_odata.keycode[j])
477 goto pfound;
478
479 ADDKEY(key | PRESS);
480 pfound:
481 ;
482 }
483 }
484 sc->sc_odata = *ud;
485
486 if (nkeys == 0)
487 return;
488
489 #ifdef WSDISPLAY_COMPAT_RAWKBD
490 if (sc->sc_rawkbd) {
491 u_char cbuf[MAXKEYS * 2];
492 int c;
493 int npress;
494
495 for (npress = i = j = 0 ; i < nkeys ; i++) {
496 key = ibuf[i];
497 c = btkbd_trtab[key & CODEMASK];
498 if (c == NN)
499 continue;
500
501 if (c & 0x80)
502 cbuf[j++] = 0xe0;
503
504 cbuf[j] = c & 0x7f;
505 if (key & RELEASE)
506 cbuf[j] |= 0x80;
507 #ifdef BTKBD_REPEAT
508 else {
509
510 if (c & 0x80)
511 sc->sc_rep[npress++] = 0xe0;
512
513 sc->sc_rep[npress++] = c & 0x7f;
514 }
515 #endif
516
517 j++;
518 }
519
520 s = spltty();
521 wskbd_rawinput(sc->sc_wskbd, cbuf, j);
522 splx(s);
523 #ifdef BTKBD_REPEAT
524 timeout_del(&sc->sc_repeat);
525 if (npress != 0) {
526 sc->sc_nrep = npress;
527 timeout_del(&sc->sc_repeat);
528 timeout_set(&sc->sc_repeat, btkbd_repeat, sc);
529 timeout_add(&sc->sc_repeat, hz * REP_DELAY1 / 1000);
530 }
531 #endif
532 return;
533 }
534 #endif
535
536 s = spltty();
537 for (i = 0 ; i < nkeys ; i++) {
538 key = ibuf[i];
539 wskbd_input(sc->sc_wskbd,
540 key & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN,
541 key & CODEMASK);
542 }
543 splx(s);
544 }
545
546 #ifdef WSDISPLAY_COMPAT_RAWKBD
547 #ifdef BTKBD_REPEAT
548 void
549 btkbd_repeat(void *arg)
550 {
551 struct btkbd_softc *sc = arg;
552 int s;
553
554 s = spltty();
555 wskbd_rawinput(sc->sc_wskbd, sc->sc_rep, sc->sc_nrep);
556 splx(s);
557 timeout_del(&sc->sc_repeat);
558 timeout_set(&sc->sc_repeat, btkbd_repeat, sc);
559 timeout_add(&sc->sc_repeat, hz * REP_DELAYN / 1000);
560 }
561 #endif
562 #endif