1 /* $OpenBSD: ukbd.c,v 1.76 2016/01/12 19:16:21 jcs 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 <dev/usb/usb.h> 61 #include <dev/usb/usbhid.h> 62 63 #include <dev/usb/usbdi.h> 64 #include <dev/usb/usbdi_util.h> 65 #include <dev/usb/usbdevs.h> 66 #include <dev/usb/usb_quirks.h> 67 #include <dev/usb/uhidev.h> 68 #include <dev/usb/ukbdvar.h> 69 70 #include <dev/wscons/wsconsio.h> 71 #include <dev/wscons/wskbdvar.h> 72 #include <dev/wscons/wsksymdef.h> 73 #include <dev/wscons/wsksymvar.h> 74 75 #include <dev/hid/hidkbdsc.h> 76 77 #ifdef UKBD_DEBUG 78 #define DPRINTF(x) do { if (ukbddebug) printf x; } while (0) 79 #define DPRINTFN(n,x) do { if (ukbddebug>(n)) printf x; } while (0) 80 int ukbddebug = 0; 81 #else 82 #define DPRINTF(x) 83 #define DPRINTFN(n,x) 84 #endif 85 86 const kbd_t ukbd_countrylayout[1 + HCC_MAX] = { 87 (kbd_t)-1, 88 (kbd_t)-1, /* arabic */ 89 KB_BE, /* belgian */ 90 (kbd_t)-1, /* canadian bilingual */ 91 KB_CF, /* canadian french */ 92 (kbd_t)-1, /* czech */ 93 KB_DK, /* danish */ 94 (kbd_t)-1, /* finnish */ 95 KB_FR, /* french */ 96 KB_DE, /* german */ 97 (kbd_t)-1, /* greek */ 98 (kbd_t)-1, /* hebrew */ 99 KB_HU, /* hungary */ 100 (kbd_t)-1, /* international (iso) */ 101 KB_IT, /* italian */ 102 KB_JP, /* japanese (katakana) */ 103 (kbd_t)-1, /* korean */ 104 KB_LA, /* latin american */ 105 (kbd_t)-1, /* netherlands/dutch */ 106 KB_NO, /* norwegian */ 107 (kbd_t)-1, /* persian (farsi) */ 108 KB_PL, /* polish */ 109 KB_PT, /* portuguese */ 110 KB_RU, /* russian */ 111 (kbd_t)-1, /* slovakia */ 112 KB_ES, /* spanish */ 113 KB_SV, /* swedish */ 114 KB_SF, /* swiss french */ 115 KB_SG, /* swiss german */ 116 (kbd_t)-1, /* switzerland */ 117 (kbd_t)-1, /* taiwan */ 118 KB_TR, /* turkish Q */ 119 KB_UK, /* uk */ 120 KB_US, /* us */ 121 (kbd_t)-1, /* yugoslavia */ 122 (kbd_t)-1 /* turkish F */ 123 }; 124 125 struct ukbd_softc { 126 struct uhidev sc_hdev; 127 #define sc_ledsize sc_hdev.sc_osize 128 129 struct hidkbd sc_kbd; 130 131 int sc_spl; 132 133 struct hid_location sc_apple_fn; 134 135 void (*sc_munge)(void *, uint8_t *, u_int); 136 }; 137 138 void ukbd_cngetc(void *, u_int *, int *); 139 void ukbd_cnpollc(void *, int); 140 void ukbd_cnbell(void *, u_int, u_int, u_int); 141 142 const struct wskbd_consops ukbd_consops = { 143 ukbd_cngetc, 144 ukbd_cnpollc, 145 ukbd_cnbell, 146 }; 147 148 void ukbd_intr(struct uhidev *addr, void *ibuf, u_int len); 149 150 int ukbd_enable(void *, int); 151 void ukbd_set_leds(void *, int); 152 int ukbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 153 154 const struct wskbd_accessops ukbd_accessops = { 155 ukbd_enable, 156 ukbd_set_leds, 157 ukbd_ioctl, 158 }; 159 160 int ukbd_match(struct device *, void *, void *); 161 void ukbd_attach(struct device *, struct device *, void *); 162 int ukbd_detach(struct device *, int); 163 164 struct cfdriver ukbd_cd = { 165 NULL, "ukbd", DV_DULL 166 }; 167 168 const struct cfattach ukbd_ca = { 169 sizeof(struct ukbd_softc), ukbd_match, ukbd_attach, ukbd_detach 170 }; 171 172 struct ukbd_translation { 173 uint8_t original; 174 uint8_t translation; 175 }; 176 177 #ifdef __loongson__ 178 void ukbd_gdium_munge(void *, uint8_t *, u_int); 179 #endif 180 void ukbd_apple_munge(void *, uint8_t *, u_int); 181 void ukbd_apple_mba_munge(void *, uint8_t *, u_int); 182 void ukbd_apple_iso_munge(void *, uint8_t *, u_int); 183 void ukbd_apple_iso_mba_munge(void *, uint8_t *, u_int); 184 void ukbd_apple_translate(void *, uint8_t *, u_int, 185 const struct ukbd_translation *, u_int); 186 uint8_t ukbd_translate(const struct ukbd_translation *, size_t, uint8_t); 187 188 int 189 ukbd_match(struct device *parent, void *match, void *aux) 190 { 191 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 192 int size; 193 void *desc; 194 195 uhidev_get_report_desc(uha->parent, &desc, &size); 196 if (!hid_is_collection(desc, size, uha->reportid, 197 HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) 198 return (UMATCH_NONE); 199 200 return (UMATCH_IFACECLASS); 201 } 202 203 void 204 ukbd_attach(struct device *parent, struct device *self, void *aux) 205 { 206 struct ukbd_softc *sc = (struct ukbd_softc *)self; 207 struct hidkbd *kbd = &sc->sc_kbd; 208 struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux; 209 struct usb_hid_descriptor *hid; 210 u_int32_t quirks, qflags = 0; 211 int dlen, repid; 212 int console = 1; 213 void *desc; 214 kbd_t layout = (kbd_t)-1; 215 216 sc->sc_hdev.sc_intr = ukbd_intr; 217 sc->sc_hdev.sc_parent = uha->parent; 218 sc->sc_hdev.sc_udev = uha->uaa->device; 219 sc->sc_hdev.sc_report_id = uha->reportid; 220 221 uhidev_get_report_desc(uha->parent, &desc, &dlen); 222 repid = uha->reportid; 223 sc->sc_hdev.sc_isize = hid_report_size(desc, dlen, hid_input, repid); 224 sc->sc_hdev.sc_osize = hid_report_size(desc, dlen, hid_output, repid); 225 sc->sc_hdev.sc_fsize = hid_report_size(desc, dlen, hid_feature, repid); 226 227 /* 228 * Since the HID-Proxy is always detected before any 229 * real keyboard, do not let it grab the console. 230 */ 231 if (uha->uaa->vendor == USB_VENDOR_APPLE && 232 uha->uaa->product == USB_PRODUCT_APPLE_BLUETOOTH_HCI) 233 console = 0; 234 235 quirks = usbd_get_quirks(sc->sc_hdev.sc_udev)->uq_flags; 236 if (quirks & UQ_SPUR_BUT_UP) 237 qflags |= HIDKBD_SPUR_BUT_UP; 238 239 if (hidkbd_attach(self, kbd, console, qflags, repid, desc, dlen) != 0) 240 return; 241 242 if (uha->uaa->vendor == USB_VENDOR_APPLE) { 243 if (hid_locate(desc, dlen, HID_USAGE2(HUP_APPLE, HUG_FN_KEY), 244 uha->reportid, hid_input, &sc->sc_apple_fn, &qflags)) { 245 if (qflags & HIO_VARIABLE) { 246 switch (uha->uaa->product) { 247 case USB_PRODUCT_APPLE_FOUNTAIN_ISO: 248 case USB_PRODUCT_APPLE_GEYSER_ISO: 249 case USB_PRODUCT_APPLE_WELLSPRING6_ISO: 250 case USB_PRODUCT_APPLE_WELLSPRING8_ISO: 251 sc->sc_munge = ukbd_apple_iso_munge; 252 break; 253 case USB_PRODUCT_APPLE_WELLSPRING_ISO: 254 case USB_PRODUCT_APPLE_WELLSPRING4_ISO: 255 case USB_PRODUCT_APPLE_WELLSPRING4A_ISO: 256 sc->sc_munge = ukbd_apple_iso_mba_munge; 257 break; 258 case USB_PRODUCT_APPLE_WELLSPRING_ANSI: 259 case USB_PRODUCT_APPLE_WELLSPRING_JIS: 260 case USB_PRODUCT_APPLE_WELLSPRING4_ANSI: 261 case USB_PRODUCT_APPLE_WELLSPRING4_JIS: 262 case USB_PRODUCT_APPLE_WELLSPRING4A_ANSI: 263 case USB_PRODUCT_APPLE_WELLSPRING4A_JIS: 264 sc->sc_munge = ukbd_apple_mba_munge; 265 break; 266 default: 267 sc->sc_munge = ukbd_apple_munge; 268 break; 269 } 270 } 271 } 272 } 273 274 if (uha->uaa->vendor == USB_VENDOR_TOPRE && 275 uha->uaa->product == USB_PRODUCT_TOPRE_HHKB) { 276 /* ignore country code on purpose */ 277 } else { 278 usb_interface_descriptor_t *id; 279 280 id = usbd_get_interface_descriptor(uha->uaa->iface); 281 hid = usbd_get_hid_descriptor(uha->uaa->device, id); 282 283 if (hid->bCountryCode <= HCC_MAX) 284 layout = ukbd_countrylayout[hid->bCountryCode]; 285 #ifdef DIAGNOSTIC 286 if (hid->bCountryCode != 0) 287 printf(", country code %d", hid->bCountryCode); 288 #endif 289 } 290 if (layout == (kbd_t)-1) { 291 #ifdef UKBD_LAYOUT 292 layout = UKBD_LAYOUT; 293 #else 294 layout = KB_US | KB_DEFAULT; 295 #endif 296 } 297 298 printf("\n"); 299 300 #ifdef __loongson__ 301 if (uha->uaa->vendor == USB_VENDOR_CYPRESS && 302 uha->uaa->product == USB_PRODUCT_CYPRESS_LPRDK) 303 sc->sc_munge = ukbd_gdium_munge; 304 #endif 305 306 if (kbd->sc_console_keyboard) { 307 extern struct wskbd_mapdata ukbd_keymapdata; 308 309 DPRINTF(("ukbd_attach: console keyboard sc=%p\n", sc)); 310 ukbd_keymapdata.layout = layout; 311 wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata); 312 ukbd_enable(sc, 1); 313 } 314 315 /* Flash the leds; no real purpose, just shows we're alive. */ 316 ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | 317 WSKBD_LED_CAPS | WSKBD_LED_COMPOSE); 318 usbd_delay_ms(sc->sc_hdev.sc_udev, 400); 319 ukbd_set_leds(sc, 0); 320 321 hidkbd_attach_wskbd(kbd, layout, &ukbd_accessops); 322 } 323 324 int 325 ukbd_detach(struct device *self, int flags) 326 { 327 struct ukbd_softc *sc = (struct ukbd_softc *)self; 328 struct hidkbd *kbd = &sc->sc_kbd; 329 int rv; 330 331 rv = hidkbd_detach(kbd, flags); 332 333 /* The console keyboard does not get a disable call, so check pipe. */ 334 if (sc->sc_hdev.sc_state & UHIDEV_OPEN) 335 uhidev_close(&sc->sc_hdev); 336 337 return (rv); 338 } 339 340 void 341 ukbd_intr(struct uhidev *addr, void *ibuf, u_int len) 342 { 343 struct ukbd_softc *sc = (struct ukbd_softc *)addr; 344 struct hidkbd *kbd = &sc->sc_kbd; 345 346 if (kbd->sc_enabled != 0) { 347 if (sc->sc_munge != NULL) 348 (*sc->sc_munge)(sc, (uint8_t *)ibuf, len); 349 hidkbd_input(kbd, (uint8_t *)ibuf, len); 350 } 351 } 352 353 int 354 ukbd_enable(void *v, int on) 355 { 356 struct ukbd_softc *sc = v; 357 struct hidkbd *kbd = &sc->sc_kbd; 358 int rv; 359 360 if (on && usbd_is_dying(sc->sc_hdev.sc_udev)) 361 return EIO; 362 363 if ((rv = hidkbd_enable(kbd, on)) != 0) 364 return rv; 365 366 if (on) { 367 return uhidev_open(&sc->sc_hdev); 368 } else { 369 uhidev_close(&sc->sc_hdev); 370 return 0; 371 } 372 } 373 374 void 375 ukbd_set_leds(void *v, int leds) 376 { 377 struct ukbd_softc *sc = v; 378 struct hidkbd *kbd = &sc->sc_kbd; 379 u_int8_t res; 380 381 if (usbd_is_dying(sc->sc_hdev.sc_udev)) 382 return; 383 384 if (sc->sc_ledsize && hidkbd_set_leds(kbd, leds, &res) != 0) 385 uhidev_set_report_async(sc->sc_hdev.sc_parent, 386 UHID_OUTPUT_REPORT, sc->sc_hdev.sc_report_id, &res, 1); 387 } 388 389 int 390 ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 391 { 392 struct ukbd_softc *sc = v; 393 struct hidkbd *kbd = &sc->sc_kbd; 394 int rc; 395 396 switch (cmd) { 397 case WSKBDIO_GTYPE: 398 *(int *)data = WSKBD_TYPE_USB; 399 return (0); 400 case WSKBDIO_SETLEDS: 401 ukbd_set_leds(v, *(int *)data); 402 return (0); 403 default: 404 rc = uhidev_ioctl(&sc->sc_hdev, cmd, data, flag, p); 405 if (rc != -1) 406 return rc; 407 else 408 return hidkbd_ioctl(kbd, cmd, data, flag, p); 409 } 410 } 411 412 /* Console interface. */ 413 void 414 ukbd_cngetc(void *v, u_int *type, int *data) 415 { 416 struct ukbd_softc *sc = v; 417 struct hidkbd *kbd = &sc->sc_kbd; 418 419 DPRINTFN(0,("ukbd_cngetc: enter\n")); 420 kbd->sc_polling = 1; 421 while (kbd->sc_npollchar <= 0) 422 usbd_dopoll(sc->sc_hdev.sc_udev); 423 kbd->sc_polling = 0; 424 hidkbd_cngetc(kbd, type, data); 425 DPRINTFN(0,("ukbd_cngetc: return 0x%02x\n", *data)); 426 } 427 428 void 429 ukbd_cnpollc(void *v, int on) 430 { 431 struct ukbd_softc *sc = v; 432 433 DPRINTFN(2,("ukbd_cnpollc: sc=%p on=%d\n", v, on)); 434 435 if (on) 436 sc->sc_spl = splusb(); 437 else 438 splx(sc->sc_spl); 439 usbd_set_polling(sc->sc_hdev.sc_udev, on); 440 } 441 442 void 443 ukbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) 444 { 445 hidkbd_bell(pitch, period, volume, 1); 446 } 447 448 int 449 ukbd_cnattach(void) 450 { 451 /* 452 * XXX USB requires too many parts of the kernel to be running 453 * XXX in order to work, so we can't do much for the console 454 * XXX keyboard until autconfiguration has run its course. 455 */ 456 hidkbd_is_console = 1; 457 return (0); 458 } 459 460 uint8_t 461 ukbd_translate(const struct ukbd_translation *table, size_t tsize, 462 uint8_t keycode) 463 { 464 for (; tsize != 0; table++, tsize--) 465 if (table->original == keycode) 466 return table->translation; 467 return 0; 468 } 469 470 void 471 ukbd_apple_translate(void *vsc, uint8_t *ibuf, u_int ilen, 472 const struct ukbd_translation* trans, u_int tlen) 473 { 474 struct ukbd_softc *sc = vsc; 475 struct hidkbd *kbd = &sc->sc_kbd; 476 uint8_t *pos, *spos, *epos, xlat; 477 478 spos = ibuf + kbd->sc_keycodeloc.pos / 8; 479 epos = spos + kbd->sc_nkeycode; 480 481 for (pos = spos; pos != epos; pos++) { 482 xlat = ukbd_translate(trans, tlen, *pos); 483 if (xlat != 0) 484 *pos = xlat; 485 } 486 } 487 488 void 489 ukbd_apple_munge(void *vsc, uint8_t *ibuf, u_int ilen) 490 { 491 struct ukbd_softc *sc = vsc; 492 493 static const struct ukbd_translation apple_fn_trans[] = { 494 { 40, 73 }, /* return -> insert */ 495 { 42, 76 }, /* backspace -> delete */ 496 #ifdef notyet 497 { 58, 0 }, /* F1 -> screen brightness down */ 498 { 59, 0 }, /* F2 -> screen brightness up */ 499 { 60, 0 }, /* F3 */ 500 { 61, 0 }, /* F4 */ 501 { 62, 0 }, /* F5 -> keyboard backlight down */ 502 { 63, 0 }, /* F6 -> keyboard backlight up */ 503 { 64, 0 }, /* F7 -> audio back */ 504 { 65, 0 }, /* F8 -> audio pause/play */ 505 { 66, 0 }, /* F9 -> audio next */ 506 #endif 507 #ifdef __macppc__ 508 { 60, 127 }, /* F3 -> audio mute */ 509 { 61, 129 }, /* F4 -> audio lower */ 510 { 62, 128 }, /* F5 -> audio raise */ 511 #else 512 { 67, 127 }, /* F10 -> audio mute */ 513 { 68, 129 }, /* F11 -> audio lower */ 514 { 69, 128 }, /* F12 -> audio raise */ 515 #endif 516 { 79, 77 }, /* right -> end */ 517 { 80, 74 }, /* left -> home */ 518 { 81, 78 }, /* down -> page down */ 519 { 82, 75 } /* up -> page up */ 520 }; 521 522 if (!hid_get_data(ibuf, ilen, &sc->sc_apple_fn)) 523 return; 524 525 ukbd_apple_translate(vsc, ibuf, ilen, apple_fn_trans, 526 nitems(apple_fn_trans)); 527 } 528 529 void 530 ukbd_apple_mba_munge(void *vsc, uint8_t *ibuf, u_int ilen) 531 { 532 struct ukbd_softc *sc = vsc; 533 534 static const struct ukbd_translation apple_fn_trans[] = { 535 { 40, 73 }, /* return -> insert */ 536 { 42, 76 }, /* backspace -> delete */ 537 #ifdef notyet 538 { 58, 0 }, /* F1 -> screen brightness down */ 539 { 59, 0 }, /* F2 -> screen brightness up */ 540 { 60, 0 }, /* F3 */ 541 { 61, 0 }, /* F4 */ 542 { 62, 0 }, /* F5 */ 543 { 63, 0 }, /* F6 -> audio back */ 544 { 64, 0 }, /* F7 -> audio pause/play */ 545 { 65, 0 }, /* F8 -> audio next */ 546 #endif 547 { 66, 127 }, /* F9 -> audio mute */ 548 { 67, 129 }, /* F10 -> audio lower */ 549 { 68, 128 }, /* F11 -> audio raise */ 550 #ifdef notyet 551 { 69, 0 }, /* F12 -> eject */ 552 #endif 553 { 79, 77 }, /* right -> end */ 554 { 80, 74 }, /* left -> home */ 555 { 81, 78 }, /* down -> page down */ 556 { 82, 75 } /* up -> page up */ 557 }; 558 559 if (!hid_get_data(ibuf, ilen, &sc->sc_apple_fn)) 560 return; 561 562 ukbd_apple_translate(vsc, ibuf, ilen, apple_fn_trans, 563 nitems(apple_fn_trans)); 564 } 565 566 void 567 ukbd_apple_iso_munge(void *vsc, uint8_t *ibuf, u_int ilen) 568 { 569 static const struct ukbd_translation apple_iso_trans[] = { 570 { 53, 100 }, /* less -> grave */ 571 { 100, 53 }, 572 }; 573 574 ukbd_apple_translate(vsc, ibuf, ilen, apple_iso_trans, 575 nitems(apple_iso_trans)); 576 ukbd_apple_munge(vsc, ibuf, ilen); 577 } 578 579 void 580 ukbd_apple_iso_mba_munge(void *vsc, uint8_t *ibuf, u_int ilen) 581 { 582 static const struct ukbd_translation apple_iso_trans[] = { 583 { 53, 100 }, /* less -> grave */ 584 { 100, 53 }, 585 }; 586 587 ukbd_apple_translate(vsc, ibuf, ilen, apple_iso_trans, 588 nitems(apple_iso_trans)); 589 ukbd_apple_mba_munge(vsc, ibuf, ilen); 590 } 591 592 #ifdef __loongson__ 593 /* 594 * Software Fn- translation for Gdium Liberty keyboard. 595 */ 596 #define GDIUM_FN_CODE 0x82 597 void 598 ukbd_gdium_munge(void *vsc, uint8_t *ibuf, u_int ilen) 599 { 600 struct ukbd_softc *sc = vsc; 601 struct hidkbd *kbd = &sc->sc_kbd; 602 uint8_t *pos, *spos, *epos, xlat; 603 int fn; 604 605 static const struct ukbd_translation gdium_fn_trans[] = { 606 #ifdef notyet 607 { 58, 0 }, /* F1 -> toggle camera */ 608 { 59, 0 }, /* F2 -> toggle wireless */ 609 #endif 610 { 60, 127 }, /* F3 -> audio mute */ 611 { 61, 128 }, /* F4 -> audio raise */ 612 { 62, 129 }, /* F5 -> audio lower */ 613 #ifdef notyet 614 { 63, 0 }, /* F6 -> toggle ext. video */ 615 { 64, 0 }, /* F7 -> toggle mouse */ 616 { 65, 0 }, /* F8 -> brightness up */ 617 { 66, 0 }, /* F9 -> brightness down */ 618 { 67, 0 }, /* F10 -> suspend */ 619 { 68, 0 }, /* F11 -> user1 */ 620 { 69, 0 }, /* F12 -> user2 */ 621 { 70, 0 }, /* print screen -> sysrq */ 622 #endif 623 { 76, 71 }, /* delete -> scroll lock */ 624 { 81, 78 }, /* down -> page down */ 625 { 82, 75 } /* up -> page up */ 626 }; 627 628 spos = ibuf + kbd->sc_keycodeloc.pos / 8; 629 epos = spos + kbd->sc_nkeycode; 630 631 /* 632 * Check for Fn key being down and remove it from the report. 633 */ 634 635 fn = 0; 636 for (pos = spos; pos != epos; pos++) 637 if (*pos == GDIUM_FN_CODE) { 638 fn = 1; 639 *pos = 0; 640 break; 641 } 642 643 /* 644 * Rewrite keycodes on the fly to perform Fn-key translation. 645 * Keycodes without a translation are passed unaffected. 646 */ 647 648 if (fn != 0) 649 for (pos = spos; pos != epos; pos++) { 650 xlat = ukbd_translate(gdium_fn_trans, 651 nitems(gdium_fn_trans), *pos); 652 if (xlat != 0) 653 *pos = xlat; 654 } 655 656 } 657 #endif 658