1 /* $NetBSD: wskbd.c,v 1.148 2026/06/06 17:56:03 kre Exp $ */ 2 3 /* 4 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Christopher G. Demetriou 17 * for the NetBSD Project. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 /* 34 * Copyright (c) 1998 The NetBSD Foundation, Inc. 35 * All rights reserved. 36 * 37 * Keysym translator contributed to The NetBSD Foundation by 38 * Juergen Hannken-Illjes. 39 * 40 * Redistribution and use in source and binary forms, with or without 41 * modification, are permitted provided that the following conditions 42 * are met: 43 * 1. Redistributions of source code must retain the above copyright 44 * notice, this list of conditions and the following disclaimer. 45 * 2. Redistributions in binary form must reproduce the above copyright 46 * notice, this list of conditions and the following disclaimer in the 47 * documentation and/or other materials provided with the distribution. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 50 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 51 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 52 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 53 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 54 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 55 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 56 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 57 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 58 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 59 * POSSIBILITY OF SUCH DAMAGE. 60 */ 61 62 /* 63 * Copyright (c) 1992, 1993 64 * The Regents of the University of California. All rights reserved. 65 * 66 * This software was developed by the Computer Systems Engineering group 67 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 68 * contributed to Berkeley. 69 * 70 * All advertising materials mentioning features or use of this software 71 * must display the following acknowledgement: 72 * This product includes software developed by the University of 73 * California, Lawrence Berkeley Laboratory. 74 * 75 * Redistribution and use in source and binary forms, with or without 76 * modification, are permitted provided that the following conditions 77 * are met: 78 * 1. Redistributions of source code must retain the above copyright 79 * notice, this list of conditions and the following disclaimer. 80 * 2. Redistributions in binary form must reproduce the above copyright 81 * notice, this list of conditions and the following disclaimer in the 82 * documentation and/or other materials provided with the distribution. 83 * 3. Neither the name of the University nor the names of its contributors 84 * may be used to endorse or promote products derived from this software 85 * without specific prior written permission. 86 * 87 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 88 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 89 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 90 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 91 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 92 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 93 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 94 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 95 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 96 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 97 * SUCH DAMAGE. 98 * 99 * @(#)kbd.c 8.2 (Berkeley) 10/30/93 100 */ 101 102 /* 103 * Keyboard driver (/dev/wskbd*). Translates incoming bytes to ASCII or 104 * to `wscons_events' and passes them up to the appropriate reader. 105 */ 106 107 #include <sys/cdefs.h> 108 __KERNEL_RCSID(0, "$NetBSD: wskbd.c,v 1.148 2026/06/06 17:56:03 kre Exp $"); 109 110 #ifdef _KERNEL_OPT 111 #include "opt_ddb.h" 112 #include "opt_kgdb.h" 113 #include "opt_wsdisplay_compat.h" 114 #endif 115 116 #include "wsdisplay.h" 117 #include "wskbd.h" 118 #include "wsmux.h" 119 120 #include <sys/param.h> 121 #include <sys/conf.h> 122 #include <sys/device.h> 123 #include <sys/ioctl.h> 124 #include <sys/poll.h> 125 #include <sys/kernel.h> 126 #include <sys/proc.h> 127 #include <sys/syslog.h> 128 #include <sys/systm.h> 129 #include <sys/callout.h> 130 #include <sys/malloc.h> 131 #include <sys/tty.h> 132 #include <sys/signalvar.h> 133 #include <sys/errno.h> 134 #include <sys/fcntl.h> 135 #include <sys/vnode.h> 136 #include <sys/kauth.h> 137 138 #include <dev/wscons/wsconsio.h> 139 #include <dev/wscons/wskbdvar.h> 140 #include <dev/wscons/wsksymdef.h> 141 #include <dev/wscons/wsksymvar.h> 142 #include <dev/wscons/wsdisplayvar.h> 143 #include <dev/wscons/wseventvar.h> 144 #include <dev/wscons/wscons_callbacks.h> 145 #include <dev/wscons/wsbelldata.h> 146 #include <dev/wscons/wsmuxvar.h> 147 148 #ifdef KGDB 149 #include <sys/kgdb.h> 150 #endif 151 152 #include "ioconf.h" 153 154 #ifdef WSKBD_DEBUG 155 #define DPRINTF(x) if (wskbddebug) printf x 156 int wskbddebug = 0; 157 #else 158 #define DPRINTF(x) 159 #endif 160 161 struct wskbd_internal { 162 const struct wskbd_mapdata *t_keymap; 163 164 const struct wskbd_consops *t_consops; 165 void *t_consaccesscookie; 166 167 int t_modifiers; 168 int t_composelen; /* remaining entries in t_composebuf */ 169 keysym_t t_composebuf[2]; 170 171 int t_flags; 172 #define WSKFL_METAESC 1 173 174 #define MAXKEYSYMSPERKEY 2 /* ESC <key> at max */ 175 keysym_t t_symbols[MAXKEYSYMSPERKEY]; 176 177 struct wskbd_softc *t_sc; /* back pointer */ 178 }; 179 180 struct wskbd_softc { 181 struct wsevsrc sc_base; 182 183 struct wskbd_internal *id; 184 185 const struct wskbd_accessops *sc_accessops; 186 void *sc_accesscookie; 187 188 int sc_ledstate; 189 190 int sc_isconsole; 191 192 struct wskbd_bell_data sc_bell_data; 193 struct wskbd_keyrepeat_data sc_keyrepeat_data; 194 #ifdef WSDISPLAY_SCROLLSUPPORT 195 struct wskbd_scroll_data sc_scroll_data; 196 #endif 197 198 int sc_repeating; /* we've called timeout() */ 199 callout_t sc_repeat_ch; 200 u_int sc_repeat_type; 201 int sc_repeat_value; 202 203 int sc_translating; /* xlate to chars for emulation */ 204 205 int sc_maplen; /* number of entries in sc_map */ 206 struct wscons_keymap *sc_map; /* current translation map */ 207 kbd_t sc_layout; /* current layout */ 208 209 int sc_refcnt; 210 u_char sc_dying; /* device is being detached */ 211 212 wskbd_hotkey_plugin *sc_hotkey; 213 void *sc_hotkeycookie; 214 215 /* optional table to translate scancodes in event mode */ 216 int sc_evtrans_len; 217 keysym_t *sc_evtrans; 218 }; 219 220 #define MOD_SHIFT_L (1 << 0) 221 #define MOD_SHIFT_R (1 << 1) 222 #define MOD_SHIFTLOCK (1 << 2) 223 #define MOD_CAPSLOCK (1 << 3) 224 #define MOD_CONTROL_L (1 << 4) 225 #define MOD_CONTROL_R (1 << 5) 226 #define MOD_META_L (1 << 6) 227 #define MOD_META_R (1 << 7) 228 #define MOD_MODESHIFT (1 << 8) 229 #define MOD_NUMLOCK (1 << 9) 230 #define MOD_COMPOSE (1 << 10) 231 #define MOD_HOLDSCREEN (1 << 11) 232 #define MOD_COMMAND (1 << 12) 233 #define MOD_COMMAND1 (1 << 13) 234 #define MOD_COMMAND2 (1 << 14) 235 236 #define MOD_ANYSHIFT (MOD_SHIFT_L | MOD_SHIFT_R | MOD_SHIFTLOCK) 237 #define MOD_ANYCONTROL (MOD_CONTROL_L | MOD_CONTROL_R) 238 #define MOD_ANYMETA (MOD_META_L | MOD_META_R) 239 240 #define MOD_ONESET(id, mask) (((id)->t_modifiers & (mask)) != 0) 241 #define MOD_ALLSET(id, mask) (((id)->t_modifiers & (mask)) == (mask)) 242 243 #define GETMODSTATE(src, dst) \ 244 do { \ 245 dst |= (src & MOD_SHIFT_L) ? MOD_SHIFT_L : 0; \ 246 dst |= (src & MOD_SHIFT_R) ? MOD_SHIFT_R : 0; \ 247 dst |= (src & MOD_CONTROL_L) ? MOD_CONTROL_L : 0; \ 248 dst |= (src & MOD_CONTROL_R) ? MOD_CONTROL_R : 0; \ 249 dst |= (src & MOD_META_L) ? MOD_META_L : 0; \ 250 dst |= (src & MOD_META_R) ? MOD_META_R : 0; \ 251 } while (0) 252 253 static int wskbd_match(device_t, cfdata_t, void *); 254 static void wskbd_attach(device_t, device_t, void *); 255 static int wskbd_detach(device_t, int); 256 static int wskbd_activate(device_t, enum devact); 257 258 static int wskbd_displayioctl(device_t, u_long, void *, int, 259 struct lwp *); 260 #if NWSDISPLAY > 0 261 static int wskbd_set_display(device_t, struct wsevsrc *); 262 #else 263 #define wskbd_set_display NULL 264 #endif 265 266 static inline void update_leds(struct wskbd_internal *); 267 static inline void update_modifier(struct wskbd_internal *, u_int, int, int); 268 static int internal_command(struct wskbd_softc *, u_int *, keysym_t, keysym_t); 269 static int wskbd_translate(struct wskbd_internal *, u_int, int); 270 static int wskbd_enable(struct wskbd_softc *, int); 271 #if NWSDISPLAY > 0 272 static void change_displayparam(struct wskbd_softc *, int, int, int); 273 static void wskbd_holdscreen(struct wskbd_softc *, int); 274 #endif 275 276 static int wskbd_do_ioctl_sc(struct wskbd_softc *, u_long, void *, int, 277 struct lwp *); 278 static void wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value); 279 280 #if NWSMUX > 0 281 static int wskbd_mux_open(struct wsevsrc *, struct wseventvar *); 282 static int wskbd_mux_close(struct wsevsrc *); 283 #else 284 #define wskbd_mux_open NULL 285 #define wskbd_mux_close NULL 286 #endif 287 288 static int wskbd_do_open(struct wskbd_softc *, struct wseventvar *); 289 static int wskbd_do_ioctl(device_t, u_long, void *, int, struct lwp *); 290 291 CFATTACH_DECL_NEW(wskbd, sizeof (struct wskbd_softc), 292 wskbd_match, wskbd_attach, wskbd_detach, wskbd_activate); 293 294 dev_type_open(wskbdopen); 295 dev_type_close(wskbdclose); 296 dev_type_read(wskbdread); 297 dev_type_ioctl(wskbdioctl); 298 dev_type_poll(wskbdpoll); 299 dev_type_kqfilter(wskbdkqfilter); 300 301 const struct cdevsw wskbd_cdevsw = { 302 .d_open = wskbdopen, 303 .d_close = wskbdclose, 304 .d_read = wskbdread, 305 .d_write = nowrite, 306 .d_ioctl = wskbdioctl, 307 .d_stop = nostop, 308 .d_tty = notty, 309 .d_poll = wskbdpoll, 310 .d_mmap = nommap, 311 .d_kqfilter = wskbdkqfilter, 312 .d_discard = nodiscard, 313 .d_flag = D_OTHER 314 }; 315 316 #ifdef WSDISPLAY_SCROLLSUPPORT 317 struct wskbd_scroll_data wskbd_default_scroll_data = { 318 WSKBD_SCROLL_DOALL, 319 WSKBD_SCROLL_MODE_NORMAL, 320 #ifdef WSDISPLAY_SCROLLCOMBO 321 WSDISPLAY_SCROLLCOMBO, 322 #else 323 MOD_SHIFT_L, 324 #endif 325 }; 326 #endif 327 328 #ifndef WSKBD_DEFAULT_KEYREPEAT_DEL1 329 #define WSKBD_DEFAULT_KEYREPEAT_DEL1 400 /* 400ms to start repeating */ 330 #endif 331 #ifndef WSKBD_DEFAULT_KEYREPEAT_DELN 332 #define WSKBD_DEFAULT_KEYREPEAT_DELN 100 /* 100ms to between repeats */ 333 #endif 334 335 struct wskbd_keyrepeat_data wskbd_default_keyrepeat_data = { 336 WSKBD_KEYREPEAT_DOALL, 337 WSKBD_DEFAULT_KEYREPEAT_DEL1, 338 WSKBD_DEFAULT_KEYREPEAT_DELN, 339 }; 340 341 #if NWSDISPLAY > 0 || NWSMUX > 0 342 struct wssrcops wskbd_srcops = { 343 WSMUX_KBD, 344 wskbd_mux_open, wskbd_mux_close, wskbd_do_ioctl, 345 wskbd_displayioctl, wskbd_set_display 346 }; 347 #endif 348 349 static bool wskbd_suspend(device_t dv, const pmf_qual_t *); 350 static void wskbd_repeat(void *v); 351 352 static int wskbd_console_initted; 353 static struct wskbd_softc *wskbd_console_device; 354 static struct wskbd_internal wskbd_console_data; 355 356 static void wskbd_update_layout(struct wskbd_internal *, kbd_t); 357 358 static void 359 wskbd_update_layout(struct wskbd_internal *id, kbd_t enc) 360 { 361 362 if (enc & KB_METAESC) 363 id->t_flags |= WSKFL_METAESC; 364 else 365 id->t_flags &= ~WSKFL_METAESC; 366 } 367 368 /* 369 * Print function (for parent devices). 370 */ 371 int 372 wskbddevprint(void *aux, const char *pnp) 373 { 374 #if 0 375 struct wskbddev_attach_args *ap = aux; 376 #endif 377 378 if (pnp) 379 aprint_normal("wskbd at %s", pnp); 380 #if 0 381 aprint_normal(" console %d", ap->console); 382 #endif 383 384 return (UNCONF); 385 } 386 387 int 388 wskbd_match(device_t parent, cfdata_t match, void *aux) 389 { 390 struct wskbddev_attach_args *ap = aux; 391 392 if (match->wskbddevcf_console != WSKBDDEVCF_CONSOLE_UNK) { 393 /* 394 * If console-ness of device specified, either match 395 * exactly (at high priority), or fail. 396 */ 397 if (match->wskbddevcf_console != 0 && ap->console != 0) 398 return (10); 399 else 400 return (0); 401 } 402 403 /* If console-ness unspecified, it wins. */ 404 return (1); 405 } 406 407 void 408 wskbd_attach(device_t parent, device_t self, void *aux) 409 { 410 struct wskbd_softc *sc = device_private(self); 411 struct wskbddev_attach_args *ap = aux; 412 #if NWSMUX > 0 413 int mux, error; 414 #endif 415 416 sc->sc_base.me_dv = self; 417 sc->sc_isconsole = ap->console; 418 sc->sc_hotkey = NULL; 419 sc->sc_hotkeycookie = NULL; 420 sc->sc_evtrans_len = 0; 421 sc->sc_evtrans = NULL; 422 423 #if NWSMUX > 0 || NWSDISPLAY > 0 424 sc->sc_base.me_ops = &wskbd_srcops; 425 #endif 426 #if NWSMUX > 0 427 mux = device_cfdata(sc->sc_base.me_dv)->wskbddevcf_mux; 428 if (ap->console) { 429 /* Ignore mux for console; it always goes to the console mux. */ 430 /* printf(" (mux %d ignored for console)", mux); */ 431 mux = -1; 432 } 433 if (mux >= 0) 434 aprint_normal(" mux %d", mux); 435 #else 436 if (device_cfdata(sc->sc_base.me_dv)->wskbddevcf_mux >= 0) 437 aprint_normal(" (mux ignored)"); 438 #endif 439 440 if (ap->console) { 441 sc->id = &wskbd_console_data; 442 } else { 443 sc->id = malloc(sizeof(struct wskbd_internal), 444 M_DEVBUF, M_WAITOK|M_ZERO); 445 sc->id->t_keymap = ap->keymap; 446 wskbd_update_layout(sc->id, ap->keymap->layout); 447 } 448 449 callout_init(&sc->sc_repeat_ch, 0); 450 callout_setfunc(&sc->sc_repeat_ch, wskbd_repeat, sc); 451 452 sc->id->t_sc = sc; 453 454 sc->sc_accessops = ap->accessops; 455 sc->sc_accesscookie = ap->accesscookie; 456 sc->sc_repeating = 0; 457 sc->sc_translating = 1; 458 sc->sc_ledstate = -1; /* force update */ 459 460 if (wskbd_load_keymap(sc->id->t_keymap, 461 &sc->sc_map, &sc->sc_maplen) != 0) 462 panic("cannot load keymap"); 463 464 sc->sc_layout = sc->id->t_keymap->layout; 465 466 /* set default bell and key repeat data */ 467 sc->sc_bell_data = wskbd_default_bell_data; 468 sc->sc_keyrepeat_data = wskbd_default_keyrepeat_data; 469 470 #ifdef WSDISPLAY_SCROLLSUPPORT 471 sc->sc_scroll_data = wskbd_default_scroll_data; 472 #endif 473 474 if (ap->console) { 475 KASSERT(wskbd_console_initted); 476 KASSERT(wskbd_console_device == NULL); 477 478 wskbd_console_device = sc; 479 480 aprint_naive(": console keyboard"); 481 aprint_normal(": console keyboard"); 482 483 #if NWSDISPLAY > 0 484 wsdisplay_set_console_kbd(&sc->sc_base); /* sets me_dispv */ 485 if (sc->sc_base.me_dispdv != NULL) 486 aprint_normal(", using %s", 487 device_xname(sc->sc_base.me_dispdv)); 488 #endif 489 } 490 aprint_naive("\n"); 491 aprint_normal("\n"); 492 493 #if NWSMUX > 0 494 if (mux >= 0) { 495 error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base); 496 if (error) 497 aprint_error_dev(sc->sc_base.me_dv, 498 "attach error=%d\n", error); 499 } 500 #endif 501 502 if (!pmf_device_register(self, wskbd_suspend, NULL)) 503 aprint_error_dev(self, "couldn't establish power handler\n"); 504 else if (!pmf_class_input_register(self)) 505 aprint_error_dev(self, "couldn't register as input device\n"); 506 } 507 508 static bool 509 wskbd_suspend(device_t dv, const pmf_qual_t *qual) 510 { 511 struct wskbd_softc *sc = device_private(dv); 512 513 sc->sc_repeating = 0; 514 callout_stop(&sc->sc_repeat_ch); 515 516 return true; 517 } 518 519 void 520 wskbd_cnattach(const struct wskbd_consops *consops, void *conscookie, 521 const struct wskbd_mapdata *mapdata) 522 { 523 KASSERT(!wskbd_console_initted); 524 525 wskbd_console_data.t_keymap = mapdata; 526 wskbd_update_layout(&wskbd_console_data, mapdata->layout); 527 528 wskbd_console_data.t_consops = consops; 529 wskbd_console_data.t_consaccesscookie = conscookie; 530 531 #if NWSDISPLAY > 0 532 wsdisplay_set_cons_kbd(wskbd_cngetc, wskbd_cnpollc, wskbd_cnbell); 533 #endif 534 535 wskbd_console_initted = 1; 536 } 537 538 void 539 wskbd_cndetach(void) 540 { 541 KASSERT(wskbd_console_initted); 542 543 wskbd_console_data.t_keymap = 0; 544 545 wskbd_console_data.t_consops = 0; 546 wskbd_console_data.t_consaccesscookie = 0; 547 548 #if NWSDISPLAY > 0 549 wsdisplay_unset_cons_kbd(); 550 #endif 551 552 wskbd_console_initted = 0; 553 } 554 555 static void 556 wskbd_repeat(void *v) 557 { 558 struct wskbd_softc *sc = (struct wskbd_softc *)v; 559 int s = spltty(); 560 561 if (!sc->sc_repeating) { 562 /* 563 * race condition: a "key up" event came in when wskbd_repeat() 564 * was already called but not yet spltty()'d 565 */ 566 splx(s); 567 return; 568 } 569 if (sc->sc_translating) { 570 /* deliver keys */ 571 #if NWSDISPLAY > 0 572 if (sc->sc_base.me_dispdv != NULL) { 573 int i; 574 for (i = 0; i < sc->sc_repeating; i++) 575 wsdisplay_kbdinput(sc->sc_base.me_dispdv, 576 sc->id->t_symbols[i]); 577 } 578 #endif 579 } else { 580 #if defined(WSKBD_EVENT_AUTOREPEAT) 581 /* queue event */ 582 wskbd_deliver_event(sc, sc->sc_repeat_type, 583 sc->sc_repeat_value); 584 #endif /* defined(WSKBD_EVENT_AUTOREPEAT) */ 585 } 586 callout_schedule(&sc->sc_repeat_ch, mstohz(sc->sc_keyrepeat_data.delN)); 587 splx(s); 588 } 589 590 int 591 wskbd_activate(device_t self, enum devact act) 592 { 593 struct wskbd_softc *sc = device_private(self); 594 595 if (act == DVACT_DEACTIVATE) 596 sc->sc_dying = 1; 597 return (0); 598 } 599 600 /* 601 * Detach a keyboard. To keep track of users of the softc we keep 602 * a reference count that's incremented while inside, e.g., read. 603 * If the keyboard is active and the reference count is > 0 (0 is the 604 * normal state) we post an event and then wait for the process 605 * that had the reference to wake us up again. Then we blow away the 606 * vnode and return (which will deallocate the softc). 607 */ 608 int 609 wskbd_detach(device_t self, int flags) 610 { 611 struct wskbd_softc *sc = device_private(self); 612 struct wseventvar *evar; 613 int maj, mn; 614 int s; 615 616 #if NWSMUX > 0 617 /* Tell parent mux we're leaving. */ 618 if (sc->sc_base.me_parent != NULL) 619 wsmux_detach_sc(&sc->sc_base); 620 #endif 621 622 callout_halt(&sc->sc_repeat_ch, NULL); 623 callout_destroy(&sc->sc_repeat_ch); 624 625 if (sc->sc_isconsole) { 626 KASSERT(wskbd_console_device == sc); 627 wskbd_console_device = NULL; 628 } 629 630 pmf_device_deregister(self); 631 632 evar = sc->sc_base.me_evp; 633 if (evar != NULL && evar->io != NULL) { 634 s = spltty(); 635 if (--sc->sc_refcnt >= 0) { 636 struct wscons_event event; 637 638 /* Wake everyone by generating a dummy event. */ 639 event.type = 0; 640 event.value = 0; 641 if (wsevent_inject(evar, &event, 1) != 0) 642 wsevent_wakeup(evar); 643 644 /* Wait for processes to go away. */ 645 if (tsleep(sc, PZERO, "wskdet", hz * 60)) 646 aprint_error("wskbd_detach: %s didn't detach\n", 647 device_xname(self)); 648 } 649 splx(s); 650 } 651 652 /* locate the major number */ 653 maj = cdevsw_lookup_major(&wskbd_cdevsw); 654 655 /* Nuke the vnodes for any open instances. */ 656 mn = device_unit(self); 657 vdevgone(maj, mn, mn, VCHR); 658 659 return (0); 660 } 661 662 void 663 wskbd_input(device_t dev, u_int type, int value) 664 { 665 struct wskbd_softc *sc = device_private(dev); 666 #if NWSDISPLAY > 0 667 int num, i; 668 #endif 669 670 if (sc->sc_repeating) { 671 sc->sc_repeating = 0; 672 callout_stop(&sc->sc_repeat_ch); 673 } 674 675 device_active(dev, DVA_HARDWARE); 676 677 #if NWSDISPLAY > 0 678 /* 679 * If /dev/wskbdN is not connected in event mode translate and 680 * send upstream. 681 */ 682 if (sc->sc_translating) { 683 num = wskbd_translate(sc->id, type, value); 684 if (num > 0) { 685 if (sc->sc_base.me_dispdv != NULL) { 686 #ifdef WSDISPLAY_SCROLLSUPPORT 687 if (sc->id->t_symbols [0] != KS_Print_Screen) { 688 wsdisplay_scroll(sc->sc_base. 689 me_dispdv, WSDISPLAY_SCROLL_RESET); 690 } 691 #endif 692 for (i = 0; i < num; i++) 693 wsdisplay_kbdinput( 694 sc->sc_base.me_dispdv, 695 sc->id->t_symbols[i]); 696 } 697 698 if (sc->sc_keyrepeat_data.del1 != 0) { 699 sc->sc_repeating = num; 700 callout_schedule(&sc->sc_repeat_ch, 701 mstohz(sc->sc_keyrepeat_data.del1)); 702 } 703 } 704 return; 705 } 706 #endif 707 708 wskbd_deliver_event(sc, type, value); 709 710 #if defined(WSKBD_EVENT_AUTOREPEAT) 711 /* Repeat key presses if set. */ 712 if (type == WSCONS_EVENT_KEY_DOWN && sc->sc_keyrepeat_data.del1 != 0) { 713 sc->sc_repeat_type = type; 714 sc->sc_repeat_value = value; 715 sc->sc_repeating = 1; 716 callout_schedule(&sc->sc_repeat_ch, 717 mstohz(sc->sc_keyrepeat_data.del1)); 718 } 719 #endif /* defined(WSKBD_EVENT_AUTOREPEAT) */ 720 } 721 722 /* 723 * Keyboard is generating events. Turn this keystroke into an 724 * event and put it in the queue. If the queue is full, the 725 * keystroke is lost (sorry!). 726 */ 727 static void 728 wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value) 729 { 730 struct wseventvar *evar; 731 struct wscons_event event; 732 733 evar = sc->sc_base.me_evp; 734 735 if (evar == NULL || evar->q == NULL) { 736 DPRINTF(("wskbd_input: not open\n")); 737 return; 738 } 739 740 event.type = type; 741 event.value = 0; 742 DPRINTF(("%d ->", value)); 743 if (sc->sc_evtrans_len > 0) { 744 if (sc->sc_evtrans_len > value) { 745 DPRINTF(("%d", sc->sc_evtrans[value])); 746 event.value = sc->sc_evtrans[value]; 747 } 748 } else { 749 event.value = value; 750 } 751 DPRINTF(("\n")); 752 if (wsevent_inject(evar, &event, 1) != 0) 753 log(LOG_WARNING, "%s: event queue overflow\n", 754 device_xname(sc->sc_base.me_dv)); 755 } 756 757 #ifdef WSDISPLAY_COMPAT_RAWKBD 758 void 759 wskbd_rawinput(device_t dev, u_char *tbuf, int len) 760 { 761 #if NWSDISPLAY > 0 762 struct wskbd_softc *sc = device_private(dev); 763 int i; 764 765 if (sc->sc_base.me_dispdv != NULL) 766 for (i = 0; i < len; i++) 767 wsdisplay_kbdinput(sc->sc_base.me_dispdv, tbuf[i]); 768 /* this is KS_GROUP_Plain */ 769 #endif 770 } 771 #endif /* WSDISPLAY_COMPAT_RAWKBD */ 772 773 #if NWSDISPLAY > 0 774 static void 775 wskbd_holdscreen(struct wskbd_softc *sc, int hold) 776 { 777 int new_state; 778 779 if (sc->sc_base.me_dispdv != NULL) { 780 wsdisplay_kbdholdscreen(sc->sc_base.me_dispdv, hold); 781 new_state = sc->sc_ledstate; 782 if (hold) { 783 #ifdef WSDISPLAY_SCROLLSUPPORT 784 sc->sc_scroll_data.mode = WSKBD_SCROLL_MODE_HOLD; 785 #endif 786 new_state |= WSKBD_LED_SCROLL; 787 } else { 788 #ifdef WSDISPLAY_SCROLLSUPPORT 789 sc->sc_scroll_data.mode = WSKBD_SCROLL_MODE_NORMAL; 790 #endif 791 new_state &= ~WSKBD_LED_SCROLL; 792 } 793 if (new_state != sc->sc_ledstate) { 794 (*sc->sc_accessops->set_leds)(sc->sc_accesscookie, 795 new_state); 796 sc->sc_ledstate = new_state; 797 #ifdef WSDISPLAY_SCROLLSUPPORT 798 if (!hold) 799 wsdisplay_scroll(sc->sc_base.me_dispdv, 800 WSDISPLAY_SCROLL_RESET); 801 #endif 802 } 803 } 804 } 805 #endif 806 807 static int 808 wskbd_enable(struct wskbd_softc *sc, int on) 809 { 810 int error; 811 812 #if 0 813 /* I don't understand the purpose of this code. And it seems to 814 * break things, so it's out. -- Lennart 815 */ 816 if (!on && (!sc->sc_translating 817 #if NWSDISPLAY > 0 818 || sc->sc_base.me_dispdv 819 #endif 820 )) 821 return (EBUSY); 822 #endif 823 #if NWSDISPLAY > 0 824 if (sc->sc_base.me_dispdv != NULL) 825 return (0); 826 #endif 827 828 /* Always cancel auto repeat when fiddling with the kbd. */ 829 if (sc->sc_repeating) { 830 sc->sc_repeating = 0; 831 callout_stop(&sc->sc_repeat_ch); 832 } 833 834 error = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on); 835 DPRINTF(("wskbd_enable: sc=%p on=%d res=%d\n", sc, on, error)); 836 return (error); 837 } 838 839 #if NWSMUX > 0 840 int 841 wskbd_mux_open(struct wsevsrc *me, struct wseventvar *evp) 842 { 843 struct wskbd_softc *sc = (struct wskbd_softc *)me; 844 845 if (sc->sc_dying) 846 return (EIO); 847 848 if (sc->sc_base.me_evp != NULL) 849 return (EBUSY); 850 851 return (wskbd_do_open(sc, evp)); 852 } 853 #endif 854 855 int 856 wskbdopen(dev_t dev, int flags, int mode, struct lwp *l) 857 { 858 struct wskbd_softc *sc = device_lookup_private(&wskbd_cd, minor(dev)); 859 struct wseventvar *evar; 860 int error; 861 862 if (sc == NULL) 863 return (ENXIO); 864 865 #if NWSMUX > 0 866 DPRINTF(("wskbdopen: %s mux=%p l=%p\n", 867 device_xname(sc->sc_base.me_dv), sc->sc_base.me_parent, l)); 868 #endif 869 870 if (sc->sc_dying) 871 return (EIO); 872 873 if ((flags & (FREAD | FWRITE)) == FWRITE) 874 /* Not opening for read, only ioctl is available. */ 875 return (0); 876 877 #if NWSMUX > 0 878 if (sc->sc_base.me_parent != NULL) { 879 /* Grab the keyboard out of the greedy hands of the mux. */ 880 DPRINTF(("wskbdopen: detach\n")); 881 wsmux_detach_sc(&sc->sc_base); 882 } 883 #endif 884 885 if (sc->sc_base.me_evp != NULL) 886 return (EBUSY); 887 888 evar = &sc->sc_base.me_evar; 889 wsevent_init(evar, l->l_proc); 890 891 error = wskbd_do_open(sc, evar); 892 if (error) { 893 DPRINTF(("wskbdopen: %s open failed\n", 894 device_xname(sc->sc_base.me_dv))); 895 sc->sc_base.me_evp = NULL; 896 wsevent_fini(evar); 897 } 898 return (error); 899 } 900 901 int 902 wskbd_do_open(struct wskbd_softc *sc, struct wseventvar *evp) 903 { 904 sc->sc_base.me_evp = evp; 905 sc->sc_translating = 0; 906 907 return (wskbd_enable(sc, 1)); 908 } 909 910 int 911 wskbdclose(dev_t dev, int flags, int mode, 912 struct lwp *l) 913 { 914 struct wskbd_softc *sc = 915 device_lookup_private(&wskbd_cd, minor(dev)); 916 struct wseventvar *evar = sc->sc_base.me_evp; 917 918 #if NWSMUX > 0 919 DPRINTF(("wskbdclose: %s mux=%p p=%p\n", device_xname(sc->sc_base.me_dv), 920 sc->sc_base.me_parent, l)); 921 #endif 922 923 if (evar == NULL) { 924 /* not open for read */ 925 return (0); 926 } 927 928 sc->sc_base.me_evp = NULL; 929 sc->sc_translating = 1; 930 (void)wskbd_enable(sc, 0); 931 wsevent_fini(evar); 932 933 return (0); 934 } 935 936 #if NWSMUX > 0 937 int 938 wskbd_mux_close(struct wsevsrc *me) 939 { 940 struct wskbd_softc *sc = (struct wskbd_softc *)me; 941 942 sc->sc_base.me_evp = NULL; 943 sc->sc_translating = 1; 944 (void)wskbd_enable(sc, 0); 945 946 return (0); 947 } 948 #endif 949 950 int 951 wskbdread(dev_t dev, struct uio *uio, int flags) 952 { 953 struct wskbd_softc *sc = 954 device_lookup_private(&wskbd_cd, minor(dev)); 955 int error; 956 957 if (sc->sc_dying) 958 return (EIO); 959 960 KASSERTMSG(sc->sc_base.me_evp != NULL, "wskbdread: evp == NULL\n"); 961 962 sc->sc_refcnt++; 963 error = wsevent_read(sc->sc_base.me_evp, uio, flags); 964 if (--sc->sc_refcnt < 0) { 965 wakeup(sc); 966 error = EIO; 967 } 968 return (error); 969 } 970 971 int 972 wskbdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 973 { 974 return (wskbd_do_ioctl(device_lookup(&wskbd_cd, minor(dev)), 975 cmd, data, flag,l)); 976 } 977 978 /* A wrapper around the ioctl() workhorse to make reference counting easy. */ 979 int 980 wskbd_do_ioctl(device_t dv, u_long cmd, void *data, int flag, 981 struct lwp *l) 982 { 983 struct wskbd_softc *sc = device_private(dv); 984 int error; 985 986 sc->sc_refcnt++; 987 error = wskbd_do_ioctl_sc(sc, cmd, data, flag, l); 988 if (--sc->sc_refcnt < 0) 989 wakeup(sc); 990 return (error); 991 } 992 993 int 994 wskbd_do_ioctl_sc(struct wskbd_softc *sc, u_long cmd, void *data, int flag, 995 struct lwp *l) 996 { 997 998 /* 999 * Try the generic ioctls that the wskbd interface supports. 1000 */ 1001 switch (cmd) { 1002 case FIONBIO: /* we will remove this someday (soon???) */ 1003 return (0); 1004 1005 case FIOASYNC: 1006 if (sc->sc_base.me_evp == NULL) 1007 return (EINVAL); 1008 sc->sc_base.me_evp->async = *(int *)data != 0; 1009 return (0); 1010 1011 case FIOSETOWN: 1012 if (sc->sc_base.me_evp == NULL) 1013 return (EINVAL); 1014 if (-*(int *)data != sc->sc_base.me_evp->io->p_pgid 1015 && *(int *)data != sc->sc_base.me_evp->io->p_pid) 1016 return (EPERM); 1017 return (0); 1018 1019 case TIOCSPGRP: 1020 if (sc->sc_base.me_evp == NULL) 1021 return (EINVAL); 1022 if (*(int *)data != sc->sc_base.me_evp->io->p_pgid) 1023 return (EPERM); 1024 return (0); 1025 } 1026 1027 /* 1028 * Try the keyboard driver for WSKBDIO ioctls. It returns EPASSTHROUGH 1029 * if it didn't recognize the request. 1030 */ 1031 return (wskbd_displayioctl(sc->sc_base.me_dv, cmd, data, flag, l)); 1032 } 1033 1034 /* 1035 * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode. 1036 * Some of these have no real effect in raw mode, however. 1037 */ 1038 static int 1039 wskbd_displayioctl(device_t dev, u_long cmd, void *data, int flag, 1040 struct lwp *l) 1041 { 1042 #ifdef WSDISPLAY_SCROLLSUPPORT 1043 struct wskbd_scroll_data *usdp, *ksdp; 1044 #endif 1045 struct wskbd_softc *sc = device_private(dev); 1046 struct wskbd_bell_data *ubdp, *kbdp; 1047 struct wskbd_keyrepeat_data *ukdp, *kkdp; 1048 struct wskbd_map_data *umdp; 1049 struct wskbd_mapdata md; 1050 kbd_t enc; 1051 void *tbuf; 1052 int len, error; 1053 1054 switch (cmd) { 1055 case WSKBDIO_BELL: 1056 if ((flag & FWRITE) == 0) 1057 return (EACCES); 1058 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, 1059 WSKBDIO_COMPLEXBELL, (void *)&sc->sc_bell_data, flag, l)); 1060 1061 case WSKBDIO_COMPLEXBELL: 1062 if ((flag & FWRITE) == 0) 1063 return (EACCES); 1064 ubdp = (struct wskbd_bell_data *)data; 1065 SETBELL(ubdp, ubdp, &sc->sc_bell_data); 1066 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, 1067 WSKBDIO_COMPLEXBELL, (void *)ubdp, flag, l)); 1068 1069 case WSKBDIO_SETBELL: 1070 if ((flag & FWRITE) == 0) 1071 return (EACCES); 1072 kbdp = &sc->sc_bell_data; 1073 setbell: 1074 ubdp = (struct wskbd_bell_data *)data; 1075 SETBELL(kbdp, ubdp, kbdp); 1076 return (0); 1077 1078 case WSKBDIO_GETBELL: 1079 kbdp = &sc->sc_bell_data; 1080 getbell: 1081 ubdp = (struct wskbd_bell_data *)data; 1082 SETBELL(ubdp, kbdp, kbdp); 1083 return (0); 1084 1085 case WSKBDIO_SETDEFAULTBELL: 1086 if ((error = kauth_authorize_device(l->l_cred, 1087 KAUTH_DEVICE_WSCONS_KEYBOARD_BELL, NULL, NULL, 1088 NULL, NULL)) != 0) 1089 return (error); 1090 kbdp = &wskbd_default_bell_data; 1091 goto setbell; 1092 1093 1094 case WSKBDIO_GETDEFAULTBELL: 1095 kbdp = &wskbd_default_bell_data; 1096 goto getbell; 1097 1098 #undef SETBELL 1099 1100 #define SETKEYREPEAT(dstp, srcp, dfltp) \ 1101 do { \ 1102 (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ? \ 1103 (srcp)->del1 : (dfltp)->del1; \ 1104 (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ? \ 1105 (srcp)->delN : (dfltp)->delN; \ 1106 (dstp)->which = WSKBD_KEYREPEAT_DOALL; \ 1107 } while (0) 1108 1109 case WSKBDIO_SETKEYREPEAT: 1110 if ((flag & FWRITE) == 0) 1111 return (EACCES); 1112 kkdp = &sc->sc_keyrepeat_data; 1113 setkeyrepeat: 1114 ukdp = (struct wskbd_keyrepeat_data *)data; 1115 SETKEYREPEAT(kkdp, ukdp, kkdp); 1116 return (0); 1117 1118 case WSKBDIO_GETKEYREPEAT: 1119 kkdp = &sc->sc_keyrepeat_data; 1120 getkeyrepeat: 1121 ukdp = (struct wskbd_keyrepeat_data *)data; 1122 SETKEYREPEAT(ukdp, kkdp, kkdp); 1123 return (0); 1124 1125 case WSKBDIO_SETDEFAULTKEYREPEAT: 1126 if ((error = kauth_authorize_device(l->l_cred, 1127 KAUTH_DEVICE_WSCONS_KEYBOARD_KEYREPEAT, NULL, NULL, 1128 NULL, NULL)) != 0) 1129 return (error); 1130 kkdp = &wskbd_default_keyrepeat_data; 1131 goto setkeyrepeat; 1132 1133 1134 case WSKBDIO_GETDEFAULTKEYREPEAT: 1135 kkdp = &wskbd_default_keyrepeat_data; 1136 goto getkeyrepeat; 1137 1138 #ifdef WSDISPLAY_SCROLLSUPPORT 1139 #define SETSCROLLMOD(dstp, srcp, dfltp) \ 1140 do { \ 1141 (dstp)->mode = ((srcp)->which & WSKBD_SCROLL_DOMODE) ? \ 1142 (srcp)->mode : (dfltp)->mode; \ 1143 (dstp)->modifier = ((srcp)->which & WSKBD_SCROLL_DOMODIFIER) ? \ 1144 (srcp)->modifier : (dfltp)->modifier; \ 1145 (dstp)->which = WSKBD_SCROLL_DOALL; \ 1146 } while (0) 1147 1148 case WSKBDIO_SETSCROLL: 1149 usdp = (struct wskbd_scroll_data *)data; 1150 ksdp = &sc->sc_scroll_data; 1151 SETSCROLLMOD(ksdp, usdp, ksdp); 1152 return (0); 1153 1154 case WSKBDIO_GETSCROLL: 1155 usdp = (struct wskbd_scroll_data *)data; 1156 ksdp = &sc->sc_scroll_data; 1157 SETSCROLLMOD(usdp, ksdp, ksdp); 1158 return (0); 1159 #else 1160 case WSKBDIO_GETSCROLL: 1161 case WSKBDIO_SETSCROLL: 1162 return ENODEV; 1163 #endif 1164 1165 #undef SETKEYREPEAT 1166 1167 case WSKBDIO_SETMAP: 1168 if ((flag & FWRITE) == 0) 1169 return (EACCES); 1170 umdp = (struct wskbd_map_data *)data; 1171 if (umdp->maplen > WSKBDIO_MAXMAPLEN) 1172 return (EINVAL); 1173 1174 len = umdp->maplen*sizeof(struct wscons_keymap); 1175 tbuf = malloc(len, M_TEMP, M_WAITOK); 1176 error = copyin(umdp->map, tbuf, len); 1177 if (error == 0) { 1178 wskbd_init_keymap(umdp->maplen, 1179 &sc->sc_map, &sc->sc_maplen); 1180 memcpy(sc->sc_map, tbuf, len); 1181 /* drop the variant bits handled by the map */ 1182 sc->sc_layout = KB_USER | 1183 (KB_VARIANT(sc->sc_layout) & KB_HANDLEDBYWSKBD); 1184 wskbd_update_layout(sc->id, sc->sc_layout); 1185 } 1186 free(tbuf, M_TEMP); 1187 return(error); 1188 1189 case WSKBDIO_GETMAP: { 1190 int i; 1191 1192 umdp = (struct wskbd_map_data *)data; 1193 if (sc->sc_evtrans_len > 0) { 1194 /* we're translating scancodes so we need to generate an 1195 * appropriate map or clients will be *very* confused */ 1196 int new_maplen = 0; 1197 int code; 1198 struct wscons_keymap new_map[256]; 1199 1200 memset(new_map, 0, sizeof(new_map)); 1201 for (i = 0; i < sc->sc_evtrans_len; i++) { 1202 code = sc->sc_evtrans[i]; 1203 if (code > 255) continue; 1204 if (code >= new_maplen) 1205 new_maplen = code + 1; 1206 /* do not overwrite entries */ 1207 if (new_map[code].group1[0] == 0) 1208 new_map[code] = sc->sc_map[i]; 1209 } 1210 if (umdp->maplen > new_maplen) 1211 umdp->maplen = new_maplen; 1212 error = copyout(new_map, umdp->map, 1213 umdp->maplen*sizeof(struct wscons_keymap)); 1214 } else { 1215 if (umdp->maplen > sc->sc_maplen) 1216 umdp->maplen = sc->sc_maplen; 1217 error = copyout(sc->sc_map, umdp->map, 1218 umdp->maplen*sizeof(struct wscons_keymap)); 1219 } 1220 return(error); 1221 } 1222 1223 case WSKBDIO_GETENCODING: 1224 *((kbd_t *) data) = sc->sc_layout; 1225 return(0); 1226 1227 case WSKBDIO_SETENCODING: 1228 if ((flag & FWRITE) == 0) 1229 return (EACCES); 1230 enc = *((kbd_t *)data); 1231 if (KB_ENCODING(enc) == KB_USER) { 1232 /* user map must already be loaded */ 1233 if (KB_ENCODING(sc->sc_layout) != KB_USER) 1234 return (EINVAL); 1235 /* map variants make no sense */ 1236 if (KB_VARIANT(enc) & ~KB_HANDLEDBYWSKBD) 1237 return (EINVAL); 1238 } else { 1239 md = *(sc->id->t_keymap); /* structure assignment */ 1240 md.layout = enc; 1241 error = wskbd_load_keymap(&md, &sc->sc_map, 1242 &sc->sc_maplen); 1243 if (error) 1244 return (error); 1245 } 1246 sc->sc_layout = enc; 1247 wskbd_update_layout(sc->id, enc); 1248 return (0); 1249 1250 case WSKBDIO_SETVERSION: 1251 return wsevent_setversion(sc->sc_base.me_evp, *(int *)data); 1252 } 1253 1254 /* 1255 * Try the keyboard driver for WSKBDIO ioctls. It returns -1 1256 * if it didn't recognize the request, and in turn we return 1257 * -1 if we didn't recognize the request. 1258 */ 1259 /* printf("kbdaccess\n"); */ 1260 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 1261 flag, l); 1262 #ifdef WSDISPLAY_COMPAT_RAWKBD 1263 if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) { 1264 int s = spltty(); 1265 sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R 1266 | MOD_CONTROL_L | MOD_CONTROL_R 1267 | MOD_META_L | MOD_META_R 1268 | MOD_COMMAND 1269 | MOD_COMMAND1 | MOD_COMMAND2); 1270 if (sc->sc_repeating) { 1271 sc->sc_repeating = 0; 1272 callout_stop(&sc->sc_repeat_ch); 1273 } 1274 splx(s); 1275 } 1276 #endif 1277 return (error); 1278 } 1279 1280 int 1281 wskbdpoll(dev_t dev, int events, struct lwp *l) 1282 { 1283 struct wskbd_softc *sc = 1284 device_lookup_private(&wskbd_cd, minor(dev)); 1285 1286 if (sc->sc_base.me_evp == NULL) 1287 return (POLLERR); 1288 return (wsevent_poll(sc->sc_base.me_evp, events, l)); 1289 } 1290 1291 int 1292 wskbdkqfilter(dev_t dev, struct knote *kn) 1293 { 1294 struct wskbd_softc *sc = 1295 device_lookup_private(&wskbd_cd, minor(dev)); 1296 1297 if (sc->sc_base.me_evp == NULL) 1298 return (1); 1299 return (wsevent_kqfilter(sc->sc_base.me_evp, kn)); 1300 } 1301 1302 #if NWSDISPLAY > 0 1303 1304 int 1305 wskbd_pickfree(void) 1306 { 1307 int i; 1308 struct wskbd_softc *sc; 1309 1310 for (i = 0; i < wskbd_cd.cd_ndevs; i++) { 1311 sc = device_lookup_private(&wskbd_cd, i); 1312 if (sc == NULL) 1313 continue; 1314 if (sc->sc_base.me_dispdv == NULL) 1315 return (i); 1316 } 1317 return (-1); 1318 } 1319 1320 struct wsevsrc * 1321 wskbd_set_console_display(device_t displaydv, struct wsevsrc *me) 1322 { 1323 struct wskbd_softc *sc = wskbd_console_device; 1324 1325 if (sc == NULL) 1326 return (NULL); 1327 sc->sc_base.me_dispdv = displaydv; 1328 #if NWSMUX > 0 1329 (void)wsmux_attach_sc((struct wsmux_softc *)me, &sc->sc_base); 1330 #endif 1331 return (&sc->sc_base); 1332 } 1333 1334 int 1335 wskbd_set_display(device_t dv, struct wsevsrc *me) 1336 { 1337 struct wskbd_softc *sc = device_private(dv); 1338 device_t displaydv = me != NULL ? me->me_dispdv : NULL; 1339 device_t odisplaydv; 1340 int error; 1341 1342 DPRINTF(("wskbd_set_display: %s me=%p odisp=%p disp=%p cons=%d\n", 1343 device_xname(dv), me, sc->sc_base.me_dispdv, displaydv, 1344 sc->sc_isconsole)); 1345 1346 if (sc->sc_isconsole) 1347 return (EBUSY); 1348 1349 if (displaydv != NULL) { 1350 if (sc->sc_base.me_dispdv != NULL) 1351 return (EBUSY); 1352 } else { 1353 if (sc->sc_base.me_dispdv == NULL) 1354 return (ENXIO); 1355 } 1356 1357 odisplaydv = sc->sc_base.me_dispdv; 1358 sc->sc_base.me_dispdv = NULL; 1359 error = wskbd_enable(sc, displaydv != NULL); 1360 sc->sc_base.me_dispdv = displaydv; 1361 if (error) { 1362 sc->sc_base.me_dispdv = odisplaydv; 1363 return (error); 1364 } 1365 1366 if (displaydv) 1367 aprint_verbose_dev(sc->sc_base.me_dv, "connecting to %s\n", 1368 device_xname(displaydv)); 1369 else 1370 aprint_verbose_dev(sc->sc_base.me_dv, "disconnecting from %s\n", 1371 device_xname(odisplaydv)); 1372 1373 return (0); 1374 } 1375 1376 #endif /* NWSDISPLAY > 0 */ 1377 1378 #if NWSMUX > 0 1379 int 1380 wskbd_add_mux(int unit, struct wsmux_softc *muxsc) 1381 { 1382 struct wskbd_softc *sc = device_lookup_private(&wskbd_cd, unit); 1383 1384 if (sc == NULL) 1385 return (ENXIO); 1386 1387 if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL) 1388 return (EBUSY); 1389 1390 return (wsmux_attach_sc(muxsc, &sc->sc_base)); 1391 } 1392 #endif 1393 1394 /* 1395 * Console interface. 1396 */ 1397 int 1398 wskbd_cngetc(dev_t dev) 1399 { 1400 static int num = 0; 1401 static int pos; 1402 u_int type; 1403 int data; 1404 keysym_t ks; 1405 1406 if (!wskbd_console_initted) 1407 return -1; 1408 1409 if (wskbd_console_device != NULL && 1410 !wskbd_console_device->sc_translating) 1411 return -1; 1412 1413 for(;;) { 1414 if (num-- > 0) { 1415 ks = wskbd_console_data.t_symbols[pos++]; 1416 if (KS_GROUP(ks) == KS_GROUP_Plain) 1417 return (KS_VALUE(ks)); 1418 } else { 1419 (*wskbd_console_data.t_consops->getc) 1420 (wskbd_console_data.t_consaccesscookie, 1421 &type, &data); 1422 if (type == 0) { 1423 /* No data returned */ 1424 return -1; 1425 } 1426 if (type == WSCONS_EVENT_ASCII) { 1427 /* 1428 * We assume that when the driver falls back 1429 * to deliver pure ASCII it is in a state that 1430 * it can not track press/release events 1431 * reliable - so we clear all previously 1432 * accumulated modifier state. 1433 */ 1434 wskbd_console_data.t_modifiers = 0; 1435 return(data); 1436 } 1437 num = wskbd_translate(&wskbd_console_data, type, data); 1438 pos = 0; 1439 } 1440 } 1441 } 1442 1443 void 1444 wskbd_cnpollc(dev_t dev, int poll) 1445 { 1446 1447 if (!wskbd_console_initted) 1448 return; 1449 1450 if (wskbd_console_device != NULL && 1451 !wskbd_console_device->sc_translating) 1452 return; 1453 1454 (*wskbd_console_data.t_consops->pollc) 1455 (wskbd_console_data.t_consaccesscookie, poll); 1456 } 1457 1458 void 1459 wskbd_cnbell(dev_t dev, u_int pitch, u_int period, u_int volume) 1460 { 1461 1462 if (!wskbd_console_initted) 1463 return; 1464 1465 if (wskbd_console_data.t_consops->bell != NULL) 1466 (*wskbd_console_data.t_consops->bell) 1467 (wskbd_console_data.t_consaccesscookie, pitch, period, 1468 volume); 1469 } 1470 1471 static inline void 1472 update_leds(struct wskbd_internal *id) 1473 { 1474 int new_state; 1475 1476 new_state = 0; 1477 if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK)) 1478 new_state |= WSKBD_LED_CAPS; 1479 if (id->t_modifiers & MOD_NUMLOCK) 1480 new_state |= WSKBD_LED_NUM; 1481 if (id->t_modifiers & MOD_COMPOSE) 1482 new_state |= WSKBD_LED_COMPOSE; 1483 if (id->t_modifiers & MOD_HOLDSCREEN) 1484 new_state |= WSKBD_LED_SCROLL; 1485 1486 if (id->t_sc && new_state != id->t_sc->sc_ledstate) { 1487 (*id->t_sc->sc_accessops->set_leds) 1488 (id->t_sc->sc_accesscookie, new_state); 1489 id->t_sc->sc_ledstate = new_state; 1490 } 1491 } 1492 1493 static inline void 1494 update_modifier(struct wskbd_internal *id, u_int type, int toggle, int mask) 1495 { 1496 if (toggle) { 1497 if (type == WSCONS_EVENT_KEY_DOWN) 1498 id->t_modifiers ^= mask; 1499 } else { 1500 if (type == WSCONS_EVENT_KEY_DOWN) 1501 id->t_modifiers |= mask; 1502 else 1503 id->t_modifiers &= ~mask; 1504 } 1505 } 1506 1507 #if NWSDISPLAY > 0 1508 static void 1509 change_displayparam(struct wskbd_softc *sc, int param, int updown, 1510 int wraparound) 1511 { 1512 int res; 1513 struct wsdisplay_param dp; 1514 1515 dp.param = param; 1516 res = wsdisplay_param(sc->sc_base.me_dispdv, WSDISPLAYIO_GETPARAM, &dp); 1517 1518 if (res == EINVAL) 1519 return; /* no such parameter */ 1520 1521 dp.curval += updown; 1522 if (dp.max < dp.curval) 1523 dp.curval = wraparound ? dp.min : dp.max; 1524 else 1525 if (dp.curval < dp.min) 1526 dp.curval = wraparound ? dp.max : dp.min; 1527 wsdisplay_param(sc->sc_base.me_dispdv, WSDISPLAYIO_SETPARAM, &dp); 1528 } 1529 #endif 1530 1531 static int 1532 internal_command(struct wskbd_softc *sc, u_int *type, keysym_t ksym, 1533 keysym_t ksym2) 1534 { 1535 #if NWSDISPLAY > 0 && defined(WSDISPLAY_SCROLLSUPPORT) 1536 u_int state = 0; 1537 #endif 1538 switch (ksym) { 1539 case KS_Cmd_VolumeToggle: 1540 if (*type == WSCONS_EVENT_KEY_DOWN) 1541 pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_TOGGLE); 1542 break; 1543 case KS_Cmd_VolumeUp: 1544 if (*type == WSCONS_EVENT_KEY_DOWN) 1545 pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_UP); 1546 break; 1547 case KS_Cmd_VolumeDown: 1548 if (*type == WSCONS_EVENT_KEY_DOWN) 1549 pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_DOWN); 1550 break; 1551 #if NWSDISPLAY > 0 && defined(WSDISPLAY_SCROLLSUPPORT) 1552 case KS_Cmd_ScrollFastUp: 1553 case KS_Cmd_ScrollFastDown: 1554 if (*type == WSCONS_EVENT_KEY_DOWN) { 1555 GETMODSTATE(sc->id->t_modifiers, state); 1556 if ((sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_HOLD 1557 && MOD_ONESET(sc->id, MOD_HOLDSCREEN)) 1558 || (sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_NORMAL 1559 && sc->sc_scroll_data.modifier == state)) { 1560 update_modifier(sc->id, *type, 0, MOD_COMMAND); 1561 wsdisplay_scroll(sc->sc_base.me_dispdv, 1562 (ksym == KS_Cmd_ScrollFastUp) ? 1563 WSDISPLAY_SCROLL_BACKWARD : 1564 WSDISPLAY_SCROLL_FORWARD); 1565 return (1); 1566 } else { 1567 return (0); 1568 } 1569 } else 1570 update_modifier(sc->id, *type, 0, MOD_COMMAND); 1571 break; 1572 1573 case KS_Cmd_ScrollSlowUp: 1574 case KS_Cmd_ScrollSlowDown: 1575 if (*type == WSCONS_EVENT_KEY_DOWN) { 1576 GETMODSTATE(sc->id->t_modifiers, state); 1577 if ((sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_HOLD 1578 && MOD_ONESET(sc->id, MOD_HOLDSCREEN)) 1579 || (sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_NORMAL 1580 && sc->sc_scroll_data.modifier == state)) { 1581 update_modifier(sc->id, *type, 0, MOD_COMMAND); 1582 wsdisplay_scroll(sc->sc_base.me_dispdv, 1583 (ksym == KS_Cmd_ScrollSlowUp) ? 1584 WSDISPLAY_SCROLL_BACKWARD | WSDISPLAY_SCROLL_LOW: 1585 WSDISPLAY_SCROLL_FORWARD | WSDISPLAY_SCROLL_LOW); 1586 return (1); 1587 } else { 1588 return (0); 1589 } 1590 } else 1591 update_modifier(sc->id, *type, 0, MOD_COMMAND); 1592 break; 1593 #endif 1594 1595 case KS_Cmd: 1596 update_modifier(sc->id, *type, 0, MOD_COMMAND); 1597 ksym = ksym2; 1598 break; 1599 1600 case KS_Cmd1: 1601 update_modifier(sc->id, *type, 0, MOD_COMMAND1); 1602 break; 1603 1604 case KS_Cmd2: 1605 update_modifier(sc->id, *type, 0, MOD_COMMAND2); 1606 break; 1607 } 1608 1609 if (*type != WSCONS_EVENT_KEY_DOWN || 1610 (! MOD_ONESET(sc->id, MOD_COMMAND) && 1611 ! MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2))) 1612 return (0); 1613 1614 #if defined(DDB) || defined(KGDB) 1615 if (ksym == KS_Cmd_Debugger) { 1616 if (sc->sc_isconsole) { 1617 #ifdef DDB 1618 console_debugger(); 1619 #endif 1620 #ifdef KGDB 1621 kgdb_connect(1); 1622 #endif 1623 } 1624 /* discard this key (ddb discarded command modifiers) */ 1625 *type = WSCONS_EVENT_KEY_UP; 1626 return (1); 1627 } 1628 #endif 1629 1630 #if NWSDISPLAY > 0 1631 if (sc->sc_base.me_dispdv == NULL) 1632 return (0); 1633 1634 switch (ksym) { 1635 case KS_Cmd_Screen0: 1636 case KS_Cmd_Screen1: 1637 case KS_Cmd_Screen2: 1638 case KS_Cmd_Screen3: 1639 case KS_Cmd_Screen4: 1640 case KS_Cmd_Screen5: 1641 case KS_Cmd_Screen6: 1642 case KS_Cmd_Screen7: 1643 case KS_Cmd_Screen8: 1644 case KS_Cmd_Screen9: 1645 wsdisplay_switch(sc->sc_base.me_dispdv, ksym - KS_Cmd_Screen0, 0); 1646 return (1); 1647 case KS_Cmd_ResetEmul: 1648 wsdisplay_reset(sc->sc_base.me_dispdv, WSDISPLAY_RESETEMUL); 1649 return (1); 1650 case KS_Cmd_ResetClose: 1651 wsdisplay_reset(sc->sc_base.me_dispdv, WSDISPLAY_RESETCLOSE); 1652 return (1); 1653 case KS_Cmd_BacklightOn: 1654 case KS_Cmd_BacklightOff: 1655 case KS_Cmd_BacklightToggle: 1656 change_displayparam(sc, WSDISPLAYIO_PARAM_BACKLIGHT, 1657 ksym == KS_Cmd_BacklightOff ? -1 : 1, 1658 ksym == KS_Cmd_BacklightToggle ? 1 : 0); 1659 return (1); 1660 case KS_Cmd_BrightnessUp: 1661 case KS_Cmd_BrightnessDown: 1662 case KS_Cmd_BrightnessRotate: 1663 change_displayparam(sc, WSDISPLAYIO_PARAM_BRIGHTNESS, 1664 ksym == KS_Cmd_BrightnessDown ? -1 : 1, 1665 ksym == KS_Cmd_BrightnessRotate ? 1 : 0); 1666 return (1); 1667 case KS_Cmd_ContrastUp: 1668 case KS_Cmd_ContrastDown: 1669 case KS_Cmd_ContrastRotate: 1670 change_displayparam(sc, WSDISPLAYIO_PARAM_CONTRAST, 1671 ksym == KS_Cmd_ContrastDown ? -1 : 1, 1672 ksym == KS_Cmd_ContrastRotate ? 1 : 0); 1673 return (1); 1674 } 1675 #endif 1676 1677 return (0); 1678 } 1679 1680 device_t 1681 wskbd_hotkey_register(device_t self, void *cookie, wskbd_hotkey_plugin *hotkey) 1682 { 1683 struct wskbd_softc *sc = device_private(self); 1684 1685 KASSERT(sc != NULL); 1686 KASSERT(hotkey != NULL); 1687 1688 sc->sc_hotkey = hotkey; 1689 sc->sc_hotkeycookie = cookie; 1690 1691 return sc->sc_base.me_dv; 1692 } 1693 1694 void 1695 wskbd_hotkey_deregister(device_t self) 1696 { 1697 struct wskbd_softc *sc = device_private(self); 1698 1699 KASSERT(sc != NULL); 1700 1701 sc->sc_hotkey = NULL; 1702 sc->sc_hotkeycookie = NULL; 1703 } 1704 1705 static int 1706 wskbd_translate(struct wskbd_internal *id, u_int type, int value) 1707 { 1708 struct wskbd_softc *sc = id->t_sc; 1709 keysym_t ksym, res, *group; 1710 struct wscons_keymap kpbuf, *kp; 1711 int iscommand = 0; 1712 int ishotkey = 0; 1713 1714 if (type == WSCONS_EVENT_ALL_KEYS_UP) { 1715 id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R 1716 | MOD_CONTROL_L | MOD_CONTROL_R 1717 | MOD_META_L | MOD_META_R 1718 | MOD_MODESHIFT 1719 | MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2); 1720 update_leds(id); 1721 return (0); 1722 } 1723 1724 if (sc != NULL) { 1725 if (sc->sc_hotkey != NULL) 1726 ishotkey = sc->sc_hotkey(sc, sc->sc_hotkeycookie, 1727 type, value); 1728 if (ishotkey) 1729 return 0; 1730 1731 if (value < 0 || value >= sc->sc_maplen) { 1732 #ifdef DEBUG 1733 printf("%s: keycode %d out of range\n", 1734 __func__, value); 1735 #endif 1736 return (0); 1737 } 1738 kp = sc->sc_map + value; 1739 } else { 1740 kp = &kpbuf; 1741 wskbd_get_mapentry(id->t_keymap, value, kp); 1742 } 1743 1744 /* if this key has a command, process it first */ 1745 if (sc != NULL && kp->command != KS_voidSymbol) 1746 iscommand = internal_command(sc, &type, kp->command, 1747 kp->group1[0]); 1748 1749 /* Now update modifiers */ 1750 switch (kp->group1[0]) { 1751 case KS_Shift_L: 1752 update_modifier(id, type, 0, MOD_SHIFT_L); 1753 break; 1754 1755 case KS_Shift_R: 1756 update_modifier(id, type, 0, MOD_SHIFT_R); 1757 break; 1758 1759 case KS_Shift_Lock: 1760 update_modifier(id, type, 1, MOD_SHIFTLOCK); 1761 break; 1762 1763 case KS_Caps_Lock: 1764 update_modifier(id, type, 1, MOD_CAPSLOCK); 1765 break; 1766 1767 case KS_Control_L: 1768 update_modifier(id, type, 0, MOD_CONTROL_L); 1769 break; 1770 1771 case KS_Control_R: 1772 update_modifier(id, type, 0, MOD_CONTROL_R); 1773 break; 1774 1775 case KS_Alt_L: 1776 update_modifier(id, type, 0, MOD_META_L); 1777 break; 1778 1779 case KS_Alt_R: 1780 update_modifier(id, type, 0, MOD_META_R); 1781 break; 1782 1783 case KS_Mode_switch: 1784 update_modifier(id, type, 0, MOD_MODESHIFT); 1785 break; 1786 1787 case KS_Num_Lock: 1788 update_modifier(id, type, 1, MOD_NUMLOCK); 1789 break; 1790 1791 #if NWSDISPLAY > 0 1792 case KS_Hold_Screen: 1793 if (sc != NULL) { 1794 update_modifier(id, type, 1, MOD_HOLDSCREEN); 1795 wskbd_holdscreen(sc, id->t_modifiers & MOD_HOLDSCREEN); 1796 } 1797 break; 1798 #endif 1799 } 1800 1801 /* If this is a key release or we are in command mode, we are done */ 1802 if (type != WSCONS_EVENT_KEY_DOWN || iscommand) { 1803 update_leds(id); 1804 return (0); 1805 } 1806 1807 /* Get the keysym */ 1808 if (id->t_modifiers & MOD_MODESHIFT) 1809 group = & kp->group2[0]; 1810 else 1811 group = & kp->group1[0]; 1812 1813 if ((id->t_modifiers & MOD_NUMLOCK) != 0 && 1814 KS_GROUP(group[1]) == KS_GROUP_Keypad) { 1815 if (MOD_ONESET(id, MOD_ANYSHIFT)) 1816 ksym = group[0]; 1817 else 1818 ksym = group[1]; 1819 } else if (! MOD_ONESET(id, MOD_ANYSHIFT | MOD_CAPSLOCK)) { 1820 ksym = group[0]; 1821 } else if (MOD_ONESET(id, MOD_CAPSLOCK)) { 1822 if (! MOD_ONESET(id, MOD_SHIFT_L | MOD_SHIFT_R)) 1823 ksym = group[0]; 1824 else 1825 ksym = group[1]; 1826 if (ksym >= KS_a && ksym <= KS_z) 1827 ksym += KS_A - KS_a; 1828 else if (ksym >= KS_agrave && ksym <= KS_thorn && 1829 ksym != KS_division) 1830 ksym += KS_Agrave - KS_agrave; 1831 } else if (MOD_ONESET(id, MOD_ANYSHIFT)) { 1832 ksym = group[1]; 1833 } else { 1834 ksym = group[0]; 1835 } 1836 1837 /* Process compose sequence and dead accents */ 1838 res = KS_voidSymbol; 1839 1840 switch (KS_GROUP(ksym)) { 1841 case KS_GROUP_Plain: 1842 case KS_GROUP_Keypad: 1843 case KS_GROUP_Function: 1844 res = ksym; 1845 break; 1846 1847 case KS_GROUP_Mod: 1848 if (ksym == KS_Multi_key) { 1849 update_modifier(id, 1, 0, MOD_COMPOSE); 1850 id->t_composelen = 2; 1851 } 1852 break; 1853 1854 case KS_GROUP_Dead: 1855 if (id->t_composelen == 0) { 1856 update_modifier(id, 1, 0, MOD_COMPOSE); 1857 id->t_composelen = 1; 1858 id->t_composebuf[0] = ksym; 1859 } else 1860 res = ksym; 1861 break; 1862 } 1863 1864 if (res == KS_voidSymbol) { 1865 update_leds(id); 1866 return (0); 1867 } 1868 1869 if (id->t_composelen > 0) { 1870 id->t_composebuf[2 - id->t_composelen] = res; 1871 if (--id->t_composelen == 0) { 1872 res = wskbd_compose_value(id->t_composebuf); 1873 update_modifier(id, 0, 0, MOD_COMPOSE); 1874 } else { 1875 return (0); 1876 } 1877 } 1878 1879 update_leds(id); 1880 1881 /* We are done, return the symbol */ 1882 if (KS_GROUP(res) == KS_GROUP_Plain) { 1883 if (MOD_ONESET(id, MOD_ANYCONTROL)) { 1884 if ((res >= KS_at && res <= KS_z) || res == KS_space) 1885 res = res & 0x1f; 1886 else if (res == KS_2) 1887 res = 0x00; 1888 else if (res >= KS_3 && res <= KS_7) 1889 res = KS_Escape + (res - KS_3); 1890 else if (res == KS_8) 1891 res = KS_Delete; 1892 /* convert CTL-/ to ^_ as xterm does (undo in emacs) */ 1893 else if (res == KS_slash) 1894 res = KS_underscore & 0x1f; 1895 } 1896 if (MOD_ONESET(id, MOD_ANYMETA)) { 1897 if (id->t_flags & WSKFL_METAESC) { 1898 id->t_symbols[0] = KS_Escape; 1899 id->t_symbols[1] = res; 1900 return (2); 1901 } else 1902 res |= 0x80; 1903 } 1904 } 1905 1906 id->t_symbols[0] = res; 1907 return (1); 1908 } 1909 1910 void 1911 wskbd_set_evtrans(device_t dev, keysym_t *tab, int len) 1912 { 1913 struct wskbd_softc *sc = device_private(dev); 1914 1915 sc->sc_evtrans_len = len; 1916 sc->sc_evtrans = tab; 1917 } 1918 1919