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