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