Line data Source code
1 : /* $OpenBSD: ukbd.c,v 1.78 2017/05/12 09:16:55 mpi Exp $ */
2 : /* $NetBSD: ukbd.c,v 1.85 2003/03/11 16:44:00 augustss Exp $ */
3 :
4 : /*
5 : * Copyright (c) 2010 Miodrag Vallat.
6 : *
7 : * Permission to use, copy, modify, and distribute this software for any
8 : * purpose with or without fee is hereby granted, provided that the above
9 : * copyright notice and this permission notice appear in all copies.
10 : *
11 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 : * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 : * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 : * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 : */
19 : /*
20 : * Copyright (c) 1998 The NetBSD Foundation, Inc.
21 : * All rights reserved.
22 : *
23 : * This code is derived from software contributed to The NetBSD Foundation
24 : * by Lennart Augustsson (lennart@augustsson.net) at
25 : * Carlstedt Research & Technology.
26 : *
27 : * Redistribution and use in source and binary forms, with or without
28 : * modification, are permitted provided that the following conditions
29 : * are met:
30 : * 1. Redistributions of source code must retain the above copyright
31 : * notice, this list of conditions and the following disclaimer.
32 : * 2. Redistributions in binary form must reproduce the above copyright
33 : * notice, this list of conditions and the following disclaimer in the
34 : * documentation and/or other materials provided with the distribution.
35 : *
36 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
37 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
38 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
40 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
41 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
42 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
43 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
44 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : * POSSIBILITY OF SUCH DAMAGE.
47 : */
48 :
49 : /*
50 : * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
51 : */
52 :
53 : #include <sys/param.h>
54 : #include <sys/systm.h>
55 : #include <sys/timeout.h>
56 : #include <sys/kernel.h>
57 : #include <sys/device.h>
58 : #include <sys/ioctl.h>
59 :
60 : #include <machine/bus.h>
61 :
62 : #include <dev/usb/usb.h>
63 : #include <dev/usb/usbhid.h>
64 :
65 : #include <dev/usb/usbdi.h>
66 : #include <dev/usb/usbdivar.h> /* needs_reattach() */
67 : #include <dev/usb/usbdi_util.h>
68 : #include <dev/usb/usbdevs.h>
69 : #include <dev/usb/usb_quirks.h>
70 : #include <dev/usb/uhidev.h>
71 : #include <dev/usb/ukbdvar.h>
72 :
73 : #include <dev/wscons/wsconsio.h>
74 : #include <dev/wscons/wskbdvar.h>
75 : #include <dev/wscons/wsksymdef.h>
76 : #include <dev/wscons/wsksymvar.h>
77 :
78 : #include <dev/hid/hidkbdsc.h>
79 :
80 : #ifdef UKBD_DEBUG
81 : #define DPRINTF(x) do { if (ukbddebug) printf x; } while (0)
82 : #define DPRINTFN(n,x) do { if (ukbddebug>(n)) printf x; } while (0)
83 : int ukbddebug = 0;
84 : #else
85 : #define DPRINTF(x)
86 : #define DPRINTFN(n,x)
87 : #endif
88 :
89 : const kbd_t ukbd_countrylayout[1 + HCC_MAX] = {
90 : (kbd_t)-1,
91 : (kbd_t)-1, /* arabic */
92 : KB_BE, /* belgian */
93 : (kbd_t)-1, /* canadian bilingual */
94 : KB_CF, /* canadian french */
95 : (kbd_t)-1, /* czech */
96 : KB_DK, /* danish */
97 : (kbd_t)-1, /* finnish */
98 : KB_FR, /* french */
99 : KB_DE, /* german */
100 : (kbd_t)-1, /* greek */
101 : (kbd_t)-1, /* hebrew */
102 : KB_HU, /* hungary */
103 : (kbd_t)-1, /* international (iso) */
104 : KB_IT, /* italian */
105 : KB_JP, /* japanese (katakana) */
106 : (kbd_t)-1, /* korean */
107 : KB_LA, /* latin american */
108 : (kbd_t)-1, /* netherlands/dutch */
109 : KB_NO, /* norwegian */
110 : (kbd_t)-1, /* persian (farsi) */
111 : KB_PL, /* polish */
112 : KB_PT, /* portuguese */
113 : KB_RU, /* russian */
114 : (kbd_t)-1, /* slovakia */
115 : KB_ES, /* spanish */
116 : KB_SV, /* swedish */
117 : KB_SF, /* swiss french */
118 : KB_SG, /* swiss german */
119 : (kbd_t)-1, /* switzerland */
120 : (kbd_t)-1, /* taiwan */
121 : KB_TR, /* turkish Q */
122 : KB_UK, /* uk */
123 : KB_US, /* us */
124 : (kbd_t)-1, /* yugoslavia */
125 : (kbd_t)-1 /* turkish F */
126 : };
127 :
128 : struct ukbd_softc {
129 : struct uhidev sc_hdev;
130 : #define sc_ledsize sc_hdev.sc_osize
131 :
132 : struct hidkbd sc_kbd;
133 : int sc_spl;
134 : struct hid_location sc_apple_fn;
135 : void (*sc_munge)(void *, uint8_t *, u_int);
136 :
137 : #ifdef DDB
138 : struct timeout sc_ddb; /* for entering DDB */
139 : #endif
140 : };
141 :
142 : void ukbd_cngetc(void *, u_int *, int *);
143 : void ukbd_cnpollc(void *, int);
144 : void ukbd_cnbell(void *, u_int, u_int, u_int);
145 : void ukbd_debugger(void *);
146 :
147 : const struct wskbd_consops ukbd_consops = {
148 : ukbd_cngetc,
149 : ukbd_cnpollc,
150 : ukbd_cnbell,
151 : #ifdef DDB
152 : ukbd_debugger,
153 : #endif
154 : };
155 :
156 : void ukbd_intr(struct uhidev *addr, void *ibuf, u_int len);
157 :
158 : void ukbd_db_enter(void *);
159 : int ukbd_enable(void *, int);
160 : void ukbd_set_leds(void *, int);
161 : int ukbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
162 :
163 : const struct wskbd_accessops ukbd_accessops = {
164 : ukbd_enable,
165 : ukbd_set_leds,
166 : ukbd_ioctl,
167 : };
168 :
169 : int ukbd_match(struct device *, void *, void *);
170 : void ukbd_attach(struct device *, struct device *, void *);
171 : int ukbd_detach(struct device *, int);
172 :
173 : struct cfdriver ukbd_cd = {
174 : NULL, "ukbd", DV_DULL
175 : };
176 :
177 : const struct cfattach ukbd_ca = {
178 : sizeof(struct ukbd_softc), ukbd_match, ukbd_attach, ukbd_detach
179 : };
180 :
181 : struct ukbd_translation {
182 : uint8_t original;
183 : uint8_t translation;
184 : };
185 :
186 : #ifdef __loongson__
187 : void ukbd_gdium_munge(void *, uint8_t *, u_int);
188 : #endif
189 : void ukbd_apple_munge(void *, uint8_t *, u_int);
190 : void ukbd_apple_mba_munge(void *, uint8_t *, u_int);
191 : void ukbd_apple_iso_munge(void *, uint8_t *, u_int);
192 : void ukbd_apple_iso_mba_munge(void *, uint8_t *, u_int);
193 : void ukbd_apple_translate(void *, uint8_t *, u_int,
194 : const struct ukbd_translation *, u_int);
195 : uint8_t ukbd_translate(const struct ukbd_translation *, size_t, uint8_t);
196 :
197 : int
198 0 : ukbd_match(struct device *parent, void *match, void *aux)
199 : {
200 0 : struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
201 0 : int size;
202 0 : void *desc;
203 :
204 0 : uhidev_get_report_desc(uha->parent, &desc, &size);
205 0 : if (!hid_is_collection(desc, size, uha->reportid,
206 : HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
207 0 : return (UMATCH_NONE);
208 :
209 0 : return (UMATCH_IFACECLASS);
210 0 : }
211 :
212 : void
213 0 : ukbd_attach(struct device *parent, struct device *self, void *aux)
214 : {
215 0 : struct ukbd_softc *sc = (struct ukbd_softc *)self;
216 0 : struct hidkbd *kbd = &sc->sc_kbd;
217 0 : struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
218 : struct usb_hid_descriptor *hid;
219 0 : u_int32_t quirks, qflags = 0;
220 0 : int dlen, repid;
221 : int console = 1;
222 0 : void *desc;
223 : kbd_t layout = (kbd_t)-1;
224 :
225 0 : sc->sc_hdev.sc_intr = ukbd_intr;
226 0 : sc->sc_hdev.sc_parent = uha->parent;
227 0 : sc->sc_hdev.sc_udev = uha->uaa->device;
228 0 : sc->sc_hdev.sc_report_id = uha->reportid;
229 :
230 0 : uhidev_get_report_desc(uha->parent, &desc, &dlen);
231 0 : repid = uha->reportid;
232 0 : sc->sc_hdev.sc_isize = hid_report_size(desc, dlen, hid_input, repid);
233 0 : sc->sc_hdev.sc_osize = hid_report_size(desc, dlen, hid_output, repid);
234 0 : sc->sc_hdev.sc_fsize = hid_report_size(desc, dlen, hid_feature, repid);
235 :
236 : /*
237 : * Since the HID-Proxy is always detected before any
238 : * real keyboard, do not let it grab the console.
239 : */
240 0 : if (uha->uaa->vendor == USB_VENDOR_APPLE &&
241 0 : uha->uaa->product == USB_PRODUCT_APPLE_BLUETOOTH_HCI)
242 0 : console = 0;
243 :
244 0 : quirks = usbd_get_quirks(sc->sc_hdev.sc_udev)->uq_flags;
245 0 : if (quirks & UQ_SPUR_BUT_UP)
246 0 : qflags |= HIDKBD_SPUR_BUT_UP;
247 :
248 0 : if (hidkbd_attach(self, kbd, console, qflags, repid, desc, dlen) != 0)
249 0 : return;
250 :
251 0 : if (uha->uaa->vendor == USB_VENDOR_APPLE) {
252 0 : if (hid_locate(desc, dlen, HID_USAGE2(HUP_APPLE, HUG_FN_KEY),
253 0 : uha->reportid, hid_input, &sc->sc_apple_fn, &qflags)) {
254 0 : if (qflags & HIO_VARIABLE) {
255 0 : switch (uha->uaa->product) {
256 : case USB_PRODUCT_APPLE_FOUNTAIN_ISO:
257 : case USB_PRODUCT_APPLE_GEYSER_ISO:
258 : case USB_PRODUCT_APPLE_WELLSPRING6_ISO:
259 : case USB_PRODUCT_APPLE_WELLSPRING8_ISO:
260 0 : sc->sc_munge = ukbd_apple_iso_munge;
261 0 : break;
262 : case USB_PRODUCT_APPLE_WELLSPRING_ISO:
263 : case USB_PRODUCT_APPLE_WELLSPRING4_ISO:
264 : case USB_PRODUCT_APPLE_WELLSPRING4A_ISO:
265 0 : sc->sc_munge = ukbd_apple_iso_mba_munge;
266 0 : break;
267 : case USB_PRODUCT_APPLE_WELLSPRING_ANSI:
268 : case USB_PRODUCT_APPLE_WELLSPRING_JIS:
269 : case USB_PRODUCT_APPLE_WELLSPRING4_ANSI:
270 : case USB_PRODUCT_APPLE_WELLSPRING4_JIS:
271 : case USB_PRODUCT_APPLE_WELLSPRING4A_ANSI:
272 : case USB_PRODUCT_APPLE_WELLSPRING4A_JIS:
273 0 : sc->sc_munge = ukbd_apple_mba_munge;
274 0 : break;
275 : default:
276 0 : sc->sc_munge = ukbd_apple_munge;
277 0 : break;
278 : }
279 : }
280 : }
281 : }
282 :
283 0 : if (uha->uaa->vendor == USB_VENDOR_TOPRE &&
284 0 : uha->uaa->product == USB_PRODUCT_TOPRE_HHKB) {
285 : /* ignore country code on purpose */
286 : } else {
287 : usb_interface_descriptor_t *id;
288 :
289 0 : id = usbd_get_interface_descriptor(uha->uaa->iface);
290 0 : hid = usbd_get_hid_descriptor(uha->uaa->device, id);
291 :
292 0 : if (hid->bCountryCode <= HCC_MAX)
293 0 : layout = ukbd_countrylayout[hid->bCountryCode];
294 : #ifdef DIAGNOSTIC
295 0 : if (hid->bCountryCode != 0)
296 0 : printf(", country code %d", hid->bCountryCode);
297 : #endif
298 : }
299 0 : if (layout == (kbd_t)-1) {
300 : #ifdef UKBD_LAYOUT
301 : layout = UKBD_LAYOUT;
302 : #else
303 : layout = KB_US | KB_DEFAULT;
304 : #endif
305 0 : }
306 :
307 0 : printf("\n");
308 :
309 : #ifdef __loongson__
310 : if (uha->uaa->vendor == USB_VENDOR_CYPRESS &&
311 : uha->uaa->product == USB_PRODUCT_CYPRESS_LPRDK)
312 : sc->sc_munge = ukbd_gdium_munge;
313 : #endif
314 :
315 0 : if (kbd->sc_console_keyboard) {
316 : extern struct wskbd_mapdata ukbd_keymapdata;
317 :
318 : DPRINTF(("ukbd_attach: console keyboard sc=%p\n", sc));
319 0 : ukbd_keymapdata.layout = layout;
320 0 : wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata);
321 0 : ukbd_enable(sc, 1);
322 0 : }
323 :
324 : /* Flash the leds; no real purpose, just shows we're alive. */
325 0 : ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM |
326 : WSKBD_LED_CAPS | WSKBD_LED_COMPOSE);
327 0 : usbd_delay_ms(sc->sc_hdev.sc_udev, 400);
328 0 : ukbd_set_leds(sc, 0);
329 :
330 0 : hidkbd_attach_wskbd(kbd, layout, &ukbd_accessops);
331 :
332 : #ifdef DDB
333 0 : timeout_set(&sc->sc_ddb, ukbd_db_enter, sc);
334 : #endif
335 0 : }
336 :
337 : int
338 0 : ukbd_detach(struct device *self, int flags)
339 : {
340 0 : struct ukbd_softc *sc = (struct ukbd_softc *)self;
341 0 : struct hidkbd *kbd = &sc->sc_kbd;
342 : int rv;
343 :
344 0 : rv = hidkbd_detach(kbd, flags);
345 :
346 : /* The console keyboard does not get a disable call, so check pipe. */
347 0 : if (sc->sc_hdev.sc_state & UHIDEV_OPEN)
348 0 : uhidev_close(&sc->sc_hdev);
349 :
350 0 : return (rv);
351 : }
352 :
353 : void
354 0 : ukbd_intr(struct uhidev *addr, void *ibuf, u_int len)
355 : {
356 0 : struct ukbd_softc *sc = (struct ukbd_softc *)addr;
357 0 : struct hidkbd *kbd = &sc->sc_kbd;
358 :
359 0 : if (kbd->sc_enabled != 0) {
360 0 : if (sc->sc_munge != NULL)
361 0 : (*sc->sc_munge)(sc, (uint8_t *)ibuf, len);
362 0 : hidkbd_input(kbd, (uint8_t *)ibuf, len);
363 0 : }
364 0 : }
365 :
366 : int
367 0 : ukbd_enable(void *v, int on)
368 : {
369 0 : struct ukbd_softc *sc = v;
370 0 : struct hidkbd *kbd = &sc->sc_kbd;
371 : int rv;
372 :
373 0 : if (on && usbd_is_dying(sc->sc_hdev.sc_udev))
374 0 : return EIO;
375 :
376 0 : if ((rv = hidkbd_enable(kbd, on)) != 0)
377 0 : return rv;
378 :
379 0 : if (on) {
380 0 : return uhidev_open(&sc->sc_hdev);
381 : } else {
382 0 : uhidev_close(&sc->sc_hdev);
383 0 : return 0;
384 : }
385 0 : }
386 :
387 : void
388 0 : ukbd_set_leds(void *v, int leds)
389 : {
390 0 : struct ukbd_softc *sc = v;
391 0 : struct hidkbd *kbd = &sc->sc_kbd;
392 0 : u_int8_t res;
393 :
394 0 : if (usbd_is_dying(sc->sc_hdev.sc_udev))
395 0 : return;
396 :
397 0 : if (sc->sc_ledsize && hidkbd_set_leds(kbd, leds, &res) != 0)
398 0 : uhidev_set_report_async(sc->sc_hdev.sc_parent,
399 0 : UHID_OUTPUT_REPORT, sc->sc_hdev.sc_report_id, &res, 1);
400 0 : }
401 :
402 : int
403 0 : ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
404 : {
405 0 : struct ukbd_softc *sc = v;
406 0 : struct hidkbd *kbd = &sc->sc_kbd;
407 : int rc;
408 :
409 0 : switch (cmd) {
410 : case WSKBDIO_GTYPE:
411 0 : *(int *)data = WSKBD_TYPE_USB;
412 0 : return (0);
413 : case WSKBDIO_SETLEDS:
414 0 : ukbd_set_leds(v, *(int *)data);
415 0 : return (0);
416 : default:
417 0 : rc = uhidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
418 0 : if (rc != -1)
419 0 : return rc;
420 : else
421 0 : return hidkbd_ioctl(kbd, cmd, data, flag, p);
422 : }
423 0 : }
424 :
425 : /* Console interface. */
426 : void
427 0 : ukbd_cngetc(void *v, u_int *type, int *data)
428 : {
429 0 : struct ukbd_softc *sc = v;
430 0 : struct hidkbd *kbd = &sc->sc_kbd;
431 :
432 : DPRINTFN(0,("ukbd_cngetc: enter\n"));
433 0 : kbd->sc_polling = 1;
434 0 : while (kbd->sc_npollchar <= 0)
435 0 : usbd_dopoll(sc->sc_hdev.sc_udev);
436 0 : kbd->sc_polling = 0;
437 0 : hidkbd_cngetc(kbd, type, data);
438 : DPRINTFN(0,("ukbd_cngetc: return 0x%02x\n", *data));
439 0 : }
440 :
441 : void
442 0 : ukbd_cnpollc(void *v, int on)
443 : {
444 0 : struct ukbd_softc *sc = v;
445 :
446 : DPRINTFN(2,("ukbd_cnpollc: sc=%p on=%d\n", v, on));
447 :
448 0 : if (on)
449 0 : sc->sc_spl = splusb();
450 : else
451 0 : splx(sc->sc_spl);
452 0 : usbd_set_polling(sc->sc_hdev.sc_udev, on);
453 0 : }
454 :
455 : void
456 0 : ukbd_cnbell(void *v, u_int pitch, u_int period, u_int volume)
457 : {
458 0 : hidkbd_bell(pitch, period, volume, 1);
459 0 : }
460 :
461 : #ifdef DDB
462 : void
463 0 : ukbd_debugger(void *v)
464 : {
465 0 : struct ukbd_softc *sc = v;
466 :
467 : /*
468 : * For the console keyboard we can't deliver CTL-ALT-ESC
469 : * from the interrupt routine. Doing so would start
470 : * polling from inside the interrupt routine and that
471 : * loses bigtime.
472 : */
473 0 : timeout_add(&sc->sc_ddb, 1);
474 0 : }
475 :
476 : void
477 0 : ukbd_db_enter(void *xsc)
478 : {
479 0 : db_enter();
480 0 : }
481 : #endif
482 :
483 : int
484 0 : ukbd_cnattach(void)
485 : {
486 : struct ukbd_softc *sc;
487 : int i;
488 :
489 : /*
490 : * XXX USB requires too many parts of the kernel to be running
491 : * XXX in order to work, so we can't do much for the console
492 : * XXX keyboard until autconfiguration has run its course.
493 : */
494 0 : hidkbd_is_console = 1;
495 :
496 0 : if (!cold) {
497 : /*
498 : * When switching console dynamically force all USB keyboards
499 : * to re-attach and possibly became the 'console' keyboard.
500 : */
501 0 : for (i = 0; i < ukbd_cd.cd_ndevs; i++) {
502 0 : if ((sc = ukbd_cd.cd_devs[i]) != NULL) {
503 0 : usb_needs_reattach(sc->sc_hdev.sc_udev);
504 0 : break;
505 : }
506 : }
507 : }
508 :
509 0 : return (0);
510 : }
511 :
512 : uint8_t
513 0 : ukbd_translate(const struct ukbd_translation *table, size_t tsize,
514 : uint8_t keycode)
515 : {
516 0 : for (; tsize != 0; table++, tsize--)
517 0 : if (table->original == keycode)
518 0 : return table->translation;
519 0 : return 0;
520 0 : }
521 :
522 : void
523 0 : ukbd_apple_translate(void *vsc, uint8_t *ibuf, u_int ilen,
524 : const struct ukbd_translation* trans, u_int tlen)
525 : {
526 0 : struct ukbd_softc *sc = vsc;
527 0 : struct hidkbd *kbd = &sc->sc_kbd;
528 : uint8_t *pos, *spos, *epos, xlat;
529 :
530 0 : spos = ibuf + kbd->sc_keycodeloc.pos / 8;
531 0 : epos = spos + kbd->sc_nkeycode;
532 :
533 0 : for (pos = spos; pos != epos; pos++) {
534 0 : xlat = ukbd_translate(trans, tlen, *pos);
535 0 : if (xlat != 0)
536 0 : *pos = xlat;
537 : }
538 0 : }
539 :
540 : void
541 0 : ukbd_apple_munge(void *vsc, uint8_t *ibuf, u_int ilen)
542 : {
543 0 : struct ukbd_softc *sc = vsc;
544 :
545 : static const struct ukbd_translation apple_fn_trans[] = {
546 : { 40, 73 }, /* return -> insert */
547 : { 42, 76 }, /* backspace -> delete */
548 : #ifdef notyet
549 : { 58, 0 }, /* F1 -> screen brightness down */
550 : { 59, 0 }, /* F2 -> screen brightness up */
551 : { 60, 0 }, /* F3 */
552 : { 61, 0 }, /* F4 */
553 : { 62, 0 }, /* F5 -> keyboard backlight down */
554 : { 63, 0 }, /* F6 -> keyboard backlight up */
555 : { 64, 0 }, /* F7 -> audio back */
556 : { 65, 0 }, /* F8 -> audio pause/play */
557 : { 66, 0 }, /* F9 -> audio next */
558 : #endif
559 : #ifdef __macppc__
560 : { 60, 127 }, /* F3 -> audio mute */
561 : { 61, 129 }, /* F4 -> audio lower */
562 : { 62, 128 }, /* F5 -> audio raise */
563 : #else
564 : { 67, 127 }, /* F10 -> audio mute */
565 : { 68, 129 }, /* F11 -> audio lower */
566 : { 69, 128 }, /* F12 -> audio raise */
567 : #endif
568 : { 79, 77 }, /* right -> end */
569 : { 80, 74 }, /* left -> home */
570 : { 81, 78 }, /* down -> page down */
571 : { 82, 75 } /* up -> page up */
572 : };
573 :
574 0 : if (!hid_get_data(ibuf, ilen, &sc->sc_apple_fn))
575 0 : return;
576 :
577 0 : ukbd_apple_translate(vsc, ibuf, ilen, apple_fn_trans,
578 : nitems(apple_fn_trans));
579 0 : }
580 :
581 : void
582 0 : ukbd_apple_mba_munge(void *vsc, uint8_t *ibuf, u_int ilen)
583 : {
584 0 : struct ukbd_softc *sc = vsc;
585 :
586 : static const struct ukbd_translation apple_fn_trans[] = {
587 : { 40, 73 }, /* return -> insert */
588 : { 42, 76 }, /* backspace -> delete */
589 : #ifdef notyet
590 : { 58, 0 }, /* F1 -> screen brightness down */
591 : { 59, 0 }, /* F2 -> screen brightness up */
592 : { 60, 0 }, /* F3 */
593 : { 61, 0 }, /* F4 */
594 : { 62, 0 }, /* F5 */
595 : { 63, 0 }, /* F6 -> audio back */
596 : { 64, 0 }, /* F7 -> audio pause/play */
597 : { 65, 0 }, /* F8 -> audio next */
598 : #endif
599 : { 66, 127 }, /* F9 -> audio mute */
600 : { 67, 129 }, /* F10 -> audio lower */
601 : { 68, 128 }, /* F11 -> audio raise */
602 : #ifdef notyet
603 : { 69, 0 }, /* F12 -> eject */
604 : #endif
605 : { 79, 77 }, /* right -> end */
606 : { 80, 74 }, /* left -> home */
607 : { 81, 78 }, /* down -> page down */
608 : { 82, 75 } /* up -> page up */
609 : };
610 :
611 0 : if (!hid_get_data(ibuf, ilen, &sc->sc_apple_fn))
612 0 : return;
613 :
614 0 : ukbd_apple_translate(vsc, ibuf, ilen, apple_fn_trans,
615 : nitems(apple_fn_trans));
616 0 : }
617 :
618 : void
619 0 : ukbd_apple_iso_munge(void *vsc, uint8_t *ibuf, u_int ilen)
620 : {
621 : static const struct ukbd_translation apple_iso_trans[] = {
622 : { 53, 100 }, /* less -> grave */
623 : { 100, 53 },
624 : };
625 :
626 0 : ukbd_apple_translate(vsc, ibuf, ilen, apple_iso_trans,
627 : nitems(apple_iso_trans));
628 0 : ukbd_apple_munge(vsc, ibuf, ilen);
629 0 : }
630 :
631 : void
632 0 : ukbd_apple_iso_mba_munge(void *vsc, uint8_t *ibuf, u_int ilen)
633 : {
634 : static const struct ukbd_translation apple_iso_trans[] = {
635 : { 53, 100 }, /* less -> grave */
636 : { 100, 53 },
637 : };
638 :
639 0 : ukbd_apple_translate(vsc, ibuf, ilen, apple_iso_trans,
640 : nitems(apple_iso_trans));
641 0 : ukbd_apple_mba_munge(vsc, ibuf, ilen);
642 0 : }
643 :
644 : #ifdef __loongson__
645 : /*
646 : * Software Fn- translation for Gdium Liberty keyboard.
647 : */
648 : #define GDIUM_FN_CODE 0x82
649 : void
650 : ukbd_gdium_munge(void *vsc, uint8_t *ibuf, u_int ilen)
651 : {
652 : struct ukbd_softc *sc = vsc;
653 : struct hidkbd *kbd = &sc->sc_kbd;
654 : uint8_t *pos, *spos, *epos, xlat;
655 : int fn;
656 :
657 : static const struct ukbd_translation gdium_fn_trans[] = {
658 : #ifdef notyet
659 : { 58, 0 }, /* F1 -> toggle camera */
660 : { 59, 0 }, /* F2 -> toggle wireless */
661 : #endif
662 : { 60, 127 }, /* F3 -> audio mute */
663 : { 61, 128 }, /* F4 -> audio raise */
664 : { 62, 129 }, /* F5 -> audio lower */
665 : #ifdef notyet
666 : { 63, 0 }, /* F6 -> toggle ext. video */
667 : { 64, 0 }, /* F7 -> toggle mouse */
668 : { 65, 0 }, /* F8 -> brightness up */
669 : { 66, 0 }, /* F9 -> brightness down */
670 : { 67, 0 }, /* F10 -> suspend */
671 : { 68, 0 }, /* F11 -> user1 */
672 : { 69, 0 }, /* F12 -> user2 */
673 : { 70, 0 }, /* print screen -> sysrq */
674 : #endif
675 : { 76, 71 }, /* delete -> scroll lock */
676 : { 81, 78 }, /* down -> page down */
677 : { 82, 75 } /* up -> page up */
678 : };
679 :
680 : spos = ibuf + kbd->sc_keycodeloc.pos / 8;
681 : epos = spos + kbd->sc_nkeycode;
682 :
683 : /*
684 : * Check for Fn key being down and remove it from the report.
685 : */
686 :
687 : fn = 0;
688 : for (pos = spos; pos != epos; pos++)
689 : if (*pos == GDIUM_FN_CODE) {
690 : fn = 1;
691 : *pos = 0;
692 : break;
693 : }
694 :
695 : /*
696 : * Rewrite keycodes on the fly to perform Fn-key translation.
697 : * Keycodes without a translation are passed unaffected.
698 : */
699 :
700 : if (fn != 0)
701 : for (pos = spos; pos != epos; pos++) {
702 : xlat = ukbd_translate(gdium_fn_trans,
703 : nitems(gdium_fn_trans), *pos);
704 : if (xlat != 0)
705 : *pos = xlat;
706 : }
707 :
708 : }
709 : #endif
|