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