1 /* $OpenBSD: ukbd.c,v 1.7 2001/07/25 04:54:37 mickey Exp $ */ 2 /* $NetBSD: ukbd.c,v 1.66 2001/04/06 22:54:15 augustss Exp $ */ 3 4 /* 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Lennart Augustsson (lennart@augustsson.net) at 10 * Carlstedt Research & Technology. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the NetBSD 23 * Foundation, Inc. and its contributors. 24 * 4. Neither the name of The NetBSD Foundation nor the names of its 25 * contributors may be used to endorse or promote products derived 26 * from this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 * POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 /* 42 * HID spec: http://www.usb.org/developers/data/devclass/hid1_1.pdf 43 */ 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #if defined(__OpenBSD__) 48 #include <sys/timeout.h> 49 #else 50 #include <sys/callout.h> 51 #endif 52 #include <sys/kernel.h> 53 #include <sys/device.h> 54 #include <sys/ioctl.h> 55 #include <sys/tty.h> 56 #include <sys/file.h> 57 #include <sys/select.h> 58 #include <sys/proc.h> 59 #include <sys/vnode.h> 60 #include <sys/poll.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/usbdi_util.h> 67 #include <dev/usb/usbdevs.h> 68 #include <dev/usb/usb_quirks.h> 69 #include <dev/usb/hid.h> 70 #include <dev/usb/ukbdvar.h> 71 72 #include <dev/wscons/wsconsio.h> 73 #include <dev/wscons/wskbdvar.h> 74 #include <dev/wscons/wsksymdef.h> 75 #include <dev/wscons/wsksymvar.h> 76 77 #if defined(__NetBSD__) 78 #include "opt_wsdisplay_compat.h" 79 #endif 80 81 #ifdef UKBD_DEBUG 82 #define DPRINTF(x) if (ukbddebug) logprintf x 83 #define DPRINTFN(n,x) if (ukbddebug>(n)) logprintf x 84 int ukbddebug = 0; 85 #else 86 #define DPRINTF(x) 87 #define DPRINTFN(n,x) 88 #endif 89 90 #define NKEYCODE 6 91 92 #define NUM_LOCK 0x01 93 #define CAPS_LOCK 0x02 94 #define SCROLL_LOCK 0x04 95 96 struct ukbd_data { 97 u_int8_t modifiers; 98 #define MOD_CONTROL_L 0x01 99 #define MOD_CONTROL_R 0x10 100 #define MOD_SHIFT_L 0x02 101 #define MOD_SHIFT_R 0x20 102 #define MOD_ALT_L 0x04 103 #define MOD_ALT_R 0x40 104 #define MOD_WIN_L 0x08 105 #define MOD_WIN_R 0x80 106 u_int8_t reserved; 107 u_int8_t keycode[NKEYCODE]; 108 }; 109 110 #define PRESS 0x000 111 #define RELEASE 0x100 112 #define CODEMASK 0x0ff 113 114 /* Translate USB bitmap to USB keycode. */ 115 #define NMOD 8 116 Static const struct { 117 int mask, key; 118 } ukbd_mods[NMOD] = { 119 { MOD_CONTROL_L, 224 }, 120 { MOD_CONTROL_R, 228 }, 121 { MOD_SHIFT_L, 225 }, 122 { MOD_SHIFT_R, 229 }, 123 { MOD_ALT_L, 226 }, 124 { MOD_ALT_R, 230 }, 125 { MOD_WIN_L, 227 }, 126 { MOD_WIN_R, 231 }, 127 }; 128 129 #if defined(WSDISPLAY_COMPAT_RAWKBD) 130 #define NN 0 /* no translation */ 131 /* 132 * Translate USB keycodes to US keyboard XT scancodes. 133 * Scancodes >= 128 represent EXTENDED keycodes. 134 */ 135 Static const u_int8_t ukbd_trtab[256] = { 136 NN, NN, NN, NN, 30, 48, 46, 32, /* 00 - 07 */ 137 18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */ 138 50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */ 139 22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */ 140 4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */ 141 28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */ 142 27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */ 143 53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */ 144 65, 66, 67, 68, 87, 88, 170, 70, /* 40 - 47 */ 145 127, 210, 199, 201, 211, 207, 209, 205, /* 48 - 4F */ 146 203, 208, 200, 69, 181, 55, 74, 78, /* 50 - 57 */ 147 156, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */ 148 72, 73, 82, 83, 86, 221, NN, NN, /* 60 - 67 */ 149 NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */ 150 NN, NN, NN, NN, NN, NN, NN, NN, /* 70 - 77 */ 151 NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7F */ 152 NN, NN, NN, NN, NN, NN, NN, NN, /* 80 - 87 */ 153 NN, NN, NN, NN, NN, NN, NN, NN, /* 88 - 8F */ 154 NN, NN, NN, NN, NN, NN, NN, NN, /* 90 - 97 */ 155 NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */ 156 NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */ 157 NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */ 158 NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */ 159 NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */ 160 NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */ 161 NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */ 162 NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */ 163 NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */ 164 29, 42, 56, 219, 157, 54, 184,220, /* E0 - E7 */ 165 NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */ 166 NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */ 167 NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */ 168 }; 169 #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */ 170 171 #define KEY_ERROR 0x01 172 173 #define MAXKEYS (NMOD+2*NKEYCODE) 174 175 struct ukbd_softc { 176 USBBASEDEVICE sc_dev; /* base device */ 177 usbd_device_handle sc_udev; 178 usbd_interface_handle sc_iface; /* interface */ 179 usbd_pipe_handle sc_intrpipe; /* interrupt pipe */ 180 int sc_ep_addr; 181 182 struct ukbd_data sc_ndata; 183 struct ukbd_data sc_odata; 184 185 char sc_enabled; 186 187 int sc_console_keyboard; /* we are the console keyboard */ 188 189 char sc_debounce; /* for quirk handling */ 190 struct ukbd_data sc_data; /* for quirk handling */ 191 192 int sc_leds; 193 194 #if defined(__OpenBSD__) 195 struct timeout sc_delay; /* for quirk handling */ 196 struct timeout sc_rawrepeat_ch; 197 #else 198 struct callout sc_delay; /* for quirk handling */ 199 struct callout sc_rawrepeat_ch; 200 #endif 201 202 #if defined(__NetBSD__) || defined(__OpenBSD__) 203 struct device *sc_wskbddev; 204 #if defined(WSDISPLAY_COMPAT_RAWKBD) 205 #define REP_DELAY1 400 206 #define REP_DELAYN 100 207 int sc_rawkbd; 208 int sc_nrep; 209 char sc_rep[MAXKEYS]; 210 #endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */ 211 212 int sc_polling; 213 int sc_npollchar; 214 u_int16_t sc_pollchars[MAXKEYS]; 215 #endif 216 217 u_char sc_dying; 218 }; 219 220 #ifdef UKBD_DEBUG 221 #define UKBDTRACESIZE 64 222 struct ukbdtraceinfo { 223 int unit; 224 struct timeval tv; 225 struct ukbd_data ud; 226 }; 227 struct ukbdtraceinfo ukbdtracedata[UKBDTRACESIZE]; 228 int ukbdtraceindex = 0; 229 int ukbdtrace = 0; 230 void ukbdtracedump(void); 231 void 232 ukbdtracedump(void) 233 { 234 int i; 235 for (i = 0; i < UKBDTRACESIZE; i++) { 236 struct ukbdtraceinfo *p = 237 &ukbdtracedata[(i+ukbdtraceindex)%UKBDTRACESIZE]; 238 printf("%lu.%06lu: mod=0x%02x key0=0x%02x key1=0x%02x " 239 "key2=0x%02x key3=0x%02x\n", 240 p->tv.tv_sec, p->tv.tv_usec, 241 p->ud.modifiers, p->ud.keycode[0], p->ud.keycode[1], 242 p->ud.keycode[2], p->ud.keycode[3]); 243 } 244 } 245 #endif 246 247 #define UKBDUNIT(dev) (minor(dev)) 248 #define UKBD_CHUNK 128 /* chunk size for read */ 249 #define UKBD_BSIZE 1020 /* buffer size */ 250 251 Static int ukbd_is_console; 252 253 Static void ukbd_cngetc(void *, u_int *, int *); 254 Static void ukbd_cnpollc(void *, int); 255 256 #if defined(__NetBSD__) || defined(__OpenBSD__) 257 const struct wskbd_consops ukbd_consops = { 258 ukbd_cngetc, 259 ukbd_cnpollc, 260 }; 261 #endif 262 263 Static void ukbd_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); 264 Static void ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud); 265 Static void ukbd_delayed_decode(void *addr); 266 267 Static int ukbd_enable(void *, int); 268 Static void ukbd_set_leds(void *, int); 269 270 #if defined(__NetBSD__) || defined(__OpenBSD__) 271 Static int ukbd_ioctl(void *, u_long, caddr_t, int, struct proc *); 272 #ifdef WSDISPLAY_COMPAT_RAWKBD 273 Static void ukbd_rawrepeat(void *v); 274 #endif 275 276 const struct wskbd_accessops ukbd_accessops = { 277 ukbd_enable, 278 ukbd_set_leds, 279 ukbd_ioctl, 280 }; 281 282 extern const struct wscons_keydesc ukbd_keydesctab[]; 283 284 const struct wskbd_mapdata ukbd_keymapdata = { 285 ukbd_keydesctab, 286 #ifdef UKBD_LAYOUT 287 UKBD_LAYOUT, 288 #else 289 KB_US, 290 #endif 291 }; 292 #endif 293 294 USB_DECLARE_DRIVER(ukbd); 295 296 USB_MATCH(ukbd) 297 { 298 USB_MATCH_START(ukbd, uaa); 299 usb_interface_descriptor_t *id; 300 301 /* Check that this is a keyboard that speaks the boot protocol. */ 302 if (uaa->iface == NULL) 303 return (UMATCH_NONE); 304 id = usbd_get_interface_descriptor(uaa->iface); 305 if (id == NULL || 306 id->bInterfaceClass != UICLASS_HID || 307 id->bInterfaceSubClass != UISUBCLASS_BOOT || 308 id->bInterfaceProtocol != UIPROTO_BOOT_KEYBOARD) 309 return (UMATCH_NONE); 310 return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); 311 } 312 313 USB_ATTACH(ukbd) 314 { 315 USB_ATTACH_START(ukbd, sc, uaa); 316 usbd_interface_handle iface = uaa->iface; 317 usb_interface_descriptor_t *id; 318 usb_endpoint_descriptor_t *ed; 319 usbd_status err; 320 u_int32_t qflags; 321 char devinfo[1024]; 322 #if defined(__NetBSD__) || defined(__OpenBSD__) 323 struct wskbddev_attach_args a; 324 #else 325 int i; 326 #endif 327 328 sc->sc_udev = uaa->device; 329 sc->sc_iface = iface; 330 id = usbd_get_interface_descriptor(iface); 331 usbd_devinfo(uaa->device, 0, devinfo); 332 USB_ATTACH_SETUP; 333 printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), 334 devinfo, id->bInterfaceClass, id->bInterfaceSubClass); 335 336 ed = usbd_interface2endpoint_descriptor(iface, 0); 337 if (ed == NULL) { 338 printf("%s: could not read endpoint descriptor\n", 339 USBDEVNAME(sc->sc_dev)); 340 USB_ATTACH_ERROR_RETURN; 341 } 342 343 DPRINTFN(10,("ukbd_attach: bLength=%d bDescriptorType=%d " 344 "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" 345 " bInterval=%d\n", 346 ed->bLength, ed->bDescriptorType, 347 ed->bEndpointAddress & UE_ADDR, 348 UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", 349 ed->bmAttributes & UE_XFERTYPE, 350 UGETW(ed->wMaxPacketSize), ed->bInterval)); 351 352 if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || 353 (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { 354 printf("%s: unexpected endpoint\n", 355 USBDEVNAME(sc->sc_dev)); 356 USB_ATTACH_ERROR_RETURN; 357 } 358 359 qflags = usbd_get_quirks(uaa->device)->uq_flags; 360 if ((qflags & UQ_NO_SET_PROTO) == 0) { 361 err = usbd_set_protocol(iface, 0); 362 DPRINTFN(5, ("ukbd_attach: protocol set\n")); 363 if (err) { 364 printf("%s: set protocol failed\n", 365 USBDEVNAME(sc->sc_dev)); 366 USB_ATTACH_ERROR_RETURN; 367 } 368 } 369 sc->sc_debounce = (qflags & UQ_SPUR_BUT_UP) != 0; 370 371 /* Ignore if SETIDLE fails since it is not crucial. */ 372 (void)usbd_set_idle(iface, 0, 0); 373 374 sc->sc_ep_addr = ed->bEndpointAddress; 375 376 /* 377 * Remember if we're the console keyboard. 378 * 379 * XXX This always picks the first keyboard on the 380 * first USB bus, but what else can we really do? 381 */ 382 if ((sc->sc_console_keyboard = ukbd_is_console) != 0) { 383 /* Don't let any other keyboard have it. */ 384 ukbd_is_console = 0; 385 } 386 387 if (sc->sc_console_keyboard) { 388 DPRINTF(("ukbd_attach: console keyboard sc=%p\n", sc)); 389 wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata); 390 ukbd_enable(sc, 1); 391 } 392 393 a.console = sc->sc_console_keyboard; 394 395 a.keymap = &ukbd_keymapdata; 396 397 a.accessops = &ukbd_accessops; 398 a.accesscookie = sc; 399 400 #if defined(__OpenBSD__) 401 #ifdef WSDISPLAY_COMPAT_RAWKBD 402 timeout_set(&sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc); 403 #endif 404 timeout_set(&sc->sc_delay, ukbd_delayed_decode, sc); 405 #endif 406 407 #if defined(__NetBSD__) 408 callout_init(&sc->sc_rawrepeat_ch); 409 callout_init(&sc->sc_delay); 410 #endif 411 412 /* Flash the leds; no real purpose, just shows we're alive. */ 413 ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS); 414 usbd_delay_ms(uaa->device, 400); 415 ukbd_set_leds(sc, 0); 416 417 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, 418 USBDEV(sc->sc_dev)); 419 420 sc->sc_wskbddev = config_found(self, &a, wskbddevprint); 421 422 USB_ATTACH_SUCCESS_RETURN; 423 } 424 425 int 426 ukbd_enable(void *v, int on) 427 { 428 struct ukbd_softc *sc = v; 429 usbd_status err; 430 431 if (on && sc->sc_dying) 432 return (EIO); 433 434 /* Should only be called to change state */ 435 if (sc->sc_enabled == on) { 436 #ifdef DIAGNOSTIC 437 printf("ukbd_enable: %s: bad call on=%d\n", 438 USBDEVNAME(sc->sc_dev), on); 439 #endif 440 return (EBUSY); 441 } 442 443 DPRINTF(("ukbd_enable: sc=%p on=%d\n", sc, on)); 444 if (on) { 445 /* Set up interrupt pipe. */ 446 err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, 447 USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, 448 &sc->sc_ndata, sizeof(sc->sc_ndata), ukbd_intr, 449 USBD_DEFAULT_INTERVAL); 450 if (err) 451 return (EIO); 452 } else { 453 /* Disable interrupts. */ 454 usbd_abort_pipe(sc->sc_intrpipe); 455 usbd_close_pipe(sc->sc_intrpipe); 456 } 457 sc->sc_enabled = on; 458 459 return (0); 460 } 461 462 int 463 ukbd_activate(device_ptr_t self, enum devact act) 464 { 465 struct ukbd_softc *sc = (struct ukbd_softc *)self; 466 int rv = 0; 467 468 switch (act) { 469 case DVACT_ACTIVATE: 470 return (EOPNOTSUPP); 471 break; 472 473 case DVACT_DEACTIVATE: 474 if (sc->sc_wskbddev != NULL) 475 rv = config_deactivate(sc->sc_wskbddev); 476 sc->sc_dying = 1; 477 break; 478 } 479 return (rv); 480 } 481 482 USB_DETACH(ukbd) 483 { 484 USB_DETACH_START(ukbd, sc); 485 int rv = 0; 486 487 DPRINTF(("ukbd_detach: sc=%p flags=%d\n", sc, flags)); 488 489 if (sc->sc_console_keyboard) { 490 #if 0 491 /* 492 * XXX Should probably disconnect our consops, 493 * XXX and either notify some other keyboard that 494 * XXX it can now be the console, or if there aren't 495 * XXX any more USB keyboards, set ukbd_is_console 496 * XXX back to 1 so that the next USB keyboard attached 497 * XXX to the system will get it. 498 */ 499 panic("ukbd_detach: console keyboard"); 500 #else 501 /* 502 * Disconnect our consops and set ukbd_is_console 503 * back to 1 so that the next USB keyboard attached 504 * to the system will get it. 505 * XXX Should notify some other keyboard that it can be 506 * XXX console, if there are any other keyboards. 507 */ 508 printf("%s: was console keyboard\n", USBDEVNAME(sc->sc_dev)); 509 wskbd_cndetach(); 510 ukbd_is_console = 1; 511 #endif 512 } 513 /* No need to do reference counting of ukbd, wskbd has all the goo. */ 514 if (sc->sc_wskbddev != NULL) 515 rv = config_detach(sc->sc_wskbddev, flags); 516 517 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, 518 USBDEV(sc->sc_dev)); 519 520 return (rv); 521 } 522 523 void 524 ukbd_intr(xfer, addr, status) 525 usbd_xfer_handle xfer; 526 usbd_private_handle addr; 527 usbd_status status; 528 { 529 struct ukbd_softc *sc = addr; 530 struct ukbd_data *ud = &sc->sc_ndata; 531 532 DPRINTFN(5, ("ukbd_intr: status=%d\n", status)); 533 if (status == USBD_CANCELLED) 534 return; 535 536 if (status) { 537 DPRINTF(("ukbd_intr: status=%d\n", status)); 538 usbd_clear_endpoint_stall_async(sc->sc_intrpipe); 539 return; 540 } 541 542 if (sc->sc_debounce) { 543 /* 544 * Some keyboards have a peculiar quirk. They sometimes 545 * generate a key up followed by a key down for the same 546 * key after about 10 ms. 547 * We avoid this bug by holding off decoding for 20 ms. 548 */ 549 sc->sc_data = *ud; 550 #if defined(__OpenBSD__) 551 timeout_add(&sc->sc_delay, hz / 50); 552 #else 553 callout_reset(&sc->sc_delay, hz / 50, ukbd_delayed_decode, sc); 554 #endif 555 } else { 556 ukbd_decode(sc, ud); 557 } 558 } 559 560 void 561 ukbd_delayed_decode(void *addr) 562 { 563 struct ukbd_softc *sc = addr; 564 565 ukbd_decode(sc, &sc->sc_data); 566 } 567 568 void 569 ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) 570 { 571 int mod, omod; 572 u_int16_t ibuf[MAXKEYS]; /* chars events */ 573 int s; 574 int nkeys, i, j; 575 int key; 576 #define ADDKEY(c) ibuf[nkeys++] = (c) 577 578 #ifdef UKBD_DEBUG 579 /* 580 * Keep a trace of the last events. Using printf changes the 581 * timing, so this can be useful sometimes. 582 */ 583 if (ukbdtrace) { 584 struct ukbdtraceinfo *p = &ukbdtracedata[ukbdtraceindex]; 585 p->unit = sc->sc_dev.dv_unit; 586 microtime(&p->tv); 587 p->ud = *ud; 588 if (++ukbdtraceindex >= UKBDTRACESIZE) 589 ukbdtraceindex = 0; 590 } 591 if (ukbddebug > 5) { 592 struct timeval tv; 593 microtime(&tv); 594 DPRINTF((" at %lu.%06lu mod=0x%02x key0=0x%02x key1=0x%02x " 595 "key2=0x%02x key3=0x%02x\n", 596 tv.tv_sec, tv.tv_usec, 597 ud->modifiers, ud->keycode[0], ud->keycode[1], 598 ud->keycode[2], ud->keycode[3])); 599 } 600 #endif 601 602 if (ud->keycode[0] == KEY_ERROR) { 603 DPRINTF(("ukbd_intr: KEY_ERROR\n")); 604 return; /* ignore */ 605 } 606 nkeys = 0; 607 mod = ud->modifiers; 608 omod = sc->sc_odata.modifiers; 609 if (mod != omod) 610 for (i = 0; i < NMOD; i++) 611 if (( mod & ukbd_mods[i].mask) != 612 (omod & ukbd_mods[i].mask)) 613 ADDKEY(ukbd_mods[i].key | 614 (mod & ukbd_mods[i].mask 615 ? PRESS : RELEASE)); 616 if (memcmp(ud->keycode, sc->sc_odata.keycode, NKEYCODE) != 0) { 617 /* Check for released keys. */ 618 for (i = 0; i < NKEYCODE; i++) { 619 key = sc->sc_odata.keycode[i]; 620 if (key == 0) 621 continue; 622 for (j = 0; j < NKEYCODE; j++) 623 if (key == ud->keycode[j]) 624 goto rfound; 625 DPRINTFN(3,("ukbd_intr: relse key=0x%02x\n", key)); 626 ADDKEY(key | RELEASE); 627 rfound: 628 ; 629 } 630 631 /* Check for pressed keys. */ 632 for (i = 0; i < NKEYCODE; i++) { 633 key = ud->keycode[i]; 634 if (key == 0) 635 continue; 636 for (j = 0; j < NKEYCODE; j++) 637 if (key == sc->sc_odata.keycode[j]) 638 goto pfound; 639 DPRINTFN(2,("ukbd_intr: press key=0x%02x\n", key)); 640 ADDKEY(key | PRESS); 641 pfound: 642 ; 643 } 644 } 645 sc->sc_odata = *ud; 646 647 if (nkeys == 0) 648 return; 649 650 if (sc->sc_polling) { 651 DPRINTFN(1,("ukbd_intr: pollchar = 0x%03x\n", ibuf[0])); 652 memcpy(sc->sc_pollchars, ibuf, nkeys * sizeof(u_int16_t)); 653 sc->sc_npollchar = nkeys; 654 return; 655 } 656 #ifdef WSDISPLAY_COMPAT_RAWKBD 657 if (sc->sc_rawkbd) { 658 char cbuf[MAXKEYS * 2]; 659 int c; 660 int npress; 661 662 for (npress = i = j = 0; i < nkeys; i++) { 663 key = ibuf[i]; 664 c = ukbd_trtab[key & CODEMASK]; 665 if (c == NN) 666 continue; 667 if (c & 0x80) 668 cbuf[j++] = 0xe0; 669 cbuf[j] = c & 0x7f; 670 if (key & RELEASE) 671 cbuf[j] |= 0x80; 672 else { 673 /* remember pressed keys for autorepeat */ 674 if (c & 0x80) 675 sc->sc_rep[npress++] = 0xe0; 676 sc->sc_rep[npress++] = c & 0x7f; 677 } 678 DPRINTFN(1,("ukbd_intr: raw = %s0x%02x\n", 679 c & 0x80 ? "0xe0 " : "", 680 cbuf[j])); 681 j++; 682 } 683 s = spltty(); 684 wskbd_rawinput(sc->sc_wskbddev, cbuf, j); 685 splx(s); 686 #if defined(__OpenBSD__) 687 timeout_del(&sc->sc_rawrepeat_ch); 688 #else 689 callout_stop(&sc->sc_rawrepeat_ch); 690 #endif 691 if (npress != 0) { 692 sc->sc_nrep = npress; 693 #if defined(__OpenBSD__) 694 timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAY1/1000); 695 #else 696 callout_reset(&sc->sc_rawrepeat_ch, 697 hz * REP_DELAY1 / 1000, ukbd_rawrepeat, sc); 698 #endif 699 } 700 return; 701 } 702 #endif 703 704 s = spltty(); 705 for (i = 0; i < nkeys; i++) { 706 key = ibuf[i]; 707 wskbd_input(sc->sc_wskbddev, 708 key&RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN, 709 key&CODEMASK); 710 } 711 splx(s); 712 } 713 714 void 715 ukbd_set_leds(void *v, int leds) 716 { 717 struct ukbd_softc *sc = v; 718 u_int8_t res; 719 720 DPRINTF(("ukbd_set_leds: sc=%p leds=%d\n", sc, leds)); 721 722 if (sc->sc_dying) 723 return; 724 725 sc->sc_leds = leds; 726 res = 0; 727 if (leds & WSKBD_LED_SCROLL) 728 res |= SCROLL_LOCK; 729 if (leds & WSKBD_LED_NUM) 730 res |= NUM_LOCK; 731 if (leds & WSKBD_LED_CAPS) 732 res |= CAPS_LOCK; 733 res |= leds & 0xf8; 734 usbd_set_report_async(sc->sc_iface, UHID_OUTPUT_REPORT, 0, &res, 1); 735 } 736 737 #ifdef WSDISPLAY_COMPAT_RAWKBD 738 void 739 ukbd_rawrepeat(void *v) 740 { 741 struct ukbd_softc *sc = v; 742 int s; 743 744 s = spltty(); 745 wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep); 746 splx(s); 747 #if defined(__OpenBSD__) 748 timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000); 749 #else 750 callout_reset(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000, 751 ukbd_rawrepeat, sc); 752 #endif 753 } 754 #endif 755 756 int 757 ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 758 { 759 struct ukbd_softc *sc = v; 760 761 switch (cmd) { 762 case WSKBDIO_GTYPE: 763 *(int *)data = WSKBD_TYPE_USB; 764 return (0); 765 case WSKBDIO_SETLEDS: 766 ukbd_set_leds(v, *(int *)data); 767 return (0); 768 case WSKBDIO_GETLEDS: 769 *(int *)data = sc->sc_leds; 770 return (0); 771 #ifdef WSDISPLAY_COMPAT_RAWKBD 772 case WSKBDIO_SETMODE: 773 DPRINTF(("ukbd_ioctl: set raw = %d\n", *(int *)data)); 774 sc->sc_rawkbd = *(int *)data == WSKBD_RAW; 775 #if defined(__OpenBSD__) 776 timeout_del(&sc->sc_rawrepeat_ch); 777 #else 778 callout_stop(&sc->sc_rawrepeat_ch); 779 #endif 780 return (0); 781 #endif 782 } 783 return (-1); 784 } 785 786 /* Console interface. */ 787 void 788 ukbd_cngetc(void *v, u_int *type, int *data) 789 { 790 struct ukbd_softc *sc = v; 791 int s; 792 int c; 793 794 DPRINTFN(0,("ukbd_cngetc: enter\n")); 795 s = splusb(); 796 sc->sc_polling = 1; 797 while(sc->sc_npollchar <= 0) 798 usbd_dopoll(sc->sc_iface); 799 sc->sc_polling = 0; 800 c = sc->sc_pollchars[0]; 801 sc->sc_npollchar--; 802 memcpy(sc->sc_pollchars, sc->sc_pollchars+1, 803 sc->sc_npollchar * sizeof(u_int16_t)); 804 *type = c & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; 805 *data = c & CODEMASK; 806 splx(s); 807 DPRINTFN(0,("ukbd_cngetc: return 0x%02x\n", c)); 808 } 809 810 void 811 ukbd_cnpollc(void *v, int on) 812 { 813 struct ukbd_softc *sc = v; 814 usbd_device_handle dev; 815 816 DPRINTFN(2,("ukbd_cnpollc: sc=%p on=%d\n", v, on)); 817 818 (void)usbd_interface2device_handle(sc->sc_iface,&dev); 819 usbd_set_polling(dev, on); 820 } 821 822 int 823 ukbd_cnattach(void) 824 { 825 826 /* 827 * XXX USB requires too many parts of the kernel to be running 828 * XXX in order to work, so we can't do much for the console 829 * XXX keyboard until autconfiguration has run its course. 830 */ 831 ukbd_is_console = 1; 832 return (0); 833 } 834