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