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