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