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