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