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