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