1 /* $NetBSD: wskbd.c,v 1.138 2016/12/10 22:36:28 christos 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.138 2016/12/10 22:36:28 christos 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 146 #ifdef KGDB 147 #include <sys/kgdb.h> 148 #endif 149 150 #ifdef WSKBD_DEBUG 151 #define DPRINTF(x) if (wskbddebug) printf x 152 int wskbddebug = 0; 153 #else 154 #define DPRINTF(x) 155 #endif 156 157 #include <dev/wscons/wsmuxvar.h> 158 159 struct wskbd_internal { 160 const struct wskbd_mapdata *t_keymap; 161 162 const struct wskbd_consops *t_consops; 163 void *t_consaccesscookie; 164 165 int t_modifiers; 166 int t_composelen; /* remaining entries in t_composebuf */ 167 keysym_t t_composebuf[2]; 168 169 int t_flags; 170 #define WSKFL_METAESC 1 171 172 #define MAXKEYSYMSPERKEY 2 /* ESC <key> at max */ 173 keysym_t t_symbols[MAXKEYSYMSPERKEY]; 174 175 struct wskbd_softc *t_sc; /* back pointer */ 176 }; 177 178 struct wskbd_softc { 179 struct wsevsrc sc_base; 180 181 struct wskbd_internal *id; 182 183 const struct wskbd_accessops *sc_accessops; 184 void *sc_accesscookie; 185 186 int sc_ledstate; 187 188 int sc_isconsole; 189 190 struct wskbd_bell_data sc_bell_data; 191 struct wskbd_keyrepeat_data sc_keyrepeat_data; 192 #ifdef WSDISPLAY_SCROLLSUPPORT 193 struct wskbd_scroll_data sc_scroll_data; 194 #endif 195 196 int sc_repeating; /* we've called timeout() */ 197 callout_t sc_repeat_ch; 198 u_int sc_repeat_type; 199 int sc_repeat_value; 200 201 int sc_translating; /* xlate to chars for emulation */ 202 203 int sc_maplen; /* number of entries in sc_map */ 204 struct wscons_keymap *sc_map; /* current translation map */ 205 kbd_t sc_layout; /* current layout */ 206 207 int sc_refcnt; 208 u_char sc_dying; /* device is being detached */ 209 210 wskbd_hotkey_plugin *sc_hotkey; 211 void *sc_hotkeycookie; 212 213 /* optional table to translate scancodes in event mode */ 214 int sc_evtrans_len; 215 keysym_t *sc_evtrans; 216 }; 217 218 #define MOD_SHIFT_L (1 << 0) 219 #define MOD_SHIFT_R (1 << 1) 220 #define MOD_SHIFTLOCK (1 << 2) 221 #define MOD_CAPSLOCK (1 << 3) 222 #define MOD_CONTROL_L (1 << 4) 223 #define MOD_CONTROL_R (1 << 5) 224 #define MOD_META_L (1 << 6) 225 #define MOD_META_R (1 << 7) 226 #define MOD_MODESHIFT (1 << 8) 227 #define MOD_NUMLOCK (1 << 9) 228 #define MOD_COMPOSE (1 << 10) 229 #define MOD_HOLDSCREEN (1 << 11) 230 #define MOD_COMMAND (1 << 12) 231 #define MOD_COMMAND1 (1 << 13) 232 #define MOD_COMMAND2 (1 << 14) 233 234 #define MOD_ANYSHIFT (MOD_SHIFT_L | MOD_SHIFT_R | MOD_SHIFTLOCK) 235 #define MOD_ANYCONTROL (MOD_CONTROL_L | MOD_CONTROL_R) 236 #define MOD_ANYMETA (MOD_META_L | MOD_META_R) 237 238 #define MOD_ONESET(id, mask) (((id)->t_modifiers & (mask)) != 0) 239 #define MOD_ALLSET(id, mask) (((id)->t_modifiers & (mask)) == (mask)) 240 241 #define GETMODSTATE(src, dst) \ 242 do { \ 243 dst |= (src & MOD_SHIFT_L) ? MOD_SHIFT_L : 0; \ 244 dst |= (src & MOD_SHIFT_R) ? MOD_SHIFT_R : 0; \ 245 dst |= (src & MOD_CONTROL_L) ? MOD_CONTROL_L : 0; \ 246 dst |= (src & MOD_CONTROL_R) ? MOD_CONTROL_R : 0; \ 247 dst |= (src & MOD_META_L) ? MOD_META_L : 0; \ 248 dst |= (src & MOD_META_R) ? MOD_META_R : 0; \ 249 } while (0) 250 251 static int wskbd_match(device_t, cfdata_t, void *); 252 static void wskbd_attach(device_t, device_t, void *); 253 static int wskbd_detach(device_t, int); 254 static int wskbd_activate(device_t, enum devact); 255 256 static int wskbd_displayioctl(device_t, u_long, void *, int, 257 struct lwp *); 258 #if NWSDISPLAY > 0 259 static int wskbd_set_display(device_t, struct wsevsrc *); 260 #else 261 #define wskbd_set_display NULL 262 #endif 263 264 static inline void update_leds(struct wskbd_internal *); 265 static inline void update_modifier(struct wskbd_internal *, u_int, int, int); 266 static int internal_command(struct wskbd_softc *, u_int *, keysym_t, keysym_t); 267 static int wskbd_translate(struct wskbd_internal *, u_int, int); 268 static int wskbd_enable(struct wskbd_softc *, int); 269 #if NWSDISPLAY > 0 270 static void change_displayparam(struct wskbd_softc *, int, int, int); 271 static void wskbd_holdscreen(struct wskbd_softc *, int); 272 #endif 273 274 static int wskbd_do_ioctl_sc(struct wskbd_softc *, u_long, void *, int, 275 struct lwp *); 276 static void wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value); 277 278 #if NWSMUX > 0 279 static int wskbd_mux_open(struct wsevsrc *, struct wseventvar *); 280 static int wskbd_mux_close(struct wsevsrc *); 281 #else 282 #define wskbd_mux_open NULL 283 #define wskbd_mux_close NULL 284 #endif 285 286 static int wskbd_do_open(struct wskbd_softc *, struct wseventvar *); 287 static int wskbd_do_ioctl(device_t, u_long, void *, int, struct lwp *); 288 289 CFATTACH_DECL_NEW(wskbd, sizeof (struct wskbd_softc), 290 wskbd_match, wskbd_attach, wskbd_detach, wskbd_activate); 291 292 extern struct cfdriver wskbd_cd; 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 #ifndef WSKBD_DEFAULT_BELL_PITCH 317 #define WSKBD_DEFAULT_BELL_PITCH 1500 /* 1500Hz */ 318 #endif 319 #ifndef WSKBD_DEFAULT_BELL_PERIOD 320 #define WSKBD_DEFAULT_BELL_PERIOD 100 /* 100ms */ 321 #endif 322 #ifndef WSKBD_DEFAULT_BELL_VOLUME 323 #define WSKBD_DEFAULT_BELL_VOLUME 50 /* 50% volume */ 324 #endif 325 326 struct wskbd_bell_data wskbd_default_bell_data = { 327 WSKBD_BELL_DOALL, 328 WSKBD_DEFAULT_BELL_PITCH, 329 WSKBD_DEFAULT_BELL_PERIOD, 330 WSKBD_DEFAULT_BELL_VOLUME, 331 }; 332 333 #ifdef WSDISPLAY_SCROLLSUPPORT 334 struct wskbd_scroll_data wskbd_default_scroll_data = { 335 WSKBD_SCROLL_DOALL, 336 WSKBD_SCROLL_MODE_NORMAL, 337 #ifdef WSDISPLAY_SCROLLCOMBO 338 WSDISPLAY_SCROLLCOMBO, 339 #else 340 MOD_SHIFT_L, 341 #endif 342 }; 343 #endif 344 345 #ifndef WSKBD_DEFAULT_KEYREPEAT_DEL1 346 #define WSKBD_DEFAULT_KEYREPEAT_DEL1 400 /* 400ms to start repeating */ 347 #endif 348 #ifndef WSKBD_DEFAULT_KEYREPEAT_DELN 349 #define WSKBD_DEFAULT_KEYREPEAT_DELN 100 /* 100ms to between repeats */ 350 #endif 351 352 struct wskbd_keyrepeat_data wskbd_default_keyrepeat_data = { 353 WSKBD_KEYREPEAT_DOALL, 354 WSKBD_DEFAULT_KEYREPEAT_DEL1, 355 WSKBD_DEFAULT_KEYREPEAT_DELN, 356 }; 357 358 #if NWSDISPLAY > 0 || NWSMUX > 0 359 struct wssrcops wskbd_srcops = { 360 WSMUX_KBD, 361 wskbd_mux_open, wskbd_mux_close, wskbd_do_ioctl, 362 wskbd_displayioctl, wskbd_set_display 363 }; 364 #endif 365 366 static bool wskbd_suspend(device_t dv, const pmf_qual_t *); 367 static void wskbd_repeat(void *v); 368 369 static int wskbd_console_initted; 370 static struct wskbd_softc *wskbd_console_device; 371 static struct wskbd_internal wskbd_console_data; 372 373 static void wskbd_update_layout(struct wskbd_internal *, kbd_t); 374 375 static void 376 wskbd_update_layout(struct wskbd_internal *id, kbd_t enc) 377 { 378 379 if (enc & KB_METAESC) 380 id->t_flags |= WSKFL_METAESC; 381 else 382 id->t_flags &= ~WSKFL_METAESC; 383 } 384 385 /* 386 * Print function (for parent devices). 387 */ 388 int 389 wskbddevprint(void *aux, const char *pnp) 390 { 391 #if 0 392 struct wskbddev_attach_args *ap = aux; 393 #endif 394 395 if (pnp) 396 aprint_normal("wskbd at %s", pnp); 397 #if 0 398 aprint_normal(" console %d", ap->console); 399 #endif 400 401 return (UNCONF); 402 } 403 404 int 405 wskbd_match(device_t parent, cfdata_t match, void *aux) 406 { 407 struct wskbddev_attach_args *ap = aux; 408 409 if (match->wskbddevcf_console != WSKBDDEVCF_CONSOLE_UNK) { 410 /* 411 * If console-ness of device specified, either match 412 * exactly (at high priority), or fail. 413 */ 414 if (match->wskbddevcf_console != 0 && ap->console != 0) 415 return (10); 416 else 417 return (0); 418 } 419 420 /* If console-ness unspecified, it wins. */ 421 return (1); 422 } 423 424 void 425 wskbd_attach(device_t parent, device_t self, void *aux) 426 { 427 struct wskbd_softc *sc = device_private(self); 428 struct wskbddev_attach_args *ap = aux; 429 #if NWSMUX > 0 430 int mux, error; 431 #endif 432 433 sc->sc_base.me_dv = self; 434 sc->sc_isconsole = ap->console; 435 sc->sc_hotkey = NULL; 436 sc->sc_hotkeycookie = NULL; 437 sc->sc_evtrans_len = 0; 438 sc->sc_evtrans = NULL; 439 440 #if NWSMUX > 0 || NWSDISPLAY > 0 441 sc->sc_base.me_ops = &wskbd_srcops; 442 #endif 443 #if NWSMUX > 0 444 mux = device_cfdata(sc->sc_base.me_dv)->wskbddevcf_mux; 445 if (ap->console) { 446 /* Ignore mux for console; it always goes to the console mux. */ 447 /* printf(" (mux %d ignored for console)", mux); */ 448 mux = -1; 449 } 450 if (mux >= 0) 451 aprint_normal(" mux %d", mux); 452 #else 453 if (device_cfdata(sc->sc_base.me_dv)->wskbddevcf_mux >= 0) 454 aprint_normal(" (mux ignored)"); 455 #endif 456 457 if (ap->console) { 458 sc->id = &wskbd_console_data; 459 } else { 460 sc->id = malloc(sizeof(struct wskbd_internal), 461 M_DEVBUF, M_WAITOK|M_ZERO); 462 sc->id->t_keymap = ap->keymap; 463 wskbd_update_layout(sc->id, ap->keymap->layout); 464 } 465 466 callout_init(&sc->sc_repeat_ch, 0); 467 callout_setfunc(&sc->sc_repeat_ch, wskbd_repeat, sc); 468 469 sc->id->t_sc = sc; 470 471 sc->sc_accessops = ap->accessops; 472 sc->sc_accesscookie = ap->accesscookie; 473 sc->sc_repeating = 0; 474 sc->sc_translating = 1; 475 sc->sc_ledstate = -1; /* force update */ 476 477 if (wskbd_load_keymap(sc->id->t_keymap, 478 &sc->sc_map, &sc->sc_maplen) != 0) 479 panic("cannot load keymap"); 480 481 sc->sc_layout = sc->id->t_keymap->layout; 482 483 /* set default bell and key repeat data */ 484 sc->sc_bell_data = wskbd_default_bell_data; 485 sc->sc_keyrepeat_data = wskbd_default_keyrepeat_data; 486 487 #ifdef WSDISPLAY_SCROLLSUPPORT 488 sc->sc_scroll_data = wskbd_default_scroll_data; 489 #endif 490 491 if (ap->console) { 492 KASSERT(wskbd_console_initted); 493 KASSERT(wskbd_console_device == NULL); 494 495 wskbd_console_device = sc; 496 497 aprint_naive(": console keyboard"); 498 aprint_normal(": console keyboard"); 499 500 #if NWSDISPLAY > 0 501 wsdisplay_set_console_kbd(&sc->sc_base); /* sets me_dispv */ 502 if (sc->sc_base.me_dispdv != NULL) 503 aprint_normal(", using %s", 504 device_xname(sc->sc_base.me_dispdv)); 505 #endif 506 } 507 aprint_naive("\n"); 508 aprint_normal("\n"); 509 510 #if NWSMUX > 0 511 if (mux >= 0) { 512 error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base); 513 if (error) 514 aprint_error_dev(sc->sc_base.me_dv, 515 "attach error=%d\n", error); 516 } 517 #endif 518 519 if (!pmf_device_register(self, wskbd_suspend, NULL)) 520 aprint_error_dev(self, "couldn't establish power handler\n"); 521 else if (!pmf_class_input_register(self)) 522 aprint_error_dev(self, "couldn't register as input device\n"); 523 } 524 525 static bool 526 wskbd_suspend(device_t dv, const pmf_qual_t *qual) 527 { 528 struct wskbd_softc *sc = device_private(dv); 529 530 sc->sc_repeating = 0; 531 callout_stop(&sc->sc_repeat_ch); 532 533 return true; 534 } 535 536 void 537 wskbd_cnattach(const struct wskbd_consops *consops, void *conscookie, 538 const struct wskbd_mapdata *mapdata) 539 { 540 KASSERT(!wskbd_console_initted); 541 542 wskbd_console_data.t_keymap = mapdata; 543 wskbd_update_layout(&wskbd_console_data, mapdata->layout); 544 545 wskbd_console_data.t_consops = consops; 546 wskbd_console_data.t_consaccesscookie = conscookie; 547 548 #if NWSDISPLAY > 0 549 wsdisplay_set_cons_kbd(wskbd_cngetc, wskbd_cnpollc, wskbd_cnbell); 550 #endif 551 552 wskbd_console_initted = 1; 553 } 554 555 void 556 wskbd_cndetach(void) 557 { 558 KASSERT(wskbd_console_initted); 559 560 wskbd_console_data.t_keymap = 0; 561 562 wskbd_console_data.t_consops = 0; 563 wskbd_console_data.t_consaccesscookie = 0; 564 565 #if NWSDISPLAY > 0 566 wsdisplay_unset_cons_kbd(); 567 #endif 568 569 wskbd_console_initted = 0; 570 } 571 572 static void 573 wskbd_repeat(void *v) 574 { 575 struct wskbd_softc *sc = (struct wskbd_softc *)v; 576 int s = spltty(); 577 578 if (!sc->sc_repeating) { 579 /* 580 * race condition: a "key up" event came in when wskbd_repeat() 581 * was already called but not yet spltty()'d 582 */ 583 splx(s); 584 return; 585 } 586 if (sc->sc_translating) { 587 /* deliver keys */ 588 #if NWSDISPLAY > 0 589 if (sc->sc_base.me_dispdv != NULL) { 590 int i; 591 for (i = 0; i < sc->sc_repeating; i++) 592 wsdisplay_kbdinput(sc->sc_base.me_dispdv, 593 sc->id->t_symbols[i]); 594 } 595 #endif 596 } else { 597 #if defined(WSKBD_EVENT_AUTOREPEAT) 598 /* queue event */ 599 wskbd_deliver_event(sc, sc->sc_repeat_type, 600 sc->sc_repeat_value); 601 #endif /* defined(WSKBD_EVENT_AUTOREPEAT) */ 602 } 603 callout_schedule(&sc->sc_repeat_ch, mstohz(sc->sc_keyrepeat_data.delN)); 604 splx(s); 605 } 606 607 int 608 wskbd_activate(device_t self, enum devact act) 609 { 610 struct wskbd_softc *sc = device_private(self); 611 612 if (act == DVACT_DEACTIVATE) 613 sc->sc_dying = 1; 614 return (0); 615 } 616 617 /* 618 * Detach a keyboard. To keep track of users of the softc we keep 619 * a reference count that's incremented while inside, e.g., read. 620 * If the keyboard is active and the reference count is > 0 (0 is the 621 * normal state) we post an event and then wait for the process 622 * that had the reference to wake us up again. Then we blow away the 623 * vnode and return (which will deallocate the softc). 624 */ 625 int 626 wskbd_detach(device_t self, int flags) 627 { 628 struct wskbd_softc *sc = device_private(self); 629 struct wseventvar *evar; 630 int maj, mn; 631 int s; 632 633 #if NWSMUX > 0 634 /* Tell parent mux we're leaving. */ 635 if (sc->sc_base.me_parent != NULL) 636 wsmux_detach_sc(&sc->sc_base); 637 #endif 638 639 callout_halt(&sc->sc_repeat_ch, NULL); 640 callout_destroy(&sc->sc_repeat_ch); 641 642 if (sc->sc_isconsole) { 643 KASSERT(wskbd_console_device == sc); 644 wskbd_console_device = NULL; 645 } 646 647 pmf_device_deregister(self); 648 649 evar = sc->sc_base.me_evp; 650 if (evar != NULL && evar->io != NULL) { 651 s = spltty(); 652 if (--sc->sc_refcnt >= 0) { 653 struct wscons_event event; 654 655 /* Wake everyone by generating a dummy event. */ 656 event.type = 0; 657 event.value = 0; 658 if (wsevent_inject(evar, &event, 1) != 0) 659 wsevent_wakeup(evar); 660 661 /* Wait for processes to go away. */ 662 if (tsleep(sc, PZERO, "wskdet", hz * 60)) 663 aprint_error("wskbd_detach: %s didn't detach\n", 664 device_xname(self)); 665 } 666 splx(s); 667 } 668 669 /* locate the major number */ 670 maj = cdevsw_lookup_major(&wskbd_cdevsw); 671 672 /* Nuke the vnodes for any open instances. */ 673 mn = device_unit(self); 674 vdevgone(maj, mn, mn, VCHR); 675 676 return (0); 677 } 678 679 void 680 wskbd_input(device_t dev, u_int type, int value) 681 { 682 struct wskbd_softc *sc = device_private(dev); 683 #if NWSDISPLAY > 0 684 int num, i; 685 #endif 686 687 if (sc->sc_repeating) { 688 sc->sc_repeating = 0; 689 callout_stop(&sc->sc_repeat_ch); 690 } 691 692 device_active(dev, DVA_HARDWARE); 693 694 #if NWSDISPLAY > 0 695 /* 696 * If /dev/wskbdN is not connected in event mode translate and 697 * send upstream. 698 */ 699 if (sc->sc_translating) { 700 num = wskbd_translate(sc->id, type, value); 701 if (num > 0) { 702 if (sc->sc_base.me_dispdv != NULL) { 703 #ifdef WSDISPLAY_SCROLLSUPPORT 704 if (sc->id->t_symbols [0] != KS_Print_Screen) { 705 wsdisplay_scroll(sc->sc_base. 706 me_dispdv, WSDISPLAY_SCROLL_RESET); 707 } 708 #endif 709 for (i = 0; i < num; i++) 710 wsdisplay_kbdinput( 711 sc->sc_base.me_dispdv, 712 sc->id->t_symbols[i]); 713 } 714 715 if (sc->sc_keyrepeat_data.del1 != 0) { 716 sc->sc_repeating = num; 717 callout_schedule(&sc->sc_repeat_ch, 718 mstohz(sc->sc_keyrepeat_data.del1)); 719 } 720 } 721 return; 722 } 723 #endif 724 725 wskbd_deliver_event(sc, type, value); 726 727 #if defined(WSKBD_EVENT_AUTOREPEAT) 728 /* Repeat key presses if set. */ 729 if (type == WSCONS_EVENT_KEY_DOWN && sc->sc_keyrepeat_data.del1 != 0) { 730 sc->sc_repeat_type = type; 731 sc->sc_repeat_value = value; 732 sc->sc_repeating = 1; 733 callout_schedule(&sc->sc_repeat_ch, 734 mstohz(sc->sc_keyrepeat_data.del1)); 735 } 736 #endif /* defined(WSKBD_EVENT_AUTOREPEAT) */ 737 } 738 739 /* 740 * Keyboard is generating events. Turn this keystroke into an 741 * event and put it in the queue. If the queue is full, the 742 * keystroke is lost (sorry!). 743 */ 744 static void 745 wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value) 746 { 747 struct wseventvar *evar; 748 struct wscons_event event; 749 750 evar = sc->sc_base.me_evp; 751 752 if (evar == NULL) { 753 DPRINTF(("wskbd_input: not open\n")); 754 return; 755 } 756 757 #ifdef DIAGNOSTIC 758 if (evar->q == NULL) { 759 printf("wskbd_input: evar->q=NULL\n"); 760 return; 761 } 762 #endif 763 764 event.type = type; 765 event.value = 0; 766 DPRINTF(("%d ->", value)); 767 if (sc->sc_evtrans_len > 0) { 768 if (sc->sc_evtrans_len > value) { 769 DPRINTF(("%d", sc->sc_evtrans[value])); 770 event.value = sc->sc_evtrans[value]; 771 } 772 } else { 773 event.value = value; 774 } 775 DPRINTF(("\n")); 776 if (wsevent_inject(evar, &event, 1) != 0) 777 log(LOG_WARNING, "%s: event queue overflow\n", 778 device_xname(sc->sc_base.me_dv)); 779 } 780 781 #ifdef WSDISPLAY_COMPAT_RAWKBD 782 void 783 wskbd_rawinput(device_t dev, u_char *tbuf, int len) 784 { 785 #if NWSDISPLAY > 0 786 struct wskbd_softc *sc = device_private(dev); 787 int i; 788 789 if (sc->sc_base.me_dispdv != NULL) 790 for (i = 0; i < len; i++) 791 wsdisplay_kbdinput(sc->sc_base.me_dispdv, tbuf[i]); 792 /* this is KS_GROUP_Plain */ 793 #endif 794 } 795 #endif /* WSDISPLAY_COMPAT_RAWKBD */ 796 797 #if NWSDISPLAY > 0 798 static void 799 wskbd_holdscreen(struct wskbd_softc *sc, int hold) 800 { 801 int new_state; 802 803 if (sc->sc_base.me_dispdv != NULL) { 804 wsdisplay_kbdholdscreen(sc->sc_base.me_dispdv, hold); 805 new_state = sc->sc_ledstate; 806 if (hold) { 807 #ifdef WSDISPLAY_SCROLLSUPPORT 808 sc->sc_scroll_data.mode = WSKBD_SCROLL_MODE_HOLD; 809 #endif 810 new_state |= WSKBD_LED_SCROLL; 811 } else { 812 #ifdef WSDISPLAY_SCROLLSUPPORT 813 sc->sc_scroll_data.mode = WSKBD_SCROLL_MODE_NORMAL; 814 #endif 815 new_state &= ~WSKBD_LED_SCROLL; 816 } 817 if (new_state != sc->sc_ledstate) { 818 (*sc->sc_accessops->set_leds)(sc->sc_accesscookie, 819 new_state); 820 sc->sc_ledstate = new_state; 821 #ifdef WSDISPLAY_SCROLLSUPPORT 822 if (!hold) 823 wsdisplay_scroll(sc->sc_base.me_dispdv, 824 WSDISPLAY_SCROLL_RESET); 825 #endif 826 } 827 } 828 } 829 #endif 830 831 static int 832 wskbd_enable(struct wskbd_softc *sc, int on) 833 { 834 int error; 835 836 #if 0 837 /* I don't understand the purpose of this code. And it seems to 838 * break things, so it's out. -- Lennart 839 */ 840 if (!on && (!sc->sc_translating 841 #if NWSDISPLAY > 0 842 || sc->sc_base.me_dispdv 843 #endif 844 )) 845 return (EBUSY); 846 #endif 847 #if NWSDISPLAY > 0 848 if (sc->sc_base.me_dispdv != NULL) 849 return (0); 850 #endif 851 852 /* Always cancel auto repeat when fiddling with the kbd. */ 853 if (sc->sc_repeating) { 854 sc->sc_repeating = 0; 855 callout_stop(&sc->sc_repeat_ch); 856 } 857 858 error = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on); 859 DPRINTF(("wskbd_enable: sc=%p on=%d res=%d\n", sc, on, error)); 860 return (error); 861 } 862 863 #if NWSMUX > 0 864 int 865 wskbd_mux_open(struct wsevsrc *me, struct wseventvar *evp) 866 { 867 struct wskbd_softc *sc = (struct wskbd_softc *)me; 868 869 if (sc->sc_dying) 870 return (EIO); 871 872 if (sc->sc_base.me_evp != NULL) 873 return (EBUSY); 874 875 return (wskbd_do_open(sc, evp)); 876 } 877 #endif 878 879 int 880 wskbdopen(dev_t dev, int flags, int mode, struct lwp *l) 881 { 882 struct wskbd_softc *sc = device_lookup_private(&wskbd_cd, minor(dev)); 883 struct wseventvar *evar; 884 int error; 885 886 if (sc == NULL) 887 return (ENXIO); 888 889 #if NWSMUX > 0 890 DPRINTF(("wskbdopen: %s mux=%p l=%p\n", 891 device_xname(sc->sc_base.me_dv), sc->sc_base.me_parent, l)); 892 #endif 893 894 if (sc->sc_dying) 895 return (EIO); 896 897 if ((flags & (FREAD | FWRITE)) == FWRITE) 898 /* Not opening for read, only ioctl is available. */ 899 return (0); 900 901 #if NWSMUX > 0 902 if (sc->sc_base.me_parent != NULL) { 903 /* Grab the keyboard out of the greedy hands of the mux. */ 904 DPRINTF(("wskbdopen: detach\n")); 905 wsmux_detach_sc(&sc->sc_base); 906 } 907 #endif 908 909 if (sc->sc_base.me_evp != NULL) 910 return (EBUSY); 911 912 evar = &sc->sc_base.me_evar; 913 wsevent_init(evar, l->l_proc); 914 915 error = wskbd_do_open(sc, evar); 916 if (error) { 917 DPRINTF(("wskbdopen: %s open failed\n", 918 device_xname(sc->sc_base.me_dv))); 919 sc->sc_base.me_evp = NULL; 920 wsevent_fini(evar); 921 } 922 return (error); 923 } 924 925 int 926 wskbd_do_open(struct wskbd_softc *sc, struct wseventvar *evp) 927 { 928 sc->sc_base.me_evp = evp; 929 sc->sc_translating = 0; 930 931 return (wskbd_enable(sc, 1)); 932 } 933 934 int 935 wskbdclose(dev_t dev, int flags, int mode, 936 struct lwp *l) 937 { 938 struct wskbd_softc *sc = 939 device_lookup_private(&wskbd_cd, minor(dev)); 940 struct wseventvar *evar = sc->sc_base.me_evp; 941 942 if (evar == NULL) 943 /* not open for read */ 944 return (0); 945 946 sc->sc_base.me_evp = NULL; 947 sc->sc_translating = 1; 948 (void)wskbd_enable(sc, 0); 949 wsevent_fini(evar); 950 951 return (0); 952 } 953 954 #if NWSMUX > 0 955 int 956 wskbd_mux_close(struct wsevsrc *me) 957 { 958 struct wskbd_softc *sc = (struct wskbd_softc *)me; 959 960 sc->sc_base.me_evp = NULL; 961 sc->sc_translating = 1; 962 (void)wskbd_enable(sc, 0); 963 964 return (0); 965 } 966 #endif 967 968 int 969 wskbdread(dev_t dev, struct uio *uio, int flags) 970 { 971 struct wskbd_softc *sc = 972 device_lookup_private(&wskbd_cd, minor(dev)); 973 int error; 974 975 if (sc->sc_dying) 976 return (EIO); 977 978 #ifdef DIAGNOSTIC 979 if (sc->sc_base.me_evp == NULL) { 980 printf("wskbdread: evp == NULL\n"); 981 return (EINVAL); 982 } 983 #endif 984 985 sc->sc_refcnt++; 986 error = wsevent_read(sc->sc_base.me_evp, uio, flags); 987 if (--sc->sc_refcnt < 0) { 988 wakeup(sc); 989 error = EIO; 990 } 991 return (error); 992 } 993 994 int 995 wskbdioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 996 { 997 return (wskbd_do_ioctl(device_lookup(&wskbd_cd, minor(dev)), 998 cmd, data, flag,l)); 999 } 1000 1001 /* A wrapper around the ioctl() workhorse to make reference counting easy. */ 1002 int 1003 wskbd_do_ioctl(device_t dv, u_long cmd, void *data, int flag, 1004 struct lwp *l) 1005 { 1006 struct wskbd_softc *sc = device_private(dv); 1007 int error; 1008 1009 sc->sc_refcnt++; 1010 error = wskbd_do_ioctl_sc(sc, cmd, data, flag, l); 1011 if (--sc->sc_refcnt < 0) 1012 wakeup(sc); 1013 return (error); 1014 } 1015 1016 int 1017 wskbd_do_ioctl_sc(struct wskbd_softc *sc, u_long cmd, void *data, int flag, 1018 struct lwp *l) 1019 { 1020 1021 /* 1022 * Try the generic ioctls that the wskbd interface supports. 1023 */ 1024 switch (cmd) { 1025 case FIONBIO: /* we will remove this someday (soon???) */ 1026 return (0); 1027 1028 case FIOASYNC: 1029 if (sc->sc_base.me_evp == NULL) 1030 return (EINVAL); 1031 sc->sc_base.me_evp->async = *(int *)data != 0; 1032 return (0); 1033 1034 case FIOSETOWN: 1035 if (sc->sc_base.me_evp == NULL) 1036 return (EINVAL); 1037 if (-*(int *)data != sc->sc_base.me_evp->io->p_pgid 1038 && *(int *)data != sc->sc_base.me_evp->io->p_pid) 1039 return (EPERM); 1040 return (0); 1041 1042 case TIOCSPGRP: 1043 if (sc->sc_base.me_evp == NULL) 1044 return (EINVAL); 1045 if (*(int *)data != sc->sc_base.me_evp->io->p_pgid) 1046 return (EPERM); 1047 return (0); 1048 } 1049 1050 /* 1051 * Try the keyboard driver for WSKBDIO ioctls. It returns EPASSTHROUGH 1052 * if it didn't recognize the request. 1053 */ 1054 return (wskbd_displayioctl(sc->sc_base.me_dv, cmd, data, flag, l)); 1055 } 1056 1057 /* 1058 * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode. 1059 * Some of these have no real effect in raw mode, however. 1060 */ 1061 static int 1062 wskbd_displayioctl(device_t dev, u_long cmd, void *data, int flag, 1063 struct lwp *l) 1064 { 1065 #ifdef WSDISPLAY_SCROLLSUPPORT 1066 struct wskbd_scroll_data *usdp, *ksdp; 1067 #endif 1068 struct wskbd_softc *sc = device_private(dev); 1069 struct wskbd_bell_data *ubdp, *kbdp; 1070 struct wskbd_keyrepeat_data *ukdp, *kkdp; 1071 struct wskbd_map_data *umdp; 1072 struct wskbd_mapdata md; 1073 kbd_t enc; 1074 void *tbuf; 1075 int len, error; 1076 1077 switch (cmd) { 1078 #define SETBELL(dstp, srcp, dfltp) \ 1079 do { \ 1080 (dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ? \ 1081 (srcp)->pitch : (dfltp)->pitch; \ 1082 (dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ? \ 1083 (srcp)->period : (dfltp)->period; \ 1084 (dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ? \ 1085 (srcp)->volume : (dfltp)->volume; \ 1086 (dstp)->which = WSKBD_BELL_DOALL; \ 1087 } while (0) 1088 1089 case WSKBDIO_BELL: 1090 if ((flag & FWRITE) == 0) 1091 return (EACCES); 1092 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, 1093 WSKBDIO_COMPLEXBELL, (void *)&sc->sc_bell_data, flag, l)); 1094 1095 case WSKBDIO_COMPLEXBELL: 1096 if ((flag & FWRITE) == 0) 1097 return (EACCES); 1098 ubdp = (struct wskbd_bell_data *)data; 1099 SETBELL(ubdp, ubdp, &sc->sc_bell_data); 1100 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, 1101 WSKBDIO_COMPLEXBELL, (void *)ubdp, flag, l)); 1102 1103 case WSKBDIO_SETBELL: 1104 if ((flag & FWRITE) == 0) 1105 return (EACCES); 1106 kbdp = &sc->sc_bell_data; 1107 setbell: 1108 ubdp = (struct wskbd_bell_data *)data; 1109 SETBELL(kbdp, ubdp, kbdp); 1110 return (0); 1111 1112 case WSKBDIO_GETBELL: 1113 kbdp = &sc->sc_bell_data; 1114 getbell: 1115 ubdp = (struct wskbd_bell_data *)data; 1116 SETBELL(ubdp, kbdp, kbdp); 1117 return (0); 1118 1119 case WSKBDIO_SETDEFAULTBELL: 1120 if ((error = kauth_authorize_device(l->l_cred, 1121 KAUTH_DEVICE_WSCONS_KEYBOARD_BELL, NULL, NULL, 1122 NULL, NULL)) != 0) 1123 return (error); 1124 kbdp = &wskbd_default_bell_data; 1125 goto setbell; 1126 1127 1128 case WSKBDIO_GETDEFAULTBELL: 1129 kbdp = &wskbd_default_bell_data; 1130 goto getbell; 1131 1132 #undef SETBELL 1133 1134 #define SETKEYREPEAT(dstp, srcp, dfltp) \ 1135 do { \ 1136 (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ? \ 1137 (srcp)->del1 : (dfltp)->del1; \ 1138 (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ? \ 1139 (srcp)->delN : (dfltp)->delN; \ 1140 (dstp)->which = WSKBD_KEYREPEAT_DOALL; \ 1141 } while (0) 1142 1143 case WSKBDIO_SETKEYREPEAT: 1144 if ((flag & FWRITE) == 0) 1145 return (EACCES); 1146 kkdp = &sc->sc_keyrepeat_data; 1147 setkeyrepeat: 1148 ukdp = (struct wskbd_keyrepeat_data *)data; 1149 SETKEYREPEAT(kkdp, ukdp, kkdp); 1150 return (0); 1151 1152 case WSKBDIO_GETKEYREPEAT: 1153 kkdp = &sc->sc_keyrepeat_data; 1154 getkeyrepeat: 1155 ukdp = (struct wskbd_keyrepeat_data *)data; 1156 SETKEYREPEAT(ukdp, kkdp, kkdp); 1157 return (0); 1158 1159 case WSKBDIO_SETDEFAULTKEYREPEAT: 1160 if ((error = kauth_authorize_device(l->l_cred, 1161 KAUTH_DEVICE_WSCONS_KEYBOARD_KEYREPEAT, NULL, NULL, 1162 NULL, NULL)) != 0) 1163 return (error); 1164 kkdp = &wskbd_default_keyrepeat_data; 1165 goto setkeyrepeat; 1166 1167 1168 case WSKBDIO_GETDEFAULTKEYREPEAT: 1169 kkdp = &wskbd_default_keyrepeat_data; 1170 goto getkeyrepeat; 1171 1172 #ifdef WSDISPLAY_SCROLLSUPPORT 1173 #define SETSCROLLMOD(dstp, srcp, dfltp) \ 1174 do { \ 1175 (dstp)->mode = ((srcp)->which & WSKBD_SCROLL_DOMODE) ? \ 1176 (srcp)->mode : (dfltp)->mode; \ 1177 (dstp)->modifier = ((srcp)->which & WSKBD_SCROLL_DOMODIFIER) ? \ 1178 (srcp)->modifier : (dfltp)->modifier; \ 1179 (dstp)->which = WSKBD_SCROLL_DOALL; \ 1180 } while (0) 1181 1182 case WSKBDIO_SETSCROLL: 1183 usdp = (struct wskbd_scroll_data *)data; 1184 ksdp = &sc->sc_scroll_data; 1185 SETSCROLLMOD(ksdp, usdp, ksdp); 1186 return (0); 1187 1188 case WSKBDIO_GETSCROLL: 1189 usdp = (struct wskbd_scroll_data *)data; 1190 ksdp = &sc->sc_scroll_data; 1191 SETSCROLLMOD(usdp, ksdp, ksdp); 1192 return (0); 1193 #else 1194 case WSKBDIO_GETSCROLL: 1195 case WSKBDIO_SETSCROLL: 1196 return ENODEV; 1197 #endif 1198 1199 #undef SETKEYREPEAT 1200 1201 case WSKBDIO_SETMAP: 1202 if ((flag & FWRITE) == 0) 1203 return (EACCES); 1204 umdp = (struct wskbd_map_data *)data; 1205 if (umdp->maplen > WSKBDIO_MAXMAPLEN) 1206 return (EINVAL); 1207 1208 len = umdp->maplen*sizeof(struct wscons_keymap); 1209 tbuf = malloc(len, M_TEMP, M_WAITOK); 1210 error = copyin(umdp->map, tbuf, len); 1211 if (error == 0) { 1212 wskbd_init_keymap(umdp->maplen, 1213 &sc->sc_map, &sc->sc_maplen); 1214 memcpy(sc->sc_map, tbuf, len); 1215 /* drop the variant bits handled by the map */ 1216 sc->sc_layout = KB_USER | 1217 (KB_VARIANT(sc->sc_layout) & KB_HANDLEDBYWSKBD); 1218 wskbd_update_layout(sc->id, sc->sc_layout); 1219 } 1220 free(tbuf, M_TEMP); 1221 return(error); 1222 1223 case WSKBDIO_GETMAP: 1224 umdp = (struct wskbd_map_data *)data; 1225 if (umdp->maplen > sc->sc_maplen) 1226 umdp->maplen = sc->sc_maplen; 1227 error = copyout(sc->sc_map, umdp->map, 1228 umdp->maplen*sizeof(struct wscons_keymap)); 1229 return(error); 1230 1231 case WSKBDIO_GETENCODING: 1232 *((kbd_t *) data) = sc->sc_layout; 1233 return(0); 1234 1235 case WSKBDIO_SETENCODING: 1236 if ((flag & FWRITE) == 0) 1237 return (EACCES); 1238 enc = *((kbd_t *)data); 1239 if (KB_ENCODING(enc) == KB_USER) { 1240 /* user map must already be loaded */ 1241 if (KB_ENCODING(sc->sc_layout) != KB_USER) 1242 return (EINVAL); 1243 /* map variants make no sense */ 1244 if (KB_VARIANT(enc) & ~KB_HANDLEDBYWSKBD) 1245 return (EINVAL); 1246 } else { 1247 md = *(sc->id->t_keymap); /* structure assignment */ 1248 md.layout = enc; 1249 error = wskbd_load_keymap(&md, &sc->sc_map, 1250 &sc->sc_maplen); 1251 if (error) 1252 return (error); 1253 } 1254 sc->sc_layout = enc; 1255 wskbd_update_layout(sc->id, enc); 1256 return (0); 1257 1258 case WSKBDIO_SETVERSION: 1259 return wsevent_setversion(sc->sc_base.me_evp, *(int *)data); 1260 } 1261 1262 /* 1263 * Try the keyboard driver for WSKBDIO ioctls. It returns -1 1264 * if it didn't recognize the request, and in turn we return 1265 * -1 if we didn't recognize the request. 1266 */ 1267 /* printf("kbdaccess\n"); */ 1268 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 1269 flag, l); 1270 #ifdef WSDISPLAY_COMPAT_RAWKBD 1271 if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) { 1272 int s = spltty(); 1273 sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R 1274 | MOD_CONTROL_L | MOD_CONTROL_R 1275 | MOD_META_L | MOD_META_R 1276 | MOD_COMMAND 1277 | MOD_COMMAND1 | MOD_COMMAND2); 1278 if (sc->sc_repeating) { 1279 sc->sc_repeating = 0; 1280 callout_stop(&sc->sc_repeat_ch); 1281 } 1282 splx(s); 1283 } 1284 #endif 1285 return (error); 1286 } 1287 1288 int 1289 wskbdpoll(dev_t dev, int events, struct lwp *l) 1290 { 1291 struct wskbd_softc *sc = 1292 device_lookup_private(&wskbd_cd, minor(dev)); 1293 1294 if (sc->sc_base.me_evp == NULL) 1295 return (POLLERR); 1296 return (wsevent_poll(sc->sc_base.me_evp, events, l)); 1297 } 1298 1299 int 1300 wskbdkqfilter(dev_t dev, struct knote *kn) 1301 { 1302 struct wskbd_softc *sc = 1303 device_lookup_private(&wskbd_cd, minor(dev)); 1304 1305 if (sc->sc_base.me_evp == NULL) 1306 return (1); 1307 return (wsevent_kqfilter(sc->sc_base.me_evp, kn)); 1308 } 1309 1310 #if NWSDISPLAY > 0 1311 1312 int 1313 wskbd_pickfree(void) 1314 { 1315 int i; 1316 struct wskbd_softc *sc; 1317 1318 for (i = 0; i < wskbd_cd.cd_ndevs; i++) { 1319 sc = device_lookup_private(&wskbd_cd, i); 1320 if (sc == NULL) 1321 continue; 1322 if (sc->sc_base.me_dispdv == NULL) 1323 return (i); 1324 } 1325 return (-1); 1326 } 1327 1328 struct wsevsrc * 1329 wskbd_set_console_display(device_t displaydv, struct wsevsrc *me) 1330 { 1331 struct wskbd_softc *sc = wskbd_console_device; 1332 1333 if (sc == NULL) 1334 return (NULL); 1335 sc->sc_base.me_dispdv = displaydv; 1336 #if NWSMUX > 0 1337 (void)wsmux_attach_sc((struct wsmux_softc *)me, &sc->sc_base); 1338 #endif 1339 return (&sc->sc_base); 1340 } 1341 1342 int 1343 wskbd_set_display(device_t dv, struct wsevsrc *me) 1344 { 1345 struct wskbd_softc *sc = device_private(dv); 1346 device_t displaydv = me != NULL ? me->me_dispdv : NULL; 1347 device_t odisplaydv; 1348 int error; 1349 1350 DPRINTF(("wskbd_set_display: %s me=%p odisp=%p disp=%p cons=%d\n", 1351 device_xname(dv), me, sc->sc_base.me_dispdv, displaydv, 1352 sc->sc_isconsole)); 1353 1354 if (sc->sc_isconsole) 1355 return (EBUSY); 1356 1357 if (displaydv != NULL) { 1358 if (sc->sc_base.me_dispdv != NULL) 1359 return (EBUSY); 1360 } else { 1361 if (sc->sc_base.me_dispdv == NULL) 1362 return (ENXIO); 1363 } 1364 1365 odisplaydv = sc->sc_base.me_dispdv; 1366 sc->sc_base.me_dispdv = NULL; 1367 error = wskbd_enable(sc, displaydv != NULL); 1368 sc->sc_base.me_dispdv = displaydv; 1369 if (error) { 1370 sc->sc_base.me_dispdv = odisplaydv; 1371 return (error); 1372 } 1373 1374 if (displaydv) 1375 aprint_verbose_dev(sc->sc_base.me_dv, "connecting to %s\n", 1376 device_xname(displaydv)); 1377 else 1378 aprint_verbose_dev(sc->sc_base.me_dv, "disconnecting from %s\n", 1379 device_xname(odisplaydv)); 1380 1381 return (0); 1382 } 1383 1384 #endif /* NWSDISPLAY > 0 */ 1385 1386 #if NWSMUX > 0 1387 int 1388 wskbd_add_mux(int unit, struct wsmux_softc *muxsc) 1389 { 1390 struct wskbd_softc *sc = device_lookup_private(&wskbd_cd, unit); 1391 1392 if (sc == NULL) 1393 return (ENXIO); 1394 1395 if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL) 1396 return (EBUSY); 1397 1398 return (wsmux_attach_sc(muxsc, &sc->sc_base)); 1399 } 1400 #endif 1401 1402 /* 1403 * Console interface. 1404 */ 1405 int 1406 wskbd_cngetc(dev_t dev) 1407 { 1408 static int num = 0; 1409 static int pos; 1410 u_int type; 1411 int data; 1412 keysym_t ks; 1413 1414 if (!wskbd_console_initted) 1415 return 0; 1416 1417 if (wskbd_console_device != NULL && 1418 !wskbd_console_device->sc_translating) 1419 return 0; 1420 1421 for(;;) { 1422 if (num-- > 0) { 1423 ks = wskbd_console_data.t_symbols[pos++]; 1424 if (KS_GROUP(ks) == KS_GROUP_Plain) 1425 return (KS_VALUE(ks)); 1426 } else { 1427 (*wskbd_console_data.t_consops->getc) 1428 (wskbd_console_data.t_consaccesscookie, 1429 &type, &data); 1430 if (type == WSCONS_EVENT_ASCII) { 1431 /* 1432 * We assume that when the driver falls back 1433 * to deliver pure ASCII it is in a state that 1434 * it can not track press/release events 1435 * reliable - so we clear all previously 1436 * accumulated modifier state. 1437 */ 1438 wskbd_console_data.t_modifiers = 0; 1439 return(data); 1440 } 1441 num = wskbd_translate(&wskbd_console_data, type, data); 1442 pos = 0; 1443 } 1444 } 1445 } 1446 1447 void 1448 wskbd_cnpollc(dev_t dev, int poll) 1449 { 1450 1451 if (!wskbd_console_initted) 1452 return; 1453 1454 if (wskbd_console_device != NULL && 1455 !wskbd_console_device->sc_translating) 1456 return; 1457 1458 (*wskbd_console_data.t_consops->pollc) 1459 (wskbd_console_data.t_consaccesscookie, poll); 1460 } 1461 1462 void 1463 wskbd_cnbell(dev_t dev, u_int pitch, u_int period, u_int volume) 1464 { 1465 1466 if (!wskbd_console_initted) 1467 return; 1468 1469 if (wskbd_console_data.t_consops->bell != NULL) 1470 (*wskbd_console_data.t_consops->bell) 1471 (wskbd_console_data.t_consaccesscookie, pitch, period, 1472 volume); 1473 } 1474 1475 static inline void 1476 update_leds(struct wskbd_internal *id) 1477 { 1478 int new_state; 1479 1480 new_state = 0; 1481 if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK)) 1482 new_state |= WSKBD_LED_CAPS; 1483 if (id->t_modifiers & MOD_NUMLOCK) 1484 new_state |= WSKBD_LED_NUM; 1485 if (id->t_modifiers & MOD_COMPOSE) 1486 new_state |= WSKBD_LED_COMPOSE; 1487 if (id->t_modifiers & MOD_HOLDSCREEN) 1488 new_state |= WSKBD_LED_SCROLL; 1489 1490 if (id->t_sc && new_state != id->t_sc->sc_ledstate) { 1491 (*id->t_sc->sc_accessops->set_leds) 1492 (id->t_sc->sc_accesscookie, new_state); 1493 id->t_sc->sc_ledstate = new_state; 1494 } 1495 } 1496 1497 static inline void 1498 update_modifier(struct wskbd_internal *id, u_int type, int toggle, int mask) 1499 { 1500 if (toggle) { 1501 if (type == WSCONS_EVENT_KEY_DOWN) 1502 id->t_modifiers ^= mask; 1503 } else { 1504 if (type == WSCONS_EVENT_KEY_DOWN) 1505 id->t_modifiers |= mask; 1506 else 1507 id->t_modifiers &= ~mask; 1508 } 1509 } 1510 1511 #if NWSDISPLAY > 0 1512 static void 1513 change_displayparam(struct wskbd_softc *sc, int param, int updown, 1514 int wraparound) 1515 { 1516 int res; 1517 struct wsdisplay_param dp; 1518 1519 dp.param = param; 1520 res = wsdisplay_param(sc->sc_base.me_dispdv, WSDISPLAYIO_GETPARAM, &dp); 1521 1522 if (res == EINVAL) 1523 return; /* no such parameter */ 1524 1525 dp.curval += updown; 1526 if (dp.max < dp.curval) 1527 dp.curval = wraparound ? dp.min : dp.max; 1528 else 1529 if (dp.curval < dp.min) 1530 dp.curval = wraparound ? dp.max : dp.min; 1531 wsdisplay_param(sc->sc_base.me_dispdv, WSDISPLAYIO_SETPARAM, &dp); 1532 } 1533 #endif 1534 1535 static int 1536 internal_command(struct wskbd_softc *sc, u_int *type, keysym_t ksym, 1537 keysym_t ksym2) 1538 { 1539 #if NWSDISPLAY > 0 && defined(WSDISPLAY_SCROLLSUPPORT) 1540 u_int state = 0; 1541 #endif 1542 switch (ksym) { 1543 case KS_Cmd_VolumeToggle: 1544 if (*type == WSCONS_EVENT_KEY_DOWN) 1545 pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_TOGGLE); 1546 break; 1547 case KS_Cmd_VolumeUp: 1548 if (*type == WSCONS_EVENT_KEY_DOWN) 1549 pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_UP); 1550 break; 1551 case KS_Cmd_VolumeDown: 1552 if (*type == WSCONS_EVENT_KEY_DOWN) 1553 pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_DOWN); 1554 break; 1555 #if NWSDISPLAY > 0 && defined(WSDISPLAY_SCROLLSUPPORT) 1556 case KS_Cmd_ScrollFastUp: 1557 case KS_Cmd_ScrollFastDown: 1558 if (*type == WSCONS_EVENT_KEY_DOWN) { 1559 GETMODSTATE(sc->id->t_modifiers, state); 1560 if ((sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_HOLD 1561 && MOD_ONESET(sc->id, MOD_HOLDSCREEN)) 1562 || (sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_NORMAL 1563 && sc->sc_scroll_data.modifier == state)) { 1564 update_modifier(sc->id, *type, 0, MOD_COMMAND); 1565 wsdisplay_scroll(sc->sc_base.me_dispdv, 1566 (ksym == KS_Cmd_ScrollFastUp) ? 1567 WSDISPLAY_SCROLL_BACKWARD : 1568 WSDISPLAY_SCROLL_FORWARD); 1569 return (1); 1570 } else { 1571 return (0); 1572 } 1573 } 1574 1575 case KS_Cmd_ScrollSlowUp: 1576 case KS_Cmd_ScrollSlowDown: 1577 if (*type == WSCONS_EVENT_KEY_DOWN) { 1578 GETMODSTATE(sc->id->t_modifiers, state); 1579 if ((sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_HOLD 1580 && MOD_ONESET(sc->id, MOD_HOLDSCREEN)) 1581 || (sc->sc_scroll_data.mode == WSKBD_SCROLL_MODE_NORMAL 1582 && sc->sc_scroll_data.modifier == state)) { 1583 update_modifier(sc->id, *type, 0, MOD_COMMAND); 1584 wsdisplay_scroll(sc->sc_base.me_dispdv, 1585 (ksym == KS_Cmd_ScrollSlowUp) ? 1586 WSDISPLAY_SCROLL_BACKWARD | WSDISPLAY_SCROLL_LOW: 1587 WSDISPLAY_SCROLL_FORWARD | WSDISPLAY_SCROLL_LOW); 1588 return (1); 1589 } else { 1590 return (0); 1591 } 1592 } 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