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