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