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