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