wskbd.c revision 1.55
1/* $OpenBSD: wskbd.c,v 1.55 2007/05/31 22:23:13 tedu 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 *, enum devact); 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); 389 bzero(sc->id, sizeof(struct wskbd_internal)); 390 sc->id->t_keymap = ap->keymap; 391 wskbd_update_layout(sc->id, ap->keymap->layout); 392 } 393 394#if NWSDISPLAY > 0 395 timeout_set(&sc->sc_repeat_ch, wskbd_repeat, sc); 396#endif 397 398 sc->id->t_sc = sc; 399 400 sc->sc_accessops = ap->accessops; 401 sc->sc_accesscookie = ap->accesscookie; 402 sc->sc_repeating = 0; 403 sc->sc_translating = 1; 404 sc->sc_ledstate = -1; /* force update */ 405 406 if (wskbd_load_keymap(sc->id->t_keymap, 407 &sc->sc_map, &sc->sc_maplen) != 0) 408 panic("cannot load keymap"); 409 410 sc->sc_layout = sc->id->t_keymap->layout; 411 412 /* set default bell and key repeat data */ 413 sc->sc_bell_data = wskbd_default_bell_data; 414 sc->sc_keyrepeat_data = wskbd_default_keyrepeat_data; 415 416 if (ap->console) { 417 KASSERT(wskbd_console_initted); 418 KASSERT(wskbd_console_device == NULL); 419 420 wskbd_console_device = sc; 421 422 printf(": console keyboard"); 423 424#if NWSDISPLAY > 0 425 wsdisplay_set_console_kbd(&sc->sc_base); /* sets me_dispdv */ 426 if (sc->sc_displaydv != NULL) 427 printf(", using %s", sc->sc_displaydv->dv_xname); 428#endif 429 } 430 printf("\n"); 431 432#if NWSMUX > 0 433 if (mux >= 0) { 434 error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base); 435 if (error) 436 printf("%s: attach error=%d\n", 437 sc->sc_base.me_dv.dv_xname, error); 438 } 439#endif 440 441#if WSDISPLAY > 0 && NWSMUX == 0 442 if (ap->console == 0) { 443 /* 444 * In the non-wsmux world, always connect wskbd0 and wsdisplay0 445 * together. 446 */ 447 extern struct cfdriver wsdisplay_cd; 448 449 if (wsdisplay_cd.cd_ndevs != 0 && self->dv_unit == 0) { 450 if (wskbd_set_display(self, 451 wsdisplay_cd.cd_devs[0]) == 0) 452 wsdisplay_set_kbd(wsdisplay_cd.cd_devs[0], 453 (struct wsevsrc *)sc); 454 } 455 } 456#endif 457 458} 459 460void 461wskbd_cnattach(const struct wskbd_consops *consops, void *conscookie, 462 const struct wskbd_mapdata *mapdata) 463{ 464 465 KASSERT(!wskbd_console_initted); 466 467 wskbd_console_data.t_keymap = mapdata; 468 wskbd_update_layout(&wskbd_console_data, mapdata->layout); 469 470 wskbd_console_data.t_consops = consops; 471 wskbd_console_data.t_consaccesscookie = conscookie; 472 473#if NWSDISPLAY > 0 474 wsdisplay_set_cons_kbd(wskbd_cngetc, wskbd_cnpollc, wskbd_cnbell); 475#endif 476 477 wskbd_console_initted = 1; 478} 479 480void 481wskbd_cndetach() 482{ 483 KASSERT(wskbd_console_initted); 484 485 wskbd_console_data.t_keymap = 0; 486 487 wskbd_console_data.t_consops = 0; 488 wskbd_console_data.t_consaccesscookie = 0; 489 490#if NWSDISPLAY > 0 491 wsdisplay_unset_cons_kbd(); 492#endif 493 494 wskbd_console_initted = 0; 495} 496 497#if NWSDISPLAY > 0 498void 499wskbd_repeat(void *v) 500{ 501 struct wskbd_softc *sc = (struct wskbd_softc *)v; 502 int s = spltty(); 503 504 if (!sc->sc_repeating) { 505 /* 506 * race condition: a "key up" event came in when wskbd_repeat() 507 * was already called but not yet spltty()'d 508 */ 509 splx(s); 510 return; 511 } 512 if (sc->sc_translating) { 513 /* deliver keys */ 514 if (sc->sc_base.me_dispdv != NULL) { 515 int i; 516 for (i = 0; i < sc->sc_repeating; i++) 517 wsdisplay_kbdinput(sc->sc_base.me_dispdv, 518 sc->id->t_symbols[i]); 519 } 520 } else { 521 /* queue event */ 522 wskbd_deliver_event(sc, sc->sc_repeat_type, 523 sc->sc_repeat_value); 524 } 525 if (sc->sc_keyrepeat_data.delN != 0) 526 timeout_add(&sc->sc_repeat_ch, 527 (hz * sc->sc_keyrepeat_data.delN) / 1000); 528 splx(s); 529} 530#endif 531 532int 533wskbd_activate(struct device *self, enum devact act) 534{ 535 struct wskbd_softc *sc = (struct wskbd_softc *)self; 536 537 if (act == DVACT_DEACTIVATE) 538 sc->sc_dying = 1; 539 return (0); 540} 541 542/* 543 * Detach a keyboard. To keep track of users of the softc we keep 544 * a reference count that's incremented while inside, e.g., read. 545 * If the keyboard is active and the reference count is > 0 (0 is the 546 * normal state) we post an event and then wait for the process 547 * that had the reference to wake us up again. Then we blow away the 548 * vnode and return (which will deallocate the softc). 549 */ 550int 551wskbd_detach(struct device *self, int flags) 552{ 553 struct wskbd_softc *sc = (struct wskbd_softc *)self; 554 struct wseventvar *evar; 555 int maj, mn; 556 int s; 557 558#if NWSMUX > 0 559 /* Tell parent mux we're leaving. */ 560 if (sc->sc_base.me_parent != NULL) 561 wsmux_detach_sc(&sc->sc_base); 562#endif 563 564#if NWSDISPLAY > 0 565 if (sc->sc_repeating) { 566 sc->sc_repeating = 0; 567 timeout_del(&sc->sc_repeat_ch); 568 } 569#endif 570 571 if (sc->sc_isconsole) { 572 KASSERT(wskbd_console_device == sc); 573 wskbd_console_device = NULL; 574 } 575 576 evar = sc->sc_base.me_evp; 577 if (evar != NULL && evar->io != NULL) { 578 s = spltty(); 579 if (--sc->sc_refcnt >= 0) { 580 /* Wake everyone by generating a dummy event. */ 581 if (++evar->put >= WSEVENT_QSIZE) 582 evar->put = 0; 583 WSEVENT_WAKEUP(evar); 584 /* Wait for processes to go away. */ 585 if (tsleep(sc, PZERO, "wskdet", hz * 60)) 586 printf("wskbd_detach: %s didn't detach\n", 587 sc->sc_base.me_dv.dv_xname); 588 } 589 splx(s); 590 } 591 592 /* locate the major number */ 593 for (maj = 0; maj < nchrdev; maj++) 594 if (cdevsw[maj].d_open == wskbdopen) 595 break; 596 597 /* Nuke the vnodes for any open instances. */ 598 mn = self->dv_unit; 599 vdevgone(maj, mn, mn, VCHR); 600 601 return (0); 602} 603 604void 605wskbd_input(struct device *dev, u_int type, int value) 606{ 607 struct wskbd_softc *sc = (struct wskbd_softc *)dev; 608#if NWSDISPLAY > 0 609 int num, i; 610#endif 611 612#if NWSDISPLAY > 0 613 if (sc->sc_repeating) { 614 sc->sc_repeating = 0; 615 timeout_del(&sc->sc_repeat_ch); 616 } 617 618 /* 619 * If /dev/wskbdN is not connected in event mode translate and 620 * send upstream. 621 */ 622 if (sc->sc_translating) { 623#ifdef BURNER_SUPPORT 624 if (type == WSCONS_EVENT_KEY_DOWN && sc->sc_displaydv != NULL) 625 wsdisplay_burn(sc->sc_displaydv, WSDISPLAY_BURN_KBD); 626#endif 627 num = wskbd_translate(sc->id, type, value); 628 if (num > 0) { 629 if (sc->sc_base.me_dispdv != NULL) { 630#ifdef SCROLLBACK_SUPPORT 631 /* XXX - Shift_R+PGUP(release) emits PrtSc */ 632 if (sc->id->t_symbols[0] != KS_Print_Screen) { 633 wsscrollback(sc->sc_base.me_dispdv, 634 WSDISPLAY_SCROLL_RESET); 635 } 636#endif 637 for (i = 0; i < num; i++) { 638 wsdisplay_kbdinput(sc->sc_base.me_dispdv, 639 sc->id->t_symbols[i]); 640 } 641 } 642 643 if (sc->sc_keyrepeat_data.del1 != 0) { 644 sc->sc_repeating = num; 645 timeout_add(&sc->sc_repeat_ch, 646 (hz * sc->sc_keyrepeat_data.del1) / 1000); 647 } 648 } 649 return; 650 } 651#endif 652 653 wskbd_deliver_event(sc, type, value); 654 655#if NWSDISPLAY > 0 656 /* Repeat key presses if enabled. */ 657 if (type == WSCONS_EVENT_KEY_DOWN && sc->sc_keyrepeat_data.del1 != 0) { 658 sc->sc_repeat_type = type; 659 sc->sc_repeat_value = value; 660 sc->sc_repeating = 1; 661 timeout_add(&sc->sc_repeat_ch, 662 (hz * sc->sc_keyrepeat_data.del1) / 1000); 663 } 664#endif 665} 666 667/* 668 * Keyboard is generating events. Turn this keystroke into an 669 * event and put it in the queue. If the queue is full, the 670 * keystroke is lost (sorry!). 671 */ 672void 673wskbd_deliver_event(struct wskbd_softc *sc, u_int type, int value) 674{ 675 struct wseventvar *evar; 676 struct wscons_event *ev; 677 int put; 678 679 evar = sc->sc_base.me_evp; 680 681 if (evar == NULL) { 682 DPRINTF(("wskbd_input: not open\n")); 683 return; 684 } 685 686#ifdef DIAGNOSTIC 687 if (evar->q == NULL) { 688 printf("wskbd_input: evar->q=NULL\n"); 689 return; 690 } 691#endif 692 693 put = evar->put; 694 ev = &evar->q[put]; 695 put = (put + 1) % WSEVENT_QSIZE; 696 if (put == evar->get) { 697 log(LOG_WARNING, "%s: event queue overflow\n", 698 sc->sc_base.me_dv.dv_xname); 699 return; 700 } 701 ev->type = type; 702 ev->value = value; 703 nanotime(&ev->time); 704 evar->put = put; 705 WSEVENT_WAKEUP(evar); 706} 707 708#ifdef WSDISPLAY_COMPAT_RAWKBD 709void 710wskbd_rawinput(struct device *dev, u_char *buf, int len) 711{ 712#if NWSDISPLAY > 0 713 struct wskbd_softc *sc = (struct wskbd_softc *)dev; 714 int i; 715 716 if (sc->sc_base.me_dispdv != NULL) 717 for (i = 0; i < len; i++) 718 wsdisplay_kbdinput(sc->sc_base.me_dispdv, buf[i]); 719 /* this is KS_GROUP_Ascii */ 720#endif 721} 722#endif /* WSDISPLAY_COMPAT_RAWKBD */ 723 724#if NWSDISPLAY > 0 725void 726wskbd_holdscreen(struct wskbd_softc *sc, int hold) 727{ 728 int new_state; 729 730 if (sc->sc_base.me_dispdv != NULL) { 731 wsdisplay_kbdholdscreen(sc->sc_base.me_dispdv, hold); 732 new_state = sc->sc_ledstate; 733 if (hold) 734 new_state |= WSKBD_LED_SCROLL; 735 else 736 new_state &= ~WSKBD_LED_SCROLL; 737 if (new_state != sc->sc_ledstate) { 738 (*sc->sc_accessops->set_leds)(sc->sc_accesscookie, 739 new_state); 740 sc->sc_ledstate = new_state; 741 } 742 } 743} 744#endif 745 746int 747wskbd_enable(struct wskbd_softc *sc, int on) 748{ 749 int error; 750 751#if NWSDISPLAY > 0 752 if (sc->sc_base.me_dispdv != NULL) 753 return (0); 754 755 /* Always cancel auto repeat when fiddling with the kbd. */ 756 if (sc->sc_repeating) { 757 sc->sc_repeating = 0; 758 timeout_del(&sc->sc_repeat_ch); 759 } 760#endif 761 762 error = (*sc->sc_accessops->enable)(sc->sc_accesscookie, on); 763 DPRINTF(("wskbd_enable: sc=%p on=%d res=%d\n", sc, on, error)); 764 return (error); 765} 766 767#if NWSMUX > 0 768int 769wskbd_mux_open(struct wsevsrc *me, struct wseventvar *evp) 770{ 771 struct wskbd_softc *sc = (struct wskbd_softc *)me; 772 773 if (sc->sc_dying) 774 return (EIO); 775 776 if (sc->sc_base.me_evp != NULL) 777 return (EBUSY); 778 779 return (wskbd_do_open(sc, evp)); 780} 781#endif 782 783int 784wskbdopen(dev_t dev, int flags, int mode, struct proc *p) 785{ 786 struct wskbd_softc *sc; 787 struct wseventvar *evar; 788 int unit, error; 789 790 unit = minor(dev); 791 if (unit >= wskbd_cd.cd_ndevs || /* make sure it was attached */ 792 (sc = wskbd_cd.cd_devs[unit]) == NULL) 793 return (ENXIO); 794 795#if NWSMUX > 0 796 DPRINTF(("wskbdopen: %s mux=%p p=%p\n", sc->sc_base.me_dv.dv_xname, 797 sc->sc_base.me_parent, p)); 798#endif 799 800 if (sc->sc_dying) 801 return (EIO); 802 803 if ((flags & (FREAD | FWRITE)) == FWRITE) { 804 /* Not opening for read, only ioctl is available. */ 805 return (0); 806 } 807 808#if NWSMUX > 0 809 if (sc->sc_base.me_parent != NULL) { 810 /* Grab the keyboard out of the greedy hands of the mux. */ 811 DPRINTF(("wskbdopen: detach\n")); 812 wsmux_detach_sc(&sc->sc_base); 813 } 814#endif 815 816 if (sc->sc_base.me_evp != NULL) 817 return (EBUSY); 818 819 evar = &sc->sc_base.me_evar; 820 wsevent_init(evar); 821 evar->io = p; 822 823 error = wskbd_do_open(sc, evar); 824 if (error) { 825 DPRINTF(("wskbdopen: %s open failed\n", 826 sc->sc_base.me_dv.dv_xname)); 827 sc->sc_base.me_evp = NULL; 828 wsevent_fini(evar); 829 } 830 return (error); 831} 832 833int 834wskbd_do_open(struct wskbd_softc *sc, struct wseventvar *evp) 835{ 836 sc->sc_base.me_evp = evp; 837 sc->sc_translating = 0; 838 839 return (wskbd_enable(sc, 1)); 840} 841 842int 843wskbdclose(dev_t dev, int flags, int mode, struct proc *p) 844{ 845 struct wskbd_softc *sc = 846 (struct wskbd_softc *)wskbd_cd.cd_devs[minor(dev)]; 847 struct wseventvar *evar = sc->sc_base.me_evp; 848 849 if (evar == NULL) 850 /* not open for read */ 851 return (0); 852 853 sc->sc_base.me_evp = NULL; 854 sc->sc_translating = 1; 855 (void)wskbd_enable(sc, 0); 856 wsevent_fini(evar); 857 858 return (0); 859} 860 861#if NWSMUX > 0 862int 863wskbd_mux_close(struct wsevsrc *me) 864{ 865 struct wskbd_softc *sc = (struct wskbd_softc *)me; 866 867 sc->sc_base.me_evp = NULL; 868 sc->sc_translating = 1; 869 (void)wskbd_enable(sc, 0); 870 871 return (0); 872} 873#endif 874 875int 876wskbdread(dev_t dev, struct uio *uio, int flags) 877{ 878 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)]; 879 int error; 880 881 if (sc->sc_dying) 882 return (EIO); 883 884#ifdef DIAGNOSTIC 885 if (sc->sc_base.me_evp == NULL) { 886 printf("wskbdread: evp == NULL\n"); 887 return (EINVAL); 888 } 889#endif 890 891 sc->sc_refcnt++; 892 error = wsevent_read(&sc->sc_base.me_evar, uio, flags); 893 if (--sc->sc_refcnt < 0) { 894 wakeup(sc); 895 error = EIO; 896 } 897 return (error); 898} 899 900int 901wskbdioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) 902{ 903 return (wskbd_do_ioctl(wskbd_cd.cd_devs[minor(dev)], cmd, data, flag,p)); 904} 905 906/* A wrapper around the ioctl() workhorse to make reference counting easy. */ 907int 908wskbd_do_ioctl(struct device *dv, u_long cmd, caddr_t data, int flag, 909 struct proc *p) 910{ 911 struct wskbd_softc *sc = (struct wskbd_softc *)dv; 912 int error; 913 914 sc->sc_refcnt++; 915 error = wskbd_do_ioctl_sc(sc, cmd, data, flag, p); 916 if (--sc->sc_refcnt < 0) 917 wakeup(sc); 918 return (error); 919} 920 921int 922wskbd_do_ioctl_sc(struct wskbd_softc *sc, u_long cmd, caddr_t data, int flag, 923 struct proc *p) 924{ 925 int error; 926 927 /* 928 * Try the generic ioctls that the wskbd interface supports. 929 */ 930 switch (cmd) { 931 case FIONBIO: /* we will remove this someday (soon???) */ 932 return (0); 933 934 case FIOASYNC: 935 if (sc->sc_base.me_evp == NULL) 936 return (EINVAL); 937 sc->sc_base.me_evp->async = *(int *)data != 0; 938 return (0); 939 940 case FIOSETOWN: 941 if (sc->sc_base.me_evp == NULL) 942 return (EINVAL); 943 if (-*(int *)data != sc->sc_base.me_evp->io->p_pgid && 944 *(int *)data != sc->sc_base.me_evp->io->p_pid) 945 return (EPERM); 946 return (0); 947 948 case TIOCSPGRP: 949 if (sc->sc_base.me_evp == NULL) 950 return (EINVAL); 951 if (*(int *)data != sc->sc_base.me_evp->io->p_pgid) 952 return (EPERM); 953 return (0); 954 } 955 956 /* 957 * Try the keyboard driver for WSKBDIO ioctls. It returns -1 958 * if it didn't recognize the request. 959 */ 960 error = wskbd_displayioctl(&sc->sc_base.me_dv, cmd, data, flag, p); 961 return (error != -1 ? error : ENOTTY); 962} 963 964/* 965 * WSKBDIO ioctls, handled in both emulation mode and in ``raw'' mode. 966 * Some of these have no real effect in raw mode, however. 967 */ 968int 969wskbd_displayioctl(struct device *dev, u_long cmd, caddr_t data, int flag, 970 struct proc *p) 971{ 972 struct wskbd_softc *sc = (struct wskbd_softc *)dev; 973 struct wskbd_bell_data *ubdp, *kbdp; 974 struct wskbd_keyrepeat_data *ukdp, *kkdp; 975 struct wskbd_map_data *umdp; 976 struct wskbd_mapdata md; 977 kbd_t enc; 978 void *buf; 979 int len, error; 980 981 switch (cmd) { 982 case WSKBDIO_BELL: 983 case WSKBDIO_COMPLEXBELL: 984 case WSKBDIO_SETBELL: 985 case WSKBDIO_SETKEYREPEAT: 986 case WSKBDIO_SETDEFAULTKEYREPEAT: 987 case WSKBDIO_SETMAP: 988 case WSKBDIO_SETENCODING: 989 if ((flag & FWRITE) == 0) 990 return (EACCES); 991 } 992 993 switch (cmd) { 994#define SETBELL(dstp, srcp, dfltp) \ 995 do { \ 996 (dstp)->pitch = ((srcp)->which & WSKBD_BELL_DOPITCH) ? \ 997 (srcp)->pitch : (dfltp)->pitch; \ 998 (dstp)->period = ((srcp)->which & WSKBD_BELL_DOPERIOD) ? \ 999 (srcp)->period : (dfltp)->period; \ 1000 (dstp)->volume = ((srcp)->which & WSKBD_BELL_DOVOLUME) ? \ 1001 (srcp)->volume : (dfltp)->volume; \ 1002 (dstp)->which = WSKBD_BELL_DOALL; \ 1003 } while (0) 1004 1005 case WSKBDIO_BELL: 1006 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, 1007 WSKBDIO_COMPLEXBELL, (caddr_t)&sc->sc_bell_data, flag, p)); 1008 1009 case WSKBDIO_COMPLEXBELL: 1010 ubdp = (struct wskbd_bell_data *)data; 1011 SETBELL(ubdp, ubdp, &sc->sc_bell_data); 1012 return ((*sc->sc_accessops->ioctl)(sc->sc_accesscookie, 1013 WSKBDIO_COMPLEXBELL, (caddr_t)ubdp, flag, p)); 1014 1015 case WSKBDIO_SETBELL: 1016 kbdp = &sc->sc_bell_data; 1017setbell: 1018 ubdp = (struct wskbd_bell_data *)data; 1019 SETBELL(kbdp, ubdp, kbdp); 1020 return (0); 1021 1022 case WSKBDIO_GETBELL: 1023 kbdp = &sc->sc_bell_data; 1024getbell: 1025 ubdp = (struct wskbd_bell_data *)data; 1026 SETBELL(ubdp, kbdp, kbdp); 1027 return (0); 1028 1029 case WSKBDIO_SETDEFAULTBELL: 1030 if ((error = suser(p, 0)) != 0) 1031 return (error); 1032 kbdp = &wskbd_default_bell_data; 1033 goto setbell; 1034 1035 1036 case WSKBDIO_GETDEFAULTBELL: 1037 kbdp = &wskbd_default_bell_data; 1038 goto getbell; 1039 1040#undef SETBELL 1041 1042#define SETKEYREPEAT(dstp, srcp, dfltp) \ 1043 do { \ 1044 (dstp)->del1 = ((srcp)->which & WSKBD_KEYREPEAT_DODEL1) ? \ 1045 (srcp)->del1 : (dfltp)->del1; \ 1046 (dstp)->delN = ((srcp)->which & WSKBD_KEYREPEAT_DODELN) ? \ 1047 (srcp)->delN : (dfltp)->delN; \ 1048 (dstp)->which = WSKBD_KEYREPEAT_DOALL; \ 1049 } while (0) 1050 1051 case WSKBDIO_SETKEYREPEAT: 1052 kkdp = &sc->sc_keyrepeat_data; 1053setkeyrepeat: 1054 ukdp = (struct wskbd_keyrepeat_data *)data; 1055 SETKEYREPEAT(kkdp, ukdp, kkdp); 1056 return (0); 1057 1058 case WSKBDIO_GETKEYREPEAT: 1059 kkdp = &sc->sc_keyrepeat_data; 1060getkeyrepeat: 1061 ukdp = (struct wskbd_keyrepeat_data *)data; 1062 SETKEYREPEAT(ukdp, kkdp, kkdp); 1063 return (0); 1064 1065 case WSKBDIO_SETDEFAULTKEYREPEAT: 1066 if ((error = suser(p, 0)) != 0) 1067 return (error); 1068 kkdp = &wskbd_default_keyrepeat_data; 1069 goto setkeyrepeat; 1070 1071 1072 case WSKBDIO_GETDEFAULTKEYREPEAT: 1073 kkdp = &wskbd_default_keyrepeat_data; 1074 goto getkeyrepeat; 1075 1076#undef SETKEYREPEAT 1077 1078 case WSKBDIO_SETMAP: 1079 umdp = (struct wskbd_map_data *)data; 1080 if (umdp->maplen > WSKBDIO_MAXMAPLEN) 1081 return (EINVAL); 1082 1083 len = umdp->maplen * sizeof(struct wscons_keymap); 1084 buf = malloc(len, M_TEMP, M_WAITOK); 1085 error = copyin(umdp->map, buf, len); 1086 if (error == 0) { 1087 wskbd_init_keymap(umdp->maplen, 1088 &sc->sc_map, &sc->sc_maplen); 1089 memcpy(sc->sc_map, buf, len); 1090 /* drop the variant bits handled by the map */ 1091 sc->sc_layout = KB_USER | 1092 (KB_VARIANT(sc->sc_layout) & KB_HANDLEDBYWSKBD); 1093 wskbd_update_layout(sc->id, sc->sc_layout); 1094 } 1095 free(buf, M_TEMP); 1096 return(error); 1097 1098 case WSKBDIO_GETMAP: 1099 umdp = (struct wskbd_map_data *)data; 1100 if (umdp->maplen > sc->sc_maplen) 1101 umdp->maplen = sc->sc_maplen; 1102 error = copyout(sc->sc_map, umdp->map, 1103 umdp->maplen*sizeof(struct wscons_keymap)); 1104 return(error); 1105 1106 case WSKBDIO_GETENCODING: 1107 *((kbd_t *) data) = sc->sc_layout; 1108 return(0); 1109 1110 case WSKBDIO_SETENCODING: 1111 enc = *((kbd_t *)data); 1112 if (KB_ENCODING(enc) == KB_USER) { 1113 /* user map must already be loaded */ 1114 if (KB_ENCODING(sc->sc_layout) != KB_USER) 1115 return (EINVAL); 1116 /* map variants make no sense */ 1117 if (KB_VARIANT(enc) & ~KB_HANDLEDBYWSKBD) 1118 return (EINVAL); 1119 } else { 1120 md = *(sc->id->t_keymap); /* structure assignment */ 1121 md.layout = enc; 1122 error = wskbd_load_keymap(&md, &sc->sc_map, 1123 &sc->sc_maplen); 1124 if (error) 1125 return(error); 1126 } 1127 sc->sc_layout = enc; 1128 wskbd_update_layout(sc->id, enc); 1129 return (0); 1130 } 1131 1132 /* 1133 * Try the keyboard driver for WSKBDIO ioctls. It returns -1 1134 * if it didn't recognize the request, and in turn we return 1135 * -1 if we didn't recognize the request. 1136 */ 1137/* printf("kbdaccess\n"); */ 1138 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd, data, 1139 flag, p); 1140#ifdef WSDISPLAY_COMPAT_RAWKBD 1141 if (!error && cmd == WSKBDIO_SETMODE && *(int *)data == WSKBD_RAW) { 1142 int s = spltty(); 1143 sc->id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R 1144 | MOD_CONTROL_L | MOD_CONTROL_R 1145 | MOD_META_L | MOD_META_R 1146 | MOD_COMMAND 1147 | MOD_COMMAND1 | MOD_COMMAND2); 1148#if NWSDISPLAY > 0 1149 if (sc->sc_repeating) { 1150 sc->sc_repeating = 0; 1151 timeout_del(&sc->sc_repeat_ch); 1152 } 1153#endif 1154 splx(s); 1155 } 1156#endif 1157 return (error); 1158} 1159 1160int 1161wskbdpoll(dev_t dev, int events, struct proc *p) 1162{ 1163 struct wskbd_softc *sc = wskbd_cd.cd_devs[minor(dev)]; 1164 1165 if (sc->sc_base.me_evp == NULL) 1166 return (POLLERR); 1167 return (wsevent_poll(sc->sc_base.me_evp, events, p)); 1168} 1169 1170#if NWSDISPLAY > 0 1171 1172int 1173wskbd_pickfree() 1174{ 1175 int i; 1176 struct wskbd_softc *sc; 1177 1178 for (i = 0; i < wskbd_cd.cd_ndevs; i++) { 1179 if ((sc = wskbd_cd.cd_devs[i]) == NULL) 1180 continue; 1181 if (sc->sc_displaydv == NULL) 1182 return (i); 1183 } 1184 return (-1); 1185} 1186 1187struct wsevsrc * 1188wskbd_set_console_display(struct device *displaydv, struct wsevsrc *me) 1189{ 1190 struct wskbd_softc *sc = wskbd_console_device; 1191 1192 if (sc == NULL) 1193 return (NULL); 1194 sc->sc_base.me_dispdv = displaydv; 1195#if NWSMUX > 0 1196 (void)wsmux_attach_sc((struct wsmux_softc *)me, &sc->sc_base); 1197#endif 1198 return (&sc->sc_base); 1199} 1200 1201int 1202wskbd_set_display(struct device *dv, struct device *displaydv) 1203{ 1204 struct wskbd_softc *sc = (struct wskbd_softc *)dv; 1205 struct device *odisplaydv; 1206 int error; 1207 1208 DPRINTF(("wskbd_set_display: %s odisp=%p disp=%p cons=%d\n", 1209 dv->dv_xname, sc->sc_base.me_dispdv, displaydv, 1210 sc->sc_isconsole)); 1211 1212 if (sc->sc_isconsole) 1213 return (EBUSY); 1214 1215 if (displaydv != NULL) { 1216 if (sc->sc_base.me_dispdv != NULL) 1217 return (EBUSY); 1218 } else { 1219 if (sc->sc_base.me_dispdv == NULL) 1220 return (ENXIO); 1221 } 1222 1223 odisplaydv = sc->sc_base.me_dispdv; 1224 sc->sc_base.me_dispdv = NULL; 1225 error = wskbd_enable(sc, displaydv != NULL); 1226 sc->sc_base.me_dispdv = displaydv; 1227 if (error) { 1228 sc->sc_base.me_dispdv = odisplaydv; 1229 return (error); 1230 } 1231 1232 if (displaydv) 1233 printf("%s: connecting to %s\n", 1234 sc->sc_base.me_dv.dv_xname, displaydv->dv_xname); 1235 else 1236 printf("%s: disconnecting from %s\n", 1237 sc->sc_base.me_dv.dv_xname, odisplaydv->dv_xname); 1238 1239 return (0); 1240} 1241 1242#endif /* NWSDISPLAY > 0 */ 1243 1244#if NWSMUX > 0 1245int 1246wskbd_add_mux(int unit, struct wsmux_softc *muxsc) 1247{ 1248 struct wskbd_softc *sc; 1249 1250 if (unit < 0 || unit >= wskbd_cd.cd_ndevs || 1251 (sc = wskbd_cd.cd_devs[unit]) == NULL) 1252 return (ENXIO); 1253 1254 if (sc->sc_base.me_parent != NULL || sc->sc_base.me_evp != NULL) 1255 return (EBUSY); 1256 1257 return (wsmux_attach_sc(muxsc, &sc->sc_base)); 1258} 1259#endif 1260 1261/* 1262 * Console interface. 1263 */ 1264int 1265wskbd_cngetc(dev_t dev) 1266{ 1267 static int num = 0; 1268 static int pos; 1269 u_int type; 1270 int data; 1271 keysym_t ks; 1272 1273 if (!wskbd_console_initted) 1274 return 0; 1275 1276 if (wskbd_console_device != NULL && 1277 !wskbd_console_device->sc_translating) 1278 return 0; 1279 1280 for(;;) { 1281 if (num-- > 0) { 1282 ks = wskbd_console_data.t_symbols[pos++]; 1283 if (KS_GROUP(ks) == KS_GROUP_Ascii) 1284 return (KS_VALUE(ks)); 1285 } else { 1286 (*wskbd_console_data.t_consops->getc) 1287 (wskbd_console_data.t_consaccesscookie, 1288 &type, &data); 1289 num = wskbd_translate(&wskbd_console_data, type, data); 1290 pos = 0; 1291 } 1292 } 1293} 1294 1295void 1296wskbd_cnpollc(dev_t dev, int poll) 1297{ 1298 1299 if (!wskbd_console_initted) 1300 return; 1301 1302 if (wskbd_console_device != NULL && 1303 !wskbd_console_device->sc_translating) 1304 return; 1305 1306 (*wskbd_console_data.t_consops->pollc) 1307 (wskbd_console_data.t_consaccesscookie, poll); 1308} 1309 1310void 1311wskbd_cnbell(dev_t dev, u_int pitch, u_int period, u_int volume) 1312{ 1313 if (!wskbd_console_initted) 1314 return; 1315 1316 if (wskbd_console_data.t_consops->bell != NULL) 1317 (*wskbd_console_data.t_consops->bell) 1318 (wskbd_console_data.t_consaccesscookie, pitch, period, 1319 volume); 1320} 1321 1322void 1323update_leds(struct wskbd_internal *id) 1324{ 1325 int new_state; 1326 1327 new_state = 0; 1328 if (id->t_modifiers & (MOD_SHIFTLOCK | MOD_CAPSLOCK)) 1329 new_state |= WSKBD_LED_CAPS; 1330 if (id->t_modifiers & MOD_NUMLOCK) 1331 new_state |= WSKBD_LED_NUM; 1332 if (id->t_modifiers & MOD_COMPOSE) 1333 new_state |= WSKBD_LED_COMPOSE; 1334 if (id->t_modifiers & MOD_HOLDSCREEN) 1335 new_state |= WSKBD_LED_SCROLL; 1336 1337 if (id->t_sc && new_state != id->t_sc->sc_ledstate) { 1338 (*id->t_sc->sc_accessops->set_leds) 1339 (id->t_sc->sc_accesscookie, new_state); 1340 id->t_sc->sc_ledstate = new_state; 1341 } 1342} 1343 1344void 1345update_modifier(struct wskbd_internal *id, u_int type, int toggle, int mask) 1346{ 1347 if (toggle) { 1348 if (type == WSCONS_EVENT_KEY_DOWN) 1349 id->t_modifiers ^= mask; 1350 } else { 1351 if (type == WSCONS_EVENT_KEY_DOWN) 1352 id->t_modifiers |= mask; 1353 else 1354 id->t_modifiers &= ~mask; 1355 } 1356} 1357 1358#if NWSDISPLAY > 0 1359void 1360change_displayparam(struct wskbd_softc *sc, int param, int updown, 1361 int wraparound) 1362{ 1363 int res; 1364 struct wsdisplay_param dp; 1365 1366 dp.param = param; 1367 res = wsdisplay_param(sc->sc_base.me_dispdv, WSDISPLAYIO_GETPARAM, &dp); 1368 1369 if (res == EINVAL) 1370 return; /* no such parameter */ 1371 1372 dp.curval += updown; 1373 if (dp.max < dp.curval) 1374 dp.curval = wraparound ? dp.min : dp.max; 1375 else 1376 if (dp.curval < dp.min) 1377 dp.curval = wraparound ? dp.max : dp.min; 1378 wsdisplay_param(sc->sc_base.me_dispdv, WSDISPLAYIO_SETPARAM, &dp); 1379} 1380#endif 1381 1382int 1383internal_command(struct wskbd_softc *sc, u_int *type, keysym_t ksym, 1384 keysym_t ksym2) 1385{ 1386 switch (ksym) { 1387 case KS_Cmd: 1388 update_modifier(sc->id, *type, 0, MOD_COMMAND); 1389 ksym = ksym2; 1390 break; 1391 1392 case KS_Cmd1: 1393 update_modifier(sc->id, *type, 0, MOD_COMMAND1); 1394 break; 1395 1396 case KS_Cmd2: 1397 update_modifier(sc->id, *type, 0, MOD_COMMAND2); 1398 break; 1399 } 1400 1401 if (*type != WSCONS_EVENT_KEY_DOWN) 1402 return (0); 1403 1404#ifdef SCROLLBACK_SUPPORT 1405#if NWSDISPLAY > 0 1406 switch (ksym) { 1407 case KS_Cmd_ScrollBack: 1408 if (MOD_ONESET(sc->id, MOD_ANYSHIFT)) { 1409 if (sc->sc_displaydv != NULL) 1410 wsscrollback(sc->sc_displaydv, 1411 WSDISPLAY_SCROLL_BACKWARD); 1412 return (1); 1413 } 1414 break; 1415 1416 case KS_Cmd_ScrollFwd: 1417 if (MOD_ONESET(sc->id, MOD_ANYSHIFT)) { 1418 if (sc->sc_displaydv != NULL) 1419 wsscrollback(sc->sc_displaydv, 1420 WSDISPLAY_SCROLL_FORWARD); 1421 return (1); 1422 } 1423 break; 1424 } 1425#endif 1426#endif 1427 1428 if (!MOD_ONESET(sc->id, MOD_COMMAND) && 1429 !MOD_ALLSET(sc->id, MOD_COMMAND1 | MOD_COMMAND2)) 1430 return (0); 1431 1432#ifdef DDB 1433 if (ksym == KS_Cmd_Debugger) { 1434 if (sc->sc_isconsole && db_console) 1435 Debugger(); 1436 /* discard this key (ddb discarded command modifiers) */ 1437 *type = WSCONS_EVENT_KEY_UP; 1438 return (1); 1439 } 1440#endif 1441 1442#if NWSDISPLAY > 0 1443 if (sc->sc_base.me_dispdv == NULL) 1444 return (0); 1445 1446 switch (ksym) { 1447 case KS_Cmd_Screen0: 1448 case KS_Cmd_Screen1: 1449 case KS_Cmd_Screen2: 1450 case KS_Cmd_Screen3: 1451 case KS_Cmd_Screen4: 1452 case KS_Cmd_Screen5: 1453 case KS_Cmd_Screen6: 1454 case KS_Cmd_Screen7: 1455 case KS_Cmd_Screen8: 1456 case KS_Cmd_Screen9: 1457 case KS_Cmd_Screen10: 1458 case KS_Cmd_Screen11: 1459 wsdisplay_switch(sc->sc_displaydv, ksym - KS_Cmd_Screen0, 0); 1460 return (1); 1461 case KS_Cmd_ResetEmul: 1462 wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETEMUL); 1463 return (1); 1464 case KS_Cmd_ResetClose: 1465 wsdisplay_reset(sc->sc_displaydv, WSDISPLAY_RESETCLOSE); 1466 return (1); 1467#if defined(__i386__) || defined(__amd64__) 1468 case KS_Cmd_KbdReset: 1469 if (kbd_reset == 1) { 1470 kbd_reset = 0; 1471 psignal(initproc, SIGUSR1); 1472 } 1473 return (1); 1474#endif 1475 case KS_Cmd_BacklightOn: 1476 case KS_Cmd_BacklightOff: 1477 case KS_Cmd_BacklightToggle: 1478 change_displayparam(sc, WSDISPLAYIO_PARAM_BACKLIGHT, 1479 ksym == KS_Cmd_BacklightOff ? -1 : 1, 1480 ksym == KS_Cmd_BacklightToggle ? 1 : 0); 1481 return (1); 1482 case KS_Cmd_BrightnessUp: 1483 case KS_Cmd_BrightnessDown: 1484 case KS_Cmd_BrightnessRotate: 1485 change_displayparam(sc, WSDISPLAYIO_PARAM_BRIGHTNESS, 1486 ksym == KS_Cmd_BrightnessDown ? -1 : 1, 1487 ksym == KS_Cmd_BrightnessRotate ? 1 : 0); 1488 return (1); 1489 case KS_Cmd_ContrastUp: 1490 case KS_Cmd_ContrastDown: 1491 case KS_Cmd_ContrastRotate: 1492 change_displayparam(sc, WSDISPLAYIO_PARAM_CONTRAST, 1493 ksym == KS_Cmd_ContrastDown ? -1 : 1, 1494 ksym == KS_Cmd_ContrastRotate ? 1 : 0); 1495 return (1); 1496 } 1497#endif 1498 return (0); 1499} 1500 1501int 1502wskbd_translate(struct wskbd_internal *id, u_int type, int value) 1503{ 1504 struct wskbd_softc *sc = id->t_sc; 1505 keysym_t ksym, res, *group; 1506 struct wscons_keymap kpbuf, *kp; 1507 int gindex, iscommand = 0; 1508 1509 if (type == WSCONS_EVENT_ALL_KEYS_UP) { 1510#if NWSDISPLAY > 0 1511 if (sc != NULL && sc->sc_repeating) { 1512 sc->sc_repeating = 0; 1513 timeout_del(&sc->sc_repeat_ch); 1514 } 1515#endif 1516 id->t_modifiers &= ~(MOD_SHIFT_L | MOD_SHIFT_R | 1517 MOD_CONTROL_L | MOD_CONTROL_R | 1518 MOD_META_L | MOD_META_R | 1519 MOD_MODESHIFT | MOD_MODELOCK | 1520 MOD_COMMAND | MOD_COMMAND1 | MOD_COMMAND2); 1521 update_leds(id); 1522 return (0); 1523 } 1524 1525 if (sc != NULL) { 1526 if (value < 0 || value >= sc->sc_maplen) { 1527#ifdef DEBUG 1528 printf("wskbd_translate: keycode %d out of range\n", 1529 value); 1530#endif 1531 return (0); 1532 } 1533 kp = sc->sc_map + value; 1534 } else { 1535 kp = &kpbuf; 1536 wskbd_get_mapentry(id->t_keymap, value, kp); 1537 } 1538 1539 /* if this key has a command, process it first */ 1540 if (sc != NULL && kp->command != KS_voidSymbol) 1541 iscommand = internal_command(sc, &type, kp->command, 1542 kp->group1[0]); 1543 1544 /* Now update modifiers */ 1545 switch (kp->group1[0]) { 1546 case KS_Shift_L: 1547 update_modifier(id, type, 0, MOD_SHIFT_L); 1548 break; 1549 1550 case KS_Shift_R: 1551 update_modifier(id, type, 0, MOD_SHIFT_R); 1552 break; 1553 1554 case KS_Shift_Lock: 1555 update_modifier(id, type, 1, MOD_SHIFTLOCK); 1556 break; 1557 1558 case KS_Caps_Lock: 1559 update_modifier(id, type, 1, MOD_CAPSLOCK); 1560 break; 1561 1562 case KS_Control_L: 1563 update_modifier(id, type, 0, MOD_CONTROL_L); 1564 break; 1565 1566 case KS_Control_R: 1567 update_modifier(id, type, 0, MOD_CONTROL_R); 1568 break; 1569 1570 case KS_Alt_L: 1571 update_modifier(id, type, 0, MOD_META_L); 1572 break; 1573 1574 case KS_Alt_R: 1575 update_modifier(id, type, 0, MOD_META_R); 1576 break; 1577 1578 case KS_Mode_switch: 1579 update_modifier(id, type, 0, MOD_MODESHIFT); 1580 break; 1581 1582 case KS_Mode_Lock: 1583 update_modifier(id, type, 1, MOD_MODELOCK); 1584 break; 1585 1586 case KS_Num_Lock: 1587 update_modifier(id, type, 1, MOD_NUMLOCK); 1588 break; 1589 1590#if NWSDISPLAY > 0 1591 case KS_Hold_Screen: 1592 if (sc != NULL) { 1593 update_modifier(id, type, 1, MOD_HOLDSCREEN); 1594 wskbd_holdscreen(sc, id->t_modifiers & MOD_HOLDSCREEN); 1595 } 1596 break; 1597 1598 default: 1599 if (sc != NULL && sc->sc_repeating && 1600 ((type == WSCONS_EVENT_KEY_UP && value != sc->sc_repkey) || 1601 (type == WSCONS_EVENT_KEY_DOWN && value == sc->sc_repkey))) 1602 return (0); 1603 break; 1604#endif 1605 } 1606 1607#if NWSDISPLAY > 0 1608 if (sc != NULL) { 1609 if (sc->sc_repeating) { 1610 sc->sc_repeating = 0; 1611 timeout_del(&sc->sc_repeat_ch); 1612 } 1613 sc->sc_repkey = value; 1614 } 1615#endif 1616 1617 /* If this is a key release or we are in command mode, we are done */ 1618 if (type != WSCONS_EVENT_KEY_DOWN || iscommand) { 1619 update_leds(id); 1620 return (0); 1621 } 1622 1623 /* Get the keysym */ 1624 if (id->t_modifiers & (MOD_MODESHIFT|MOD_MODELOCK) && 1625 !MOD_ONESET(id, MOD_ANYCONTROL)) 1626 group = & kp->group2[0]; 1627 else 1628 group = & kp->group1[0]; 1629 1630 if ((id->t_modifiers & MOD_NUMLOCK) && 1631 KS_GROUP(group[1]) == KS_GROUP_Keypad) { 1632 gindex = !MOD_ONESET(id, MOD_ANYSHIFT); 1633 ksym = group[gindex]; 1634 } else { 1635 /* CAPS alone should only affect letter keys */ 1636 if ((id->t_modifiers & (MOD_CAPSLOCK | MOD_ANYSHIFT)) == 1637 MOD_CAPSLOCK) { 1638 gindex = 0; 1639 ksym = ksym_upcase(group[0]); 1640 } else { 1641 gindex = MOD_ONESET(id, MOD_ANYSHIFT); 1642 ksym = group[gindex]; 1643 } 1644 } 1645 1646 /* Submit Audio keys for hotkey processing */ 1647 if (KS_GROUP(ksym) == KS_GROUP_Function) { 1648 switch (ksym) { 1649#if NAUDIO > 0 1650 case KS_AudioMute: 1651 workq_add_task(NULL, 0, (workq_fn)wskbd_set_mixervolume, 1652 (void *)(u_long)0, NULL); 1653 break; 1654 case KS_AudioLower: 1655 workq_add_task(NULL, 0, (workq_fn)wskbd_set_mixervolume, 1656 (void *)(u_long)1, NULL); 1657 break; 1658 case KS_AudioRaise: 1659 workq_add_task(NULL, 0, (workq_fn)wskbd_set_mixervolume, 1660 (void *)(u_long)1, NULL); 1661 return (0); 1662#endif 1663 default: 1664 break; 1665 } 1666 } 1667 1668 /* Process compose sequence and dead accents */ 1669 res = KS_voidSymbol; 1670 1671 switch (KS_GROUP(ksym)) { 1672 case KS_GROUP_Ascii: 1673 case KS_GROUP_Keypad: 1674 case KS_GROUP_Function: 1675 res = ksym; 1676 break; 1677 1678 case KS_GROUP_Mod: 1679 if (ksym == KS_Multi_key) { 1680 update_modifier(id, 1, 0, MOD_COMPOSE); 1681 id->t_composelen = 2; 1682 } 1683 break; 1684 1685 case KS_GROUP_Dead: 1686 if (id->t_composelen == 0) { 1687 update_modifier(id, 1, 0, MOD_COMPOSE); 1688 id->t_composelen = 1; 1689 id->t_composebuf[0] = ksym; 1690 } else 1691 res = ksym; 1692 break; 1693 } 1694 1695 if (res == KS_voidSymbol) { 1696 update_leds(id); 1697 return (0); 1698 } 1699 1700 if (id->t_composelen > 0) { 1701 /* 1702 * If the compose key also serves as AltGr (i.e. set to both 1703 * KS_Multi_key and KS_Mode_switch), and would provide a valid, 1704 * distinct combination as AltGr, leave compose mode. 1705 */ 1706 if (id->t_composelen == 2 && group == &kp->group2[0]) { 1707 if (kp->group1[gindex] != kp->group2[gindex]) 1708 id->t_composelen = 0; 1709 } 1710 1711 if (id->t_composelen != 0) { 1712 id->t_composebuf[2 - id->t_composelen] = res; 1713 if (--id->t_composelen == 0) { 1714 res = wskbd_compose_value(id->t_composebuf); 1715 update_modifier(id, 0, 0, MOD_COMPOSE); 1716 } else { 1717 return (0); 1718 } 1719 } 1720 } 1721 1722 update_leds(id); 1723 1724 /* We are done, return the symbol */ 1725 if (KS_GROUP(res) == KS_GROUP_Ascii) { 1726 if (MOD_ONESET(id, MOD_ANYCONTROL)) { 1727 if ((res >= KS_at && res <= KS_z) || res == KS_space) 1728 res = res & 0x1f; 1729 else if (res == KS_2) 1730 res = 0x00; 1731 else if (res >= KS_3 && res <= KS_7) 1732 res = KS_Escape + (res - KS_3); 1733 else if (res == KS_8) 1734 res = KS_Delete; 1735 } 1736 if (MOD_ONESET(id, MOD_ANYMETA)) { 1737 if (id->t_flags & WSKFL_METAESC) { 1738 id->t_symbols[0] = KS_Escape; 1739 id->t_symbols[1] = res; 1740 return (2); 1741 } else 1742 res |= 0x80; 1743 } 1744 } 1745 1746 id->t_symbols[0] = res; 1747 return (1); 1748} 1749