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