ukbd.c revision 1.112 1 /* $NetBSD: ukbd.c,v 1.112 2011/11/02 08:49:08 macallan 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 Lennart Augustsson (lennart (at) augustsson.net) at
9 * Carlstedt Research & Technology.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
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.
19 *
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.
31 */
32
33 /*
34 * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: ukbd.c,v 1.112 2011/11/02 08:49:08 macallan Exp $");
39
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>
46 #include <sys/file.h>
47 #include <sys/select.h>
48 #include <sys/proc.h>
49 #include <sys/vnode.h>
50 #include <sys/poll.h>
51
52 #include <dev/usb/usb.h>
53 #include <dev/usb/usbhid.h>
54
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>
62
63 #include <dev/wscons/wsconsio.h>
64 #include <dev/wscons/wskbdvar.h>
65 #include <dev/wscons/wsksymdef.h>
66 #include <dev/wscons/wsksymvar.h>
67
68 #ifdef _KERNEL_OPT
69 #include "opt_ukbd_layout.h"
70 #include "opt_wsdisplay_compat.h"
71 #include "opt_ddb.h"
72 #endif /* _KERNEL_OPT */
73
74 #ifdef UKBD_DEBUG
75 #define DPRINTF(x) if (ukbddebug) printf x
76 #define DPRINTFN(n,x) if (ukbddebug>(n)) printf x
77 int ukbddebug = 0;
78 #else
79 #define DPRINTF(x)
80 #define DPRINTFN(n,x)
81 #endif
82
83 #define MAXKEYCODE 6
84 #define MAXMOD 8 /* max 32 */
85
86 struct ukbd_data {
87 u_int32_t modifiers;
88 u_int8_t keycode[MAXKEYCODE];
89 };
90
91 #define PRESS 0x000
92 #define RELEASE 0x100
93 #define CODEMASK 0x0ff
94
95 struct ukbd_keycodetrans {
96 u_int16_t from;
97 u_int16_t to;
98 };
99
100 #define IS_PMF 0x8000
101
102 Static const struct ukbd_keycodetrans trtab_apple_fn[] = {
103 { 0x0c, 0x5d }, /* i -> KP 5 */
104 { 0x0d, 0x59 }, /* j -> KP 1 */
105 { 0x0e, 0x5a }, /* k -> KP 2 */
106 { 0x0f, 0x5b }, /* l -> KP 3 */
107 { 0x10, 0x62 }, /* m -> KP 0 */
108 { 0x12, 0x5e }, /* o -> KP 6 */
109 { 0x13, 0x55 }, /* o -> KP * */
110 { 0x18, 0x5c }, /* u -> KP 4 */
111 { 0x0c, 0x5d }, /* i -> KP 5 */
112 { 0x2a, 0x4c }, /* Backspace -> Delete */
113 { 0x28, 0x49 }, /* Return -> Insert */
114 { 0x24, 0x5f }, /* 7 -> KP 7 */
115 { 0x25, 0x60 }, /* 8 -> KP 8 */
116 { 0x26, 0x61 }, /* 9 -> KP 9 */
117 { 0x27, 0x54 }, /* 0 -> KP / */
118 { 0x2d, 0x67 }, /* - -> KP = */
119 { 0x33, 0x56 }, /* ; -> KP - */
120 { 0x37, 0x63 }, /* . -> KP . */
121 { 0x38, 0x57 }, /* / -> KP + */
122 { 0x3a, 0xd1 }, /* F1..F12 mapped to reserved codes 0xd1..0xdc */
123 { 0x3b, 0xd2 },
124 { 0x3c, 0xd3 },
125 { 0x3d, 0xd4 },
126 { 0x3e, 0xd5 },
127 { 0x3f, 0xd6 },
128 { 0x40, 0xd7 },
129 { 0x41, 0xd8 },
130 { 0x42, 0xd9 },
131 { 0x43, 0xda },
132 { 0x44, 0xdb },
133 { 0x45, 0xdc },
134 { 0x4f, 0x4d }, /* Right -> End */
135 { 0x50, 0x4a }, /* Left -> Home */
136 { 0x51, 0x4e }, /* Down -> PageDown */
137 { 0x52, 0x4b }, /* Up -> PageUp */
138 { 0x00, 0x00 }
139 };
140
141 Static const struct ukbd_keycodetrans trtab_apple_iso[] = {
142 { 0x35, 0x64 }, /* swap the key above tab with key right of shift */
143 { 0x64, 0x35 },
144 { 0x31, 0x32 }, /* key left of return is Europe1, not "\|" */
145 { 0x00, 0x00 }
146 };
147
148 Static const struct ukbd_keycodetrans trtab_gdium_fn[] = {
149 #ifdef notyet
150 { 58, 0 }, /* F1 -> toggle camera */
151 { 59, 0 }, /* F2 -> toggle wireless */
152 #endif
153 { 60, IS_PMF | PMFE_AUDIO_VOLUME_TOGGLE },
154 { 61, IS_PMF | PMFE_AUDIO_VOLUME_UP },
155 { 62, IS_PMF | PMFE_AUDIO_VOLUME_DOWN },
156 #ifdef notyet
157 { 63, 0 }, /* F6 -> toggle ext. video */
158 { 64, 0 }, /* F7 -> toggle mouse */
159 #endif
160 { 65, IS_PMF | PMFE_DISPLAY_BRIGHTNESS_UP },
161 { 66, IS_PMF | PMFE_DISPLAY_BRIGHTNESS_DOWN },
162 #ifdef notyet
163 { 67, 0 }, /* F10 -> suspend */
164 { 68, 0 }, /* F11 -> user1 */
165 { 69, 0 }, /* F12 -> user2 */
166 { 70, 0 }, /* print screen -> sysrq */
167 #endif
168 { 76, 71 }, /* delete -> scroll lock */
169 { 81, 78 }, /* down -> page down */
170 { 82, 75 } /* up -> page up */
171 };
172
173 #if defined(__NetBSD__) && defined(WSDISPLAY_COMPAT_RAWKBD)
174 #define NN 0 /* no translation */
175 /*
176 * Translate USB keycodes to US keyboard XT scancodes.
177 * Scancodes >= 0x80 represent EXTENDED keycodes.
178 *
179 * See http://www.microsoft.com/whdc/archive/scancode.mspx
180 *
181 * Note: a real pckbd(4) has more complexity in its
182 * protocol for some keys than this translation implements.
183 * For example, some keys generate Fake ShiftL events (e0 2a)
184 * before the actual key sequence.
185 */
186 Static const u_int8_t ukbd_trtab[256] = {
187 NN, NN, NN, NN, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */
188 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */
189 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */
190 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */
191 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */
192 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */
193 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */
194 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */
195 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xb7, 0x46, /* 40 - 47 */
196 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */
197 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */
198 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */
199 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, NN, 0x59, /* 60 - 67 */
200 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, NN, /* 68 - 6f */
201 NN, NN, NN, NN, NN, NN, NN, NN, /* 70 - 77 */
202 NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7f */
203 NN, NN, NN, NN, NN, 0x7e, NN, 0x73, /* 80 - 87 */
204 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN, NN, NN, /* 88 - 8f */
205 NN, NN, 0x78, 0x77, 0x76, NN, NN, NN, /* 90 - 97 */
206 NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9f */
207 NN, NN, NN, NN, NN, NN, NN, NN, /* a0 - a7 */
208 NN, NN, NN, NN, NN, NN, NN, NN, /* a8 - af */
209 NN, NN, NN, NN, NN, NN, NN, NN, /* b0 - b7 */
210 NN, NN, NN, NN, NN, NN, NN, NN, /* b8 - bf */
211 NN, NN, NN, NN, NN, NN, NN, NN, /* c0 - c7 */
212 NN, NN, NN, NN, NN, NN, NN, NN, /* c8 - cf */
213 NN, NN, NN, NN, NN, NN, NN, NN, /* d0 - d7 */
214 NN, NN, NN, NN, NN, NN, NN, NN, /* d8 - df */
215 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* e0 - e7 */
216 NN, NN, NN, NN, NN, NN, NN, NN, /* e8 - ef */
217 NN, NN, NN, NN, NN, NN, NN, NN, /* f0 - f7 */
218 NN, NN, NN, NN, NN, NN, NN, NN, /* f8 - ff */
219 };
220 #endif /* defined(__NetBSD__) && defined(WSDISPLAY_COMPAT_RAWKBD) */
221
222 #define KEY_ERROR 0x01
223
224 #define MAXKEYS (MAXMOD+2*MAXKEYCODE)
225
226 struct ukbd_softc {
227 struct uhidev sc_hdev;
228
229 struct ukbd_data sc_ndata;
230 struct ukbd_data sc_odata;
231 struct hid_location sc_modloc[MAXMOD];
232 u_int sc_nmod;
233 struct {
234 u_int32_t mask;
235 u_int8_t key;
236 } sc_mods[MAXMOD];
237
238 struct hid_location sc_keycodeloc;
239 u_int sc_nkeycode;
240
241 u_int sc_flags; /* flags */
242 #define FLAG_ENABLED 0x0001
243 #define FLAG_POLLING 0x0002
244 #define FLAG_DEBOUNCE 0x0004 /* for quirk handling */
245 #define FLAG_APPLE_FIX_ISO 0x0008
246 #define FLAG_APPLE_FN 0x0010
247 #define FLAG_GDIUM_FN 0x0020
248 #define FLAG_FN_PRESSED 0x0100 /* FN key is held down */
249 #define FLAG_FN_ALT 0x0200 /* Last Alt key was FN-Alt = AltGr */
250
251 int sc_console_keyboard; /* we are the console keyboard */
252
253 struct callout sc_delay; /* for quirk handling */
254 struct ukbd_data sc_data; /* for quirk handling */
255
256 struct hid_location sc_apple_fn;
257 struct hid_location sc_numloc;
258 struct hid_location sc_capsloc;
259 struct hid_location sc_scroloc;
260 int sc_leds;
261 #if defined(__NetBSD__)
262 device_t sc_wskbddev;
263
264 #if defined(WSDISPLAY_COMPAT_RAWKBD)
265 int sc_rawkbd;
266 #if defined(UKBD_REPEAT)
267 struct callout sc_rawrepeat_ch;
268 #define REP_DELAY1 400
269 #define REP_DELAYN 100
270 int sc_nrep;
271 char sc_rep[MAXKEYS];
272 #endif /* defined(UKBD_REPEAT) */
273 #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */
274
275 int sc_spl;
276 int sc_npollchar;
277 u_int16_t sc_pollchars[MAXKEYS];
278 #endif /* defined(__NetBSD__) */
279
280 u_char sc_dying;
281 };
282
283 #ifdef UKBD_DEBUG
284 #define UKBDTRACESIZE 64
285 struct ukbdtraceinfo {
286 int unit;
287 struct timeval tv;
288 struct ukbd_data ud;
289 };
290 struct ukbdtraceinfo ukbdtracedata[UKBDTRACESIZE];
291 int ukbdtraceindex = 0;
292 int ukbdtrace = 0;
293 void ukbdtracedump(void);
294 void
295 ukbdtracedump(void)
296 {
297 int i;
298 for (i = 0; i < UKBDTRACESIZE; i++) {
299 struct ukbdtraceinfo *p =
300 &ukbdtracedata[(i+ukbdtraceindex)%UKBDTRACESIZE];
301 printf("%"PRIu64".%06"PRIu64": mod=0x%02x key0=0x%02x key1=0x%02x "
302 "key2=0x%02x key3=0x%02x\n",
303 p->tv.tv_sec, (uint64_t)p->tv.tv_usec,
304 p->ud.modifiers, p->ud.keycode[0], p->ud.keycode[1],
305 p->ud.keycode[2], p->ud.keycode[3]);
306 }
307 }
308 #endif
309
310 #define UKBDUNIT(dev) (minor(dev))
311 #define UKBD_CHUNK 128 /* chunk size for read */
312 #define UKBD_BSIZE 1020 /* buffer size */
313
314 Static int ukbd_is_console;
315
316 Static void ukbd_cngetc(void *, u_int *, int *);
317 Static void ukbd_cnpollc(void *, int);
318
319 #if defined(__NetBSD__)
320 const struct wskbd_consops ukbd_consops = {
321 ukbd_cngetc,
322 ukbd_cnpollc,
323 NULL, /* bell */
324 };
325 #endif
326
327 Static const char *ukbd_parse_desc(struct ukbd_softc *sc);
328
329 Static void ukbd_intr(struct uhidev *addr, void *ibuf, u_int len);
330 Static void ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud);
331 Static void ukbd_delayed_decode(void *addr);
332
333 Static int ukbd_enable(void *, int);
334 Static void ukbd_set_leds(void *, int);
335
336 #if defined(__NetBSD__)
337 Static int ukbd_ioctl(void *, u_long, void *, int, struct lwp *);
338 #if defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT)
339 Static void ukbd_rawrepeat(void *v);
340 #endif
341
342 const struct wskbd_accessops ukbd_accessops = {
343 ukbd_enable,
344 ukbd_set_leds,
345 ukbd_ioctl,
346 };
347
348 extern const struct wscons_keydesc ukbd_keydesctab[];
349
350 const struct wskbd_mapdata ukbd_keymapdata = {
351 ukbd_keydesctab,
352 #if defined(UKBD_LAYOUT)
353 UKBD_LAYOUT,
354 #elif defined(PCKBD_LAYOUT)
355 PCKBD_LAYOUT,
356 #else
357 KB_US,
358 #endif
359 };
360 #endif
361
362 static int ukbd_match(device_t, cfdata_t, void *);
363 static void ukbd_attach(device_t, device_t, void *);
364 static int ukbd_detach(device_t, int);
365 static int ukbd_activate(device_t, enum devact);
366 static void ukbd_childdet(device_t, device_t);
367
368 extern struct cfdriver ukbd_cd;
369
370 CFATTACH_DECL2_NEW(ukbd, sizeof(struct ukbd_softc), ukbd_match, ukbd_attach,
371 ukbd_detach, ukbd_activate, NULL, ukbd_childdet);
372
373 int
374 ukbd_match(device_t parent, cfdata_t match, void *aux)
375 {
376 struct uhidev_attach_arg *uha = aux;
377 int size;
378 void *desc;
379
380 uhidev_get_report_desc(uha->parent, &desc, &size);
381 if (!hid_is_collection(desc, size, uha->reportid,
382 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
383 return (UMATCH_NONE);
384
385 return (UMATCH_IFACECLASS);
386 }
387
388 void
389 ukbd_attach(device_t parent, device_t self, void *aux)
390 {
391 struct ukbd_softc *sc = device_private(self);
392 struct uhidev_attach_arg *uha = aux;
393 u_int32_t qflags;
394 const char *parseerr;
395 #if defined(__NetBSD__)
396 struct wskbddev_attach_args a;
397 #else
398 int i;
399 #endif
400
401 sc->sc_hdev.sc_dev = self;
402 sc->sc_hdev.sc_intr = ukbd_intr;
403 sc->sc_hdev.sc_parent = uha->parent;
404 sc->sc_hdev.sc_report_id = uha->reportid;
405 sc->sc_flags = 0;
406
407 if (!pmf_device_register(self, NULL, NULL)) {
408 aprint_normal("\n");
409 aprint_error_dev(self, "couldn't establish power handler\n");
410 }
411
412 parseerr = ukbd_parse_desc(sc);
413 if (parseerr != NULL) {
414 aprint_normal("\n");
415 aprint_error_dev(self, "attach failed, %s\n", parseerr);
416 return;
417 }
418
419 /* Quirks */
420 qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
421 if (qflags & UQ_SPUR_BUT_UP)
422 sc->sc_flags |= FLAG_DEBOUNCE;
423 if (qflags & UQ_APPLE_ISO)
424 sc->sc_flags |= FLAG_APPLE_FIX_ISO;
425
426 if (uha->uaa->vendor == USB_VENDOR_CYPRESS &&
427 uha->uaa->product == USB_PRODUCT_CYPRESS_LPRDK)
428 sc->sc_flags = FLAG_GDIUM_FN;
429
430 #ifdef DIAGNOSTIC
431 aprint_normal(": %d modifier keys, %d key codes", sc->sc_nmod,
432 sc->sc_nkeycode);
433 if (sc->sc_flags & FLAG_APPLE_FN)
434 aprint_normal(", apple fn key");
435 if (sc->sc_flags & FLAG_APPLE_FIX_ISO)
436 aprint_normal(", fix apple iso");
437 if (sc->sc_flags & FLAG_GDIUM_FN)
438 aprint_normal(", Gdium fn key");
439 #endif
440 aprint_normal("\n");
441
442 /*
443 * Remember if we're the console keyboard.
444 *
445 * XXX This always picks the first keyboard on the
446 * first USB bus, but what else can we really do?
447 */
448 if ((sc->sc_console_keyboard = ukbd_is_console) != 0) {
449 /* Don't let any other keyboard have it. */
450 ukbd_is_console = 0;
451 }
452
453 if (sc->sc_console_keyboard) {
454 DPRINTF(("ukbd_attach: console keyboard sc=%p\n", sc));
455 wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata);
456 ukbd_enable(sc, 1);
457 }
458
459 a.console = sc->sc_console_keyboard;
460
461 a.keymap = &ukbd_keymapdata;
462
463 a.accessops = &ukbd_accessops;
464 a.accesscookie = sc;
465
466 #ifdef UKBD_REPEAT
467 callout_init(&sc->sc_rawrepeat_ch, 0);
468 #endif
469
470 callout_init(&sc->sc_delay, 0);
471
472 /* Flash the leds; no real purpose, just shows we're alive. */
473 ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS);
474 usbd_delay_ms(uha->parent->sc_udev, 400);
475 ukbd_set_leds(sc, 0);
476
477 sc->sc_wskbddev = config_found(self, &a, wskbddevprint);
478
479 return;
480 }
481
482 int
483 ukbd_enable(void *v, int on)
484 {
485 struct ukbd_softc *sc = v;
486
487 if (on && sc->sc_dying)
488 return (EIO);
489
490 /* Should only be called to change state */
491 if ((sc->sc_flags & FLAG_ENABLED) != 0 && on != 0) {
492 #ifdef DIAGNOSTIC
493 printf("ukbd_enable: %s: bad call on=%d\n",
494 device_xname(sc->sc_hdev.sc_dev), on);
495 #endif
496 return (EBUSY);
497 }
498
499 DPRINTF(("ukbd_enable: sc=%p on=%d\n", sc, on));
500 if (on) {
501 sc->sc_flags |= FLAG_ENABLED;
502 return (uhidev_open(&sc->sc_hdev));
503 } else {
504 sc->sc_flags &= ~FLAG_ENABLED;
505 uhidev_close(&sc->sc_hdev);
506 return (0);
507 }
508 }
509
510
511 static void
512 ukbd_childdet(device_t self, device_t child)
513 {
514 struct ukbd_softc *sc = device_private(self);
515
516 KASSERT(sc->sc_wskbddev == child);
517 sc->sc_wskbddev = NULL;
518 }
519
520 int
521 ukbd_activate(device_t self, enum devact act)
522 {
523 struct ukbd_softc *sc = device_private(self);
524
525 switch (act) {
526 case DVACT_DEACTIVATE:
527 sc->sc_dying = 1;
528 return 0;
529 default:
530 return EOPNOTSUPP;
531 }
532 }
533
534 int
535 ukbd_detach(device_t self, int flags)
536 {
537 struct ukbd_softc *sc = device_private(self);
538 int rv = 0;
539
540 DPRINTF(("ukbd_detach: sc=%p flags=%d\n", sc, flags));
541
542 pmf_device_deregister(self);
543
544 if (sc->sc_console_keyboard) {
545 #if 0
546 /*
547 * XXX Should probably disconnect our consops,
548 * XXX and either notify some other keyboard that
549 * XXX it can now be the console, or if there aren't
550 * XXX any more USB keyboards, set ukbd_is_console
551 * XXX back to 1 so that the next USB keyboard attached
552 * XXX to the system will get it.
553 */
554 panic("ukbd_detach: console keyboard");
555 #else
556 /*
557 * Disconnect our consops and set ukbd_is_console
558 * back to 1 so that the next USB keyboard attached
559 * to the system will get it.
560 * XXX Should notify some other keyboard that it can be
561 * XXX console, if there are any other keyboards.
562 */
563 printf("%s: was console keyboard\n",
564 device_xname(sc->sc_hdev.sc_dev));
565 wskbd_cndetach();
566 ukbd_is_console = 1;
567 #endif
568 }
569 /* No need to do reference counting of ukbd, wskbd has all the goo. */
570 if (sc->sc_wskbddev != NULL)
571 rv = config_detach(sc->sc_wskbddev, flags);
572
573 /* The console keyboard does not get a disable call, so check pipe. */
574 if (sc->sc_hdev.sc_state & UHIDEV_OPEN)
575 uhidev_close(&sc->sc_hdev);
576
577 return (rv);
578 }
579
580 static void
581 ukbd_translate_keycodes(struct ukbd_softc *sc, struct ukbd_data *ud,
582 const struct ukbd_keycodetrans *tab)
583 {
584 const struct ukbd_keycodetrans *tp;
585 int i;
586 u_int8_t key;
587
588 for (i = 0; i < sc->sc_nkeycode; i++) {
589 key = ud->keycode[i];
590 if (key)
591 for (tp = tab; tp->from; tp++)
592 if (tp->from == key) {
593 if (tp->to & IS_PMF) {
594 pmf_event_inject(
595 sc->sc_hdev.sc_dev,
596 tp->to & 0xff);
597 ud->keycode[i] = 0;
598 } else
599 ud->keycode[i] = tp->to;
600 break;
601 }
602 }
603 }
604
605 static u_int16_t
606 ukbd_translate_modifier(struct ukbd_softc *sc, u_int16_t key)
607 {
608 if ((sc->sc_flags & FLAG_APPLE_FN) && (key & CODEMASK) == 0x00e2) {
609 if ((key & ~CODEMASK) == PRESS) {
610 if (sc->sc_flags & FLAG_FN_PRESSED) {
611 /* pressed FN-Alt, translate to AltGr */
612 key = 0x00e6 | PRESS;
613 sc->sc_flags |= FLAG_FN_ALT;
614 }
615 } else {
616 if (sc->sc_flags & FLAG_FN_ALT) {
617 /* released Alt, which was treated as FN-Alt */
618 key = 0x00e6 | RELEASE;
619 sc->sc_flags &= ~FLAG_FN_ALT;
620 }
621 }
622 }
623 return key;
624 }
625
626 void
627 ukbd_intr(struct uhidev *addr, void *ibuf, u_int len)
628 {
629 struct ukbd_softc *sc = (struct ukbd_softc *)addr;
630 struct ukbd_data *ud = &sc->sc_ndata;
631 int i;
632
633 #ifdef UKBD_DEBUG
634 if (ukbddebug > 5) {
635 printf("ukbd_intr: data");
636 for (i = 0; i < len; i++)
637 printf(" 0x%02x", ((u_char *)ibuf)[i]);
638 printf("\n");
639 }
640 #endif
641
642 ud->modifiers = 0;
643 for (i = 0; i < sc->sc_nmod; i++)
644 if (hid_get_data(ibuf, &sc->sc_modloc[i]))
645 ud->modifiers |= sc->sc_mods[i].mask;
646 memcpy(ud->keycode, (char *)ibuf + sc->sc_keycodeloc.pos / 8,
647 sc->sc_nkeycode);
648
649 if (sc->sc_flags & FLAG_APPLE_FN) {
650 if (hid_get_data(ibuf, &sc->sc_apple_fn)) {
651 sc->sc_flags |= FLAG_FN_PRESSED;
652 ukbd_translate_keycodes(sc, ud, trtab_apple_fn);
653 }
654 else
655 sc->sc_flags &= ~FLAG_FN_PRESSED;
656 }
657
658 if (sc->sc_flags & FLAG_GDIUM_FN) {
659 if (sc->sc_flags & FLAG_FN_PRESSED) {
660 ukbd_translate_keycodes(sc, ud, trtab_gdium_fn);
661 }
662 }
663
664 if ((sc->sc_flags & FLAG_DEBOUNCE) && !(sc->sc_flags & FLAG_POLLING)) {
665 /*
666 * Some keyboards have a peculiar quirk. They sometimes
667 * generate a key up followed by a key down for the same
668 * key after about 10 ms.
669 * We avoid this bug by holding off decoding for 20 ms.
670 */
671 sc->sc_data = *ud;
672 callout_reset(&sc->sc_delay, hz / 50, ukbd_delayed_decode, sc);
673 #ifdef DDB
674 } else if (sc->sc_console_keyboard && !(sc->sc_flags & FLAG_POLLING)) {
675 /*
676 * For the console keyboard we can't deliver CTL-ALT-ESC
677 * from the interrupt routine. Doing so would start
678 * polling from inside the interrupt routine and that
679 * loses bigtime.
680 */
681 sc->sc_data = *ud;
682 callout_reset(&sc->sc_delay, 1, ukbd_delayed_decode, sc);
683 #endif
684 } else {
685 ukbd_decode(sc, ud);
686 }
687 }
688
689 void
690 ukbd_delayed_decode(void *addr)
691 {
692 struct ukbd_softc *sc = addr;
693
694 ukbd_decode(sc, &sc->sc_data);
695 }
696
697 void
698 ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud)
699 {
700 int mod, omod;
701 u_int16_t ibuf[MAXKEYS]; /* chars events */
702 int s;
703 int nkeys, i, j;
704 int key;
705 #define ADDKEY(c) ibuf[nkeys++] = (c)
706
707 #ifdef UKBD_DEBUG
708 /*
709 * Keep a trace of the last events. Using printf changes the
710 * timing, so this can be useful sometimes.
711 */
712 if (ukbdtrace) {
713 struct ukbdtraceinfo *p = &ukbdtracedata[ukbdtraceindex];
714 p->unit = device_unit(sc->sc_hdev.sc_dev);
715 microtime(&p->tv);
716 p->ud = *ud;
717 if (++ukbdtraceindex >= UKBDTRACESIZE)
718 ukbdtraceindex = 0;
719 }
720 if (ukbddebug > 5) {
721 struct timeval tv;
722 microtime(&tv);
723 DPRINTF((" at %"PRIu64".%06"PRIu64" mod=0x%02x key0=0x%02x key1=0x%02x "
724 "key2=0x%02x key3=0x%02x\n",
725 tv.tv_sec, (uint64_t)tv.tv_usec,
726 ud->modifiers, ud->keycode[0], ud->keycode[1],
727 ud->keycode[2], ud->keycode[3]));
728 }
729 #endif
730
731 if (ud->keycode[0] == KEY_ERROR) {
732 DPRINTF(("ukbd_intr: KEY_ERROR\n"));
733 return; /* ignore */
734 }
735
736 if (sc->sc_flags & FLAG_APPLE_FIX_ISO)
737 ukbd_translate_keycodes(sc, ud, trtab_apple_iso);
738
739 nkeys = 0;
740 mod = ud->modifiers;
741 omod = sc->sc_odata.modifiers;
742 if (mod != omod)
743 for (i = 0; i < sc->sc_nmod; i++)
744 if (( mod & sc->sc_mods[i].mask) !=
745 (omod & sc->sc_mods[i].mask)) {
746 key = sc->sc_mods[i].key |
747 ((mod & sc->sc_mods[i].mask) ?
748 PRESS : RELEASE);
749 ADDKEY(ukbd_translate_modifier(sc, key));
750 }
751 if (memcmp(ud->keycode, sc->sc_odata.keycode, sc->sc_nkeycode) != 0) {
752 /* Check for released keys. */
753 for (i = 0; i < sc->sc_nkeycode; i++) {
754 key = sc->sc_odata.keycode[i];
755 if (key == 0)
756 continue;
757 for (j = 0; j < sc->sc_nkeycode; j++)
758 if (key == ud->keycode[j])
759 goto rfound;
760 DPRINTFN(3,("ukbd_intr: relse key=0x%02x\n", key));
761 if (sc->sc_flags & FLAG_GDIUM_FN) {
762 if (key == 0x82) {
763 sc->sc_flags &= ~FLAG_FN_PRESSED;
764 goto rfound;
765 }
766 }
767 ADDKEY(key | RELEASE);
768 rfound:
769 ;
770 }
771
772 /* Check for pressed keys. */
773 for (i = 0; i < sc->sc_nkeycode; i++) {
774 key = ud->keycode[i];
775 if (key == 0)
776 continue;
777 for (j = 0; j < sc->sc_nkeycode; j++)
778 if (key == sc->sc_odata.keycode[j])
779 goto pfound;
780 DPRINTFN(2,("ukbd_intr: press key=0x%02x\n", key));
781 if (sc->sc_flags & FLAG_GDIUM_FN) {
782 if (key == 0x82) {
783 sc->sc_flags |= FLAG_FN_PRESSED;
784 goto pfound;
785 }
786 }
787 ADDKEY(key | PRESS);
788 pfound:
789 ;
790 }
791 }
792 sc->sc_odata = *ud;
793
794 if (nkeys == 0)
795 return;
796
797 if (sc->sc_flags & FLAG_POLLING) {
798 DPRINTFN(1,("ukbd_intr: pollchar = 0x%03x\n", ibuf[0]));
799 memcpy(sc->sc_pollchars, ibuf, nkeys * sizeof(u_int16_t));
800 sc->sc_npollchar = nkeys;
801 return;
802 }
803 #ifdef WSDISPLAY_COMPAT_RAWKBD
804 if (sc->sc_rawkbd) {
805 u_char cbuf[MAXKEYS * 2];
806 int c;
807 int npress;
808
809 for (npress = i = j = 0; i < nkeys; i++) {
810 key = ibuf[i];
811 c = ukbd_trtab[key & CODEMASK];
812 if (c == NN)
813 continue;
814 if (c == 0x7f) {
815 /* pause key */
816 cbuf[j++] = 0xe1;
817 cbuf[j++] = 0x1d;
818 cbuf[j-1] |= (key & RELEASE) ? 0x80 : 0;
819 cbuf[j] = 0x45;
820 } else {
821 if (c & 0x80)
822 cbuf[j++] = 0xe0;
823 cbuf[j] = c & 0x7f;
824 }
825 if (key & RELEASE)
826 cbuf[j] |= 0x80;
827 #if defined(UKBD_REPEAT)
828 else {
829 /* remember pressed keys for autorepeat */
830 if (c & 0x80)
831 sc->sc_rep[npress++] = 0xe0;
832 sc->sc_rep[npress++] = c & 0x7f;
833 }
834 #endif
835 DPRINTFN(1,("ukbd_intr: raw = %s0x%02x\n",
836 c & 0x80 ? "0xe0 " : "",
837 cbuf[j]));
838 j++;
839 }
840 s = spltty();
841 wskbd_rawinput(sc->sc_wskbddev, cbuf, j);
842 splx(s);
843 #ifdef UKBD_REPEAT
844 callout_stop(&sc->sc_rawrepeat_ch);
845 if (npress != 0) {
846 sc->sc_nrep = npress;
847 callout_reset(&sc->sc_rawrepeat_ch,
848 hz * REP_DELAY1 / 1000, ukbd_rawrepeat, sc);
849 }
850 #endif
851 return;
852 }
853 #endif
854
855 s = spltty();
856 for (i = 0; i < nkeys; i++) {
857 key = ibuf[i];
858 wskbd_input(sc->sc_wskbddev,
859 key&RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN,
860 key&CODEMASK);
861 }
862 splx(s);
863 }
864
865 void
866 ukbd_set_leds(void *v, int leds)
867 {
868 struct ukbd_softc *sc = v;
869 u_int8_t res;
870
871 DPRINTF(("ukbd_set_leds: sc=%p leds=%d, sc_leds=%d\n",
872 sc, leds, sc->sc_leds));
873
874 if (sc->sc_dying)
875 return;
876
877 if (sc->sc_leds == leds)
878 return;
879 sc->sc_leds = leds;
880 res = 0;
881 /* XXX not really right */
882 if ((leds & WSKBD_LED_SCROLL) && sc->sc_scroloc.size == 1)
883 res |= 1 << sc->sc_scroloc.pos;
884 if ((leds & WSKBD_LED_NUM) && sc->sc_numloc.size == 1)
885 res |= 1 << sc->sc_numloc.pos;
886 if ((leds & WSKBD_LED_CAPS) && sc->sc_capsloc.size == 1)
887 res |= 1 << sc->sc_capsloc.pos;
888 uhidev_set_report_async(&sc->sc_hdev, UHID_OUTPUT_REPORT, &res, 1);
889 }
890
891 #if defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT)
892 void
893 ukbd_rawrepeat(void *v)
894 {
895 struct ukbd_softc *sc = v;
896 int s;
897
898 s = spltty();
899 wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep);
900 splx(s);
901 callout_reset(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000,
902 ukbd_rawrepeat, sc);
903 }
904 #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) && defined(UKBD_REPEAT) */
905
906 int
907 ukbd_ioctl(void *v, u_long cmd, void *data, int flag,
908 struct lwp *l)
909 {
910 struct ukbd_softc *sc = v;
911
912 switch (cmd) {
913 case WSKBDIO_GTYPE:
914 *(int *)data = WSKBD_TYPE_USB;
915 return (0);
916 case WSKBDIO_SETLEDS:
917 ukbd_set_leds(v, *(int *)data);
918 return (0);
919 case WSKBDIO_GETLEDS:
920 *(int *)data = sc->sc_leds;
921 return (0);
922 #if defined(WSDISPLAY_COMPAT_RAWKBD)
923 case WSKBDIO_SETMODE:
924 DPRINTF(("ukbd_ioctl: set raw = %d\n", *(int *)data));
925 sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
926 #if defined(UKBD_REPEAT)
927 callout_stop(&sc->sc_rawrepeat_ch);
928 #endif
929 return (0);
930 #endif
931 }
932 return (EPASSTHROUGH);
933 }
934
935 /*
936 * This is a hack to work around some broken ports that don't call
937 * cnpollc() before cngetc().
938 */
939 static int pollenter, warned;
940
941 /* Console interface. */
942 void
943 ukbd_cngetc(void *v, u_int *type, int *data)
944 {
945 struct ukbd_softc *sc = v;
946 int c;
947 int broken;
948
949 if (pollenter == 0) {
950 if (!warned) {
951 printf("\n"
952 "This port is broken, it does not call cnpollc() before calling cngetc().\n"
953 "This should be fixed, but it will work anyway (for now).\n");
954 warned = 1;
955 }
956 broken = 1;
957 ukbd_cnpollc(v, 1);
958 } else
959 broken = 0;
960
961 DPRINTFN(0,("ukbd_cngetc: enter\n"));
962 sc->sc_flags |= FLAG_POLLING;
963 while(sc->sc_npollchar <= 0)
964 usbd_dopoll(sc->sc_hdev.sc_parent->sc_iface);
965 sc->sc_flags &= ~FLAG_POLLING;
966 c = sc->sc_pollchars[0];
967 sc->sc_npollchar--;
968 memcpy(sc->sc_pollchars, sc->sc_pollchars+1,
969 sc->sc_npollchar * sizeof(u_int16_t));
970 *type = c & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
971 *data = c & CODEMASK;
972 DPRINTFN(0,("ukbd_cngetc: return 0x%02x\n", c));
973 if (broken)
974 ukbd_cnpollc(v, 0);
975 }
976
977 void
978 ukbd_cnpollc(void *v, int on)
979 {
980 struct ukbd_softc *sc = v;
981 usbd_device_handle dev;
982
983 DPRINTFN(2,("ukbd_cnpollc: sc=%p on=%d\n", v, on));
984
985 usbd_interface2device_handle(sc->sc_hdev.sc_parent->sc_iface, &dev);
986 if (on) {
987 sc->sc_spl = splusb();
988 pollenter++;
989 } else {
990 splx(sc->sc_spl);
991 pollenter--;
992 }
993 usbd_set_polling(dev, on);
994 }
995
996 int
997 ukbd_cnattach(void)
998 {
999
1000 /*
1001 * XXX USB requires too many parts of the kernel to be running
1002 * XXX in order to work, so we can't do much for the console
1003 * XXX keyboard until autconfiguration has run its course.
1004 */
1005 ukbd_is_console = 1;
1006 return (0);
1007 }
1008
1009 const char *
1010 ukbd_parse_desc(struct ukbd_softc *sc)
1011 {
1012 struct hid_data *d;
1013 struct hid_item h;
1014 int size;
1015 void *desc;
1016 int imod;
1017
1018 uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size);
1019 imod = 0;
1020 sc->sc_nkeycode = 0;
1021 d = hid_start_parse(desc, size, hid_input);
1022 while (hid_get_item(d, &h)) {
1023 /*printf("ukbd: id=%d kind=%d usage=0x%x flags=0x%x pos=%d size=%d cnt=%d\n",
1024 h.report_ID, h.kind, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count);*/
1025
1026 /* Check for special Apple notebook FN key */
1027 if (HID_GET_USAGE_PAGE(h.usage) == 0x00ff &&
1028 HID_GET_USAGE(h.usage) == 0x0003 &&
1029 h.kind == hid_input && (h.flags & HIO_VARIABLE)) {
1030 sc->sc_flags |= FLAG_APPLE_FN;
1031 sc->sc_apple_fn = h.loc;
1032 }
1033
1034 if (h.kind != hid_input || (h.flags & HIO_CONST) ||
1035 HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD ||
1036 h.report_ID != sc->sc_hdev.sc_report_id)
1037 continue;
1038 DPRINTF(("ukbd: imod=%d usage=0x%x flags=0x%x pos=%d size=%d "
1039 "cnt=%d\n", imod,
1040 h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count));
1041 if (h.flags & HIO_VARIABLE) {
1042 if (h.loc.size != 1)
1043 return ("bad modifier size");
1044 /* Single item */
1045 if (imod < MAXMOD) {
1046 sc->sc_modloc[imod] = h.loc;
1047 sc->sc_mods[imod].mask = 1 << imod;
1048 sc->sc_mods[imod].key = HID_GET_USAGE(h.usage);
1049 imod++;
1050 } else
1051 return ("too many modifier keys");
1052 } else {
1053 /* Array */
1054 if (h.loc.size != 8)
1055 return ("key code size != 8");
1056 if (h.loc.count > MAXKEYCODE)
1057 h.loc.count = MAXKEYCODE;
1058 if (h.loc.pos % 8 != 0)
1059 return ("key codes not on byte boundary");
1060 if (sc->sc_nkeycode != 0)
1061 return ("multiple key code arrays\n");
1062 sc->sc_keycodeloc = h.loc;
1063 sc->sc_nkeycode = h.loc.count;
1064 }
1065 }
1066 sc->sc_nmod = imod;
1067 hid_end_parse(d);
1068
1069 hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK),
1070 sc->sc_hdev.sc_report_id, hid_output, &sc->sc_numloc, NULL);
1071 hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK),
1072 sc->sc_hdev.sc_report_id, hid_output, &sc->sc_capsloc, NULL);
1073 hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK),
1074 sc->sc_hdev.sc_report_id, hid_output, &sc->sc_scroloc, NULL);
1075
1076 return (NULL);
1077 }
1078