1 /* 2 * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer as 10 * the first lines of this file unmodified. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD: src/sys/dev/kbd/kbd.c,v 1.17.2.2 2001/07/30 16:46:43 yokota Exp $ 27 */ 28 /* 29 * Generic keyboard driver. 30 */ 31 32 #include "opt_kbd.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/kernel.h> 37 #include <sys/malloc.h> 38 #include <sys/caps.h> 39 #include <sys/conf.h> 40 #include <sys/proc.h> 41 #include <sys/tty.h> 42 #include <sys/event.h> 43 #include <sys/vnode.h> 44 #include <sys/uio.h> 45 #include <sys/thread.h> 46 47 #include <machine/console.h> 48 49 #include "kbdreg.h" 50 51 #if 0 52 #define lwkt_gettoken(x) 53 #define lwkt_reltoken(x) 54 #endif 55 56 #define KBD_INDEX(dev) minor(dev) 57 58 #define KB_QSIZE 512 59 #define KB_BUFSIZE 64 60 61 struct genkbd_softc { 62 int gkb_flags; /* flag/status bits */ 63 #define KB_ASLEEP (1 << 0) 64 struct kqinfo gkb_rkq; 65 char gkb_q[KB_QSIZE]; /* input queue */ 66 unsigned int gkb_q_start; 67 unsigned int gkb_q_length; 68 }; 69 70 typedef struct genkbd_softc *genkbd_softc_t; 71 72 static SLIST_HEAD(, keyboard_driver) keyboard_drivers = 73 SLIST_HEAD_INITIALIZER(keyboard_drivers); 74 75 SET_DECLARE(kbddriver_set, const keyboard_driver_t); 76 77 /* local arrays */ 78 79 /* 80 * We need at least one entry each in order to initialize a keyboard 81 * for the kernel console. The arrays will be increased dynamically 82 * when necessary. 83 */ 84 85 static keyboard_t *keyboard[KBD_MAXKEYBOARDS]; 86 87 keyboard_switch_t *kbdsw[KBD_MAXKEYBOARDS]; 88 89 /* 90 * Low-level keyboard driver functions. 91 * 92 * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard 93 * driver, call these functions to initialize the keyboard_t structure 94 * and register it to the virtual keyboard driver `kbd'. 95 * 96 * The reinit call is made when a driver has partially detached a keyboard 97 * but does not unregistered it, then wishes to reinitialize it later on. 98 * This is how the USB keyboard driver handles the 'default' keyboard, 99 * because unregistering the keyboard associated with the console will 100 * destroy its console association forever. 101 */ 102 void 103 kbd_reinit_struct(keyboard_t *kbd, int config, int pref) 104 { 105 lwkt_gettoken(&kbd_token); 106 kbd->kb_flags |= KB_NO_DEVICE; /* device has not been found */ 107 kbd->kb_config = config & ~KB_CONF_PROBE_ONLY; 108 kbd->kb_led = 0; /* unknown */ 109 kbd->kb_data = NULL; 110 kbd->kb_keymap = NULL; 111 kbd->kb_accentmap = NULL; 112 kbd->kb_fkeytab = NULL; 113 kbd->kb_fkeytab_size = 0; 114 kbd->kb_delay1 = KB_DELAY1; /* these values are advisory only */ 115 kbd->kb_delay2 = KB_DELAY2; 116 kbd->kb_count = 0; 117 kbd->kb_pref = pref; 118 bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact)); 119 lwkt_reltoken(&kbd_token); 120 } 121 122 /* initialize the keyboard_t structure */ 123 void 124 kbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config, 125 int pref, int port, int port_size) 126 { 127 lwkt_gettoken(&kbd_token); 128 kbd->kb_flags = 0; 129 kbd->kb_name = name; 130 kbd->kb_type = type; 131 kbd->kb_unit = unit; 132 kbd->kb_io_base = port; 133 kbd->kb_io_size = port_size; 134 kbd_reinit_struct(kbd, config, pref); 135 lockinit(&kbd->kb_lock, name, 0, LK_CANRECURSE); 136 lwkt_reltoken(&kbd_token); 137 } 138 139 void 140 kbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap, 141 fkeytab_t *fkeymap, int fkeymap_size) 142 { 143 lwkt_gettoken(&kbd_token); 144 kbd->kb_keymap = keymap; 145 kbd->kb_accentmap = accmap; 146 kbd->kb_fkeytab = fkeymap; 147 kbd->kb_fkeytab_size = fkeymap_size; 148 lwkt_reltoken(&kbd_token); 149 } 150 151 /* declare a new keyboard driver */ 152 int 153 kbd_add_driver(keyboard_driver_t *driver) 154 { 155 lwkt_gettoken(&kbd_token); 156 if (SLIST_NEXT(driver, link)) { 157 lwkt_reltoken(&kbd_token); 158 return EINVAL; 159 } 160 SLIST_INSERT_HEAD(&keyboard_drivers, driver, link); 161 lwkt_reltoken(&kbd_token); 162 return 0; 163 } 164 165 int 166 kbd_delete_driver(keyboard_driver_t *driver) 167 { 168 lwkt_gettoken(&kbd_token); 169 SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link); 170 SLIST_NEXT(driver, link) = NULL; 171 lwkt_reltoken(&kbd_token); 172 return 0; 173 } 174 175 /* register a keyboard and associate it with a function table */ 176 int 177 kbd_register(keyboard_t *kbd) 178 { 179 const keyboard_driver_t **list; 180 const keyboard_driver_t *p; 181 keyboard_t *mux; 182 keyboard_info_t ki; 183 int index; 184 185 lwkt_gettoken(&kbd_token); 186 mux = kbd_get_keyboard(kbd_find_keyboard("kbdmux", -1)); 187 188 for (index = 0; index < KBD_MAXKEYBOARDS; ++index) { 189 if (keyboard[index] == NULL) 190 break; 191 } 192 if (index >= KBD_MAXKEYBOARDS) { 193 lwkt_reltoken(&kbd_token); 194 return -1; 195 } 196 197 kbd->kb_index = index; 198 KBD_UNBUSY(kbd); 199 KBD_VALID(kbd); 200 kbd->kb_active = 0; /* disabled until someone calls kbd_enable() */ 201 kbd->kb_token = NULL; 202 kbd->kb_callback.kc_func = NULL; 203 kbd->kb_callback.kc_arg = NULL; 204 callout_init_mp(&kbd->kb_atkbd_timeout_ch); 205 206 SLIST_FOREACH(p, &keyboard_drivers, link) { 207 if (strcmp(p->name, kbd->kb_name) == 0) { 208 keyboard[index] = kbd; 209 kbdsw[index] = p->kbdsw; 210 211 if (mux != NULL) { 212 bzero(&ki, sizeof(ki)); 213 strcpy(ki.kb_name, kbd->kb_name); 214 ki.kb_unit = kbd->kb_unit; 215 kbd_ioctl(mux, KBADDKBD, (caddr_t) &ki); 216 } 217 218 lwkt_reltoken(&kbd_token); 219 return index; 220 } 221 } 222 SET_FOREACH(list, kbddriver_set) { 223 p = *list; 224 if (strcmp(p->name, kbd->kb_name) == 0) { 225 keyboard[index] = kbd; 226 kbdsw[index] = p->kbdsw; 227 228 if (mux != NULL) { 229 bzero(&ki, sizeof(ki)); 230 strcpy(ki.kb_name, kbd->kb_name); 231 ki.kb_unit = kbd->kb_unit; 232 kbd_ioctl(mux, KBADDKBD, (caddr_t) &ki); 233 } 234 235 lwkt_reltoken(&kbd_token); 236 return index; 237 } 238 } 239 240 lwkt_reltoken(&kbd_token); 241 return -1; 242 } 243 244 int 245 kbd_unregister(keyboard_t *kbd) 246 { 247 int error; 248 249 KBD_LOCK_ASSERT(kbd); 250 lwkt_gettoken(&kbd_token); 251 if ((kbd->kb_index < 0) || (kbd->kb_index >= KBD_MAXKEYBOARDS)) { 252 lwkt_reltoken(&kbd_token); 253 return ENOENT; 254 } 255 if (keyboard[kbd->kb_index] != kbd) { 256 lwkt_reltoken(&kbd_token); 257 return ENOENT; 258 } 259 260 callout_stop(&kbd->kb_atkbd_timeout_ch); 261 if (KBD_IS_BUSY(kbd)) { 262 error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING, 263 kbd->kb_callback.kc_arg); 264 if (error) { 265 lwkt_reltoken(&kbd_token); 266 return error; 267 } 268 if (KBD_IS_BUSY(kbd)) { 269 lwkt_reltoken(&kbd_token); 270 return EBUSY; 271 } 272 } 273 KBD_CONFIG_LOST(kbd); 274 KBD_INVALID(kbd); 275 keyboard[kbd->kb_index] = NULL; 276 kbdsw[kbd->kb_index] = NULL; 277 278 KBD_ALWAYS_UNLOCK(kbd); 279 lockuninit(&kbd->kb_lock); 280 281 lwkt_reltoken(&kbd_token); 282 return 0; 283 } 284 285 /* find a funciton table by the driver name */ 286 keyboard_switch_t * 287 kbd_get_switch(char *driver) 288 { 289 const keyboard_driver_t **list; 290 const keyboard_driver_t *p; 291 292 lwkt_gettoken(&kbd_token); 293 294 SLIST_FOREACH(p, &keyboard_drivers, link) { 295 if (strcmp(p->name, driver) == 0) { 296 lwkt_reltoken(&kbd_token); 297 return p->kbdsw; 298 } 299 } 300 SET_FOREACH(list, kbddriver_set) { 301 p = *list; 302 if (strcmp(p->name, driver) == 0) { 303 lwkt_reltoken(&kbd_token); 304 return p->kbdsw; 305 } 306 } 307 308 lwkt_reltoken(&kbd_token); 309 return NULL; 310 } 311 312 /* 313 * Keyboard client functions 314 * Keyboard clients, such as the console driver `syscons' and the keyboard 315 * cdev driver, use these functions to claim and release a keyboard for 316 * exclusive use. 317 */ 318 /* 319 * find the keyboard specified by a driver name and a unit number 320 * starting at given index 321 */ 322 int 323 kbd_find_keyboard2(char *driver, int unit, int index, int legacy) 324 { 325 int i; 326 int pref; 327 int pref_index; 328 329 pref = 0; 330 pref_index = -1; 331 332 lwkt_gettoken(&kbd_token); 333 if ((index < 0) || (index >= KBD_MAXKEYBOARDS)) { 334 lwkt_reltoken(&kbd_token); 335 return (-1); 336 } 337 338 for (i = index; i < KBD_MAXKEYBOARDS; ++i) { 339 if (keyboard[i] == NULL) 340 continue; 341 if (!KBD_IS_VALID(keyboard[i])) 342 continue; 343 if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver)) 344 continue; 345 if ((unit != -1) && (keyboard[i]->kb_unit != unit)) 346 continue; 347 /* 348 * If we are in legacy mode, we do the old preference magic and 349 * don't return on the first found unit. 350 */ 351 if (legacy) { 352 if (pref <= keyboard[i]->kb_pref) { 353 pref = keyboard[i]->kb_pref; 354 pref_index = i; 355 } 356 } else { 357 lwkt_reltoken(&kbd_token); 358 return i; 359 } 360 } 361 362 if (!legacy) 363 KKASSERT(pref_index == -1); 364 365 lwkt_reltoken(&kbd_token); 366 return (pref_index); 367 } 368 369 /* find the keyboard specified by a driver name and a unit number */ 370 int 371 kbd_find_keyboard(char *driver, int unit) 372 { 373 return (kbd_find_keyboard2(driver, unit, 0, 1)); 374 } 375 376 /* allocate a keyboard */ 377 int 378 kbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func, 379 void *arg) 380 { 381 int index; 382 383 if (func == NULL) 384 return -1; 385 386 lwkt_gettoken(&kbd_token); 387 388 index = kbd_find_keyboard(driver, unit); 389 if (index >= 0) { 390 if (KBD_IS_BUSY(keyboard[index])) { 391 lwkt_reltoken(&kbd_token); 392 return -1; 393 } 394 keyboard[index]->kb_token = id; 395 KBD_BUSY(keyboard[index]); 396 keyboard[index]->kb_callback.kc_func = func; 397 keyboard[index]->kb_callback.kc_arg = arg; 398 kbd_clear_state(keyboard[index]); 399 } 400 401 lwkt_reltoken(&kbd_token); 402 return index; 403 } 404 405 int 406 kbd_release(keyboard_t *kbd, void *id) 407 { 408 int error; 409 410 lwkt_gettoken(&kbd_token); 411 412 if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 413 error = EINVAL; 414 } else if (kbd->kb_token != id) { 415 error = EPERM; 416 } else { 417 kbd->kb_token = NULL; 418 KBD_UNBUSY(kbd); 419 kbd->kb_callback.kc_func = NULL; 420 kbd->kb_callback.kc_arg = NULL; 421 kbd_clear_state(kbd); 422 error = 0; 423 } 424 425 lwkt_reltoken(&kbd_token); 426 return error; 427 } 428 429 int 430 kbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func, 431 void *arg) 432 { 433 int error; 434 435 lwkt_gettoken(&kbd_token); 436 437 if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 438 error = EINVAL; 439 } else if (kbd->kb_token != id) { 440 error = EPERM; 441 } else if (func == NULL) { 442 error = EINVAL; 443 } else { 444 kbd->kb_callback.kc_func = func; 445 kbd->kb_callback.kc_arg = arg; 446 error = 0; 447 } 448 449 lwkt_reltoken(&kbd_token); 450 return error; 451 } 452 453 /* get a keyboard structure */ 454 keyboard_t * 455 kbd_get_keyboard(int index) 456 { 457 keyboard_t *kbd; 458 459 lwkt_gettoken(&kbd_token); 460 if ((index < 0) || (index >= KBD_MAXKEYBOARDS)) { 461 lwkt_reltoken(&kbd_token); 462 return NULL; 463 } 464 if (keyboard[index] == NULL) { 465 lwkt_reltoken(&kbd_token); 466 return NULL; 467 } 468 if (!KBD_IS_VALID(keyboard[index])) { 469 lwkt_reltoken(&kbd_token); 470 return NULL; 471 } 472 kbd = keyboard[index]; 473 lwkt_reltoken(&kbd_token); 474 475 return kbd; 476 } 477 478 /* 479 * The back door for the console driver; configure keyboards 480 * This function is for the kernel console to initialize keyboards 481 * at very early stage. 482 */ 483 484 int 485 kbd_configure(int flags) 486 { 487 const keyboard_driver_t **list; 488 const keyboard_driver_t *p; 489 490 lwkt_gettoken(&kbd_token); 491 492 SLIST_FOREACH(p, &keyboard_drivers, link) { 493 if (p->configure != NULL) 494 (*p->configure)(flags); 495 } 496 SET_FOREACH(list, kbddriver_set) { 497 p = *list; 498 if (p->configure != NULL) 499 (*p->configure)(flags); 500 } 501 502 lwkt_reltoken(&kbd_token); 503 return 0; 504 } 505 506 #ifdef KBD_INSTALL_CDEV 507 508 /* 509 * Virtual keyboard cdev driver functions 510 * The virtual keyboard driver dispatches driver functions to 511 * appropriate subdrivers. 512 */ 513 514 #define KBD_UNIT(dev) minor(dev) 515 516 static d_open_t genkbdopen; 517 static d_close_t genkbdclose; 518 static d_read_t genkbdread; 519 static d_write_t genkbdwrite; 520 static d_ioctl_t genkbdioctl; 521 static d_kqfilter_t genkbdkqfilter; 522 523 static void genkbdfiltdetach(struct knote *); 524 static int genkbdfilter(struct knote *, long); 525 526 static struct dev_ops kbd_ops = { 527 { "kbd", 0, D_MPSAFE }, 528 .d_open = genkbdopen, 529 .d_close = genkbdclose, 530 .d_read = genkbdread, 531 .d_write = genkbdwrite, 532 .d_ioctl = genkbdioctl, 533 .d_kqfilter = genkbdkqfilter 534 }; 535 536 /* 537 * Attach a keyboard. 538 * 539 * NOTE: The usb driver does not detach the default keyboard if it is 540 * unplugged, but calls kbd_attach() when it is plugged back in. 541 */ 542 int 543 kbd_attach(keyboard_t *kbd) 544 { 545 cdev_t dev; 546 char tbuf[MAKEDEV_MINNBUF]; 547 548 lwkt_gettoken(&kbd_token); 549 if (kbd->kb_index >= KBD_MAXKEYBOARDS) { 550 lwkt_reltoken(&kbd_token); 551 return EINVAL; 552 } 553 if (keyboard[kbd->kb_index] != kbd) { 554 lwkt_reltoken(&kbd_token); 555 return EINVAL; 556 } 557 558 if (kbd->kb_dev == NULL) { 559 kbd->kb_dev = make_dev(&kbd_ops, kbd->kb_index, 560 UID_ROOT, GID_WHEEL, 0600, "kbd%s", 561 makedev_unit_b32(tbuf, kbd->kb_index)); 562 } 563 dev = kbd->kb_dev; 564 if (dev->si_drv1 == NULL) { 565 dev->si_drv1 = kmalloc(sizeof(struct genkbd_softc), M_DEVBUF, 566 M_WAITOK); 567 } 568 bzero(dev->si_drv1, sizeof(struct genkbd_softc)); 569 570 kprintf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit); 571 lwkt_reltoken(&kbd_token); 572 return 0; 573 } 574 575 int 576 kbd_detach(keyboard_t *kbd) 577 { 578 cdev_t dev; 579 580 lwkt_gettoken(&kbd_token); 581 582 if (kbd->kb_index >= KBD_MAXKEYBOARDS) { 583 lwkt_reltoken(&kbd_token); 584 return EINVAL; 585 } 586 if (keyboard[kbd->kb_index] != kbd) { 587 lwkt_reltoken(&kbd_token); 588 return EINVAL; 589 } 590 591 if ((dev = kbd->kb_dev) != NULL) { 592 if (dev->si_drv1) { 593 kfree(dev->si_drv1, M_DEVBUF); 594 dev->si_drv1 = NULL; 595 } 596 kbd->kb_dev = NULL; 597 } 598 dev_ops_remove_minor(&kbd_ops, kbd->kb_index); 599 lwkt_reltoken(&kbd_token); 600 return 0; 601 } 602 603 /* 604 * Generic keyboard cdev driver functions 605 * Keyboard subdrivers may call these functions to implement common 606 * driver functions. 607 */ 608 609 static void 610 genkbd_putc(genkbd_softc_t sc, char c) 611 { 612 unsigned int p; 613 614 lwkt_gettoken(&kbd_token); 615 616 if (sc->gkb_q_length == KB_QSIZE) { 617 lwkt_reltoken(&kbd_token); 618 return; 619 } 620 621 p = (sc->gkb_q_start + sc->gkb_q_length) % KB_QSIZE; 622 sc->gkb_q[p] = c; 623 sc->gkb_q_length++; 624 625 lwkt_reltoken(&kbd_token); 626 } 627 628 static size_t 629 genkbd_getc(genkbd_softc_t sc, char *buf, size_t len) 630 { 631 632 lwkt_gettoken(&kbd_token); 633 634 /* Determine copy size. */ 635 if (sc->gkb_q_length == 0) { 636 lwkt_reltoken(&kbd_token); 637 return (0); 638 } 639 if (len >= sc->gkb_q_length) 640 len = sc->gkb_q_length; 641 if (len >= KB_QSIZE - sc->gkb_q_start) 642 len = KB_QSIZE - sc->gkb_q_start; 643 644 /* Copy out data and progress offset. */ 645 memcpy(buf, sc->gkb_q + sc->gkb_q_start, len); 646 sc->gkb_q_start = (sc->gkb_q_start + len) % KB_QSIZE; 647 sc->gkb_q_length -= len; 648 649 lwkt_reltoken(&kbd_token); 650 return (len); 651 } 652 653 static kbd_callback_func_t genkbd_event; 654 655 static int 656 genkbdopen(struct dev_open_args *ap) 657 { 658 cdev_t dev = ap->a_head.a_dev; 659 keyboard_t *kbd; 660 genkbd_softc_t sc; 661 int i; 662 663 /* 664 * Disallow access to disk volumes if RESTRICTEDROOT 665 */ 666 if (caps_priv_check_self(SYSCAP_RESTRICTEDROOT)) 667 return (EPERM); 668 669 lwkt_gettoken(&kbd_token); 670 sc = dev->si_drv1; 671 kbd = kbd_get_keyboard(KBD_INDEX(dev)); 672 if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 673 lwkt_reltoken(&kbd_token); 674 return ENXIO; 675 } 676 i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc, 677 genkbd_event, sc); 678 if (i < 0) { 679 lwkt_reltoken(&kbd_token); 680 return EBUSY; 681 } 682 /* assert(i == kbd->kb_index) */ 683 /* assert(kbd == kbd_get_keyboard(i)) */ 684 685 /* 686 * NOTE: even when we have successfully claimed a keyboard, 687 * the device may still be missing (!KBD_HAS_DEVICE(kbd)). 688 */ 689 690 sc->gkb_q_length = 0; 691 lwkt_reltoken(&kbd_token); 692 693 return 0; 694 } 695 696 static int 697 genkbdclose(struct dev_close_args *ap) 698 { 699 cdev_t dev = ap->a_head.a_dev; 700 keyboard_t *kbd; 701 genkbd_softc_t sc; 702 703 /* 704 * NOTE: the device may have already become invalid. 705 * kbd == NULL || !KBD_IS_VALID(kbd) 706 */ 707 lwkt_gettoken(&kbd_token); 708 sc = dev->si_drv1; 709 kbd = kbd_get_keyboard(KBD_INDEX(dev)); 710 if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 711 /* XXX: we shall be forgiving and don't report error... */ 712 } else { 713 kbd_release(kbd, sc); 714 } 715 lwkt_reltoken(&kbd_token); 716 return 0; 717 } 718 719 static int 720 genkbdread(struct dev_read_args *ap) 721 { 722 cdev_t dev = ap->a_head.a_dev; 723 struct uio *uio = ap->a_uio; 724 keyboard_t *kbd; 725 genkbd_softc_t sc; 726 u_char buffer[KB_BUFSIZE]; 727 int len; 728 int error; 729 730 /* wait for input */ 731 lwkt_gettoken(&kbd_token); 732 sc = dev->si_drv1; 733 kbd = kbd_get_keyboard(KBD_INDEX(dev)); 734 if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 735 lwkt_reltoken(&kbd_token); 736 return ENXIO; 737 } 738 while (sc->gkb_q_length == 0) { 739 if (ap->a_ioflag & IO_NDELAY) { /* O_NONBLOCK? */ 740 lwkt_reltoken(&kbd_token); 741 return EWOULDBLOCK; 742 } 743 sc->gkb_flags |= KB_ASLEEP; 744 error = tsleep((caddr_t)sc, PCATCH, "kbdrea", 0); 745 kbd = kbd_get_keyboard(KBD_INDEX(dev)); 746 if ((kbd == NULL) || !KBD_IS_VALID(kbd)) { 747 lwkt_reltoken(&kbd_token); 748 return ENXIO; /* our keyboard has gone... */ 749 } 750 if (error) { 751 sc->gkb_flags &= ~KB_ASLEEP; 752 lwkt_reltoken(&kbd_token); 753 return error; 754 } 755 } 756 lwkt_reltoken(&kbd_token); 757 758 /* copy as much input as possible */ 759 error = 0; 760 while (uio->uio_resid > 0) { 761 len = (int)szmin(uio->uio_resid, sizeof(buffer)); 762 len = genkbd_getc(sc, buffer, len); 763 if (len <= 0) 764 break; 765 error = uiomove(buffer, (size_t)len, uio); 766 if (error) 767 break; 768 } 769 770 return error; 771 } 772 773 static int 774 genkbdwrite(struct dev_write_args *ap) 775 { 776 cdev_t dev = ap->a_head.a_dev; 777 keyboard_t *kbd; 778 779 lwkt_gettoken(&kbd_token); 780 kbd = kbd_get_keyboard(KBD_INDEX(dev)); 781 if ((kbd == NULL) || !KBD_IS_VALID(kbd)) { 782 lwkt_reltoken(&kbd_token); 783 return ENXIO; 784 } 785 lwkt_reltoken(&kbd_token); 786 return ENODEV; 787 } 788 789 static int 790 genkbdioctl(struct dev_ioctl_args *ap) 791 { 792 cdev_t dev = ap->a_head.a_dev; 793 keyboard_t *kbd; 794 int error; 795 796 lwkt_gettoken(&kbd_token); 797 kbd = kbd_get_keyboard(KBD_INDEX(dev)); 798 if ((kbd == NULL) || !KBD_IS_VALID(kbd)) { 799 lwkt_reltoken(&kbd_token); 800 return ENXIO; 801 } 802 error = kbd_ioctl(kbd, ap->a_cmd, ap->a_data); 803 if (error == ENOIOCTL) 804 error = ENODEV; 805 806 lwkt_reltoken(&kbd_token); 807 return error; 808 } 809 810 static struct filterops genkbdfiltops = 811 { FILTEROP_ISFD, NULL, genkbdfiltdetach, genkbdfilter }; 812 813 static int 814 genkbdkqfilter(struct dev_kqfilter_args *ap) 815 { 816 cdev_t dev = ap->a_head.a_dev; 817 struct knote *kn = ap->a_kn; 818 genkbd_softc_t sc; 819 struct klist *klist; 820 821 ap->a_result = 0; 822 823 switch (kn->kn_filter) { 824 case EVFILT_READ: 825 kn->kn_fop = &genkbdfiltops; 826 kn->kn_hook = (caddr_t)dev; 827 break; 828 default: 829 ap->a_result = EOPNOTSUPP; 830 return (0); 831 } 832 833 sc = dev->si_drv1; 834 klist = &sc->gkb_rkq.ki_note; 835 knote_insert(klist, kn); 836 837 return (0); 838 } 839 840 static void 841 genkbdfiltdetach(struct knote *kn) 842 { 843 cdev_t dev = (cdev_t)kn->kn_hook; 844 genkbd_softc_t sc; 845 struct klist *klist; 846 847 sc = dev->si_drv1; 848 klist = &sc->gkb_rkq.ki_note; 849 knote_remove(klist, kn); 850 } 851 852 static int 853 genkbdfilter(struct knote *kn, long hint) 854 { 855 cdev_t dev = (cdev_t)kn->kn_hook; 856 keyboard_t *kbd; 857 genkbd_softc_t sc; 858 int ready = 0; 859 860 lwkt_gettoken(&kbd_token); 861 sc = dev->si_drv1; 862 kbd = kbd_get_keyboard(KBD_INDEX(dev)); 863 if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 864 /* The keyboard has gone */ 865 kn->kn_flags |= (EV_EOF | EV_NODATA); 866 ready = 1; 867 } else { 868 if (sc->gkb_q_length > 0) 869 ready = 1; 870 } 871 lwkt_reltoken(&kbd_token); 872 873 return (ready); 874 } 875 876 static int 877 genkbd_event(keyboard_t *kbd, int event, void *arg) 878 { 879 genkbd_softc_t sc; 880 size_t len; 881 u_char *cp; 882 int mode; 883 int c; 884 885 lwkt_gettoken(&kbd_token); 886 /* assert(KBD_IS_VALID(kbd)) */ 887 sc = (genkbd_softc_t)arg; 888 889 switch (event) { 890 case KBDIO_KEYINPUT: 891 break; 892 case KBDIO_UNLOADING: 893 /* the keyboard is going... */ 894 kbd_release(kbd, sc); 895 if (sc->gkb_flags & KB_ASLEEP) { 896 sc->gkb_flags &= ~KB_ASLEEP; 897 wakeup((caddr_t)sc); 898 } 899 KNOTE(&sc->gkb_rkq.ki_note, 0); 900 lwkt_reltoken(&kbd_token); 901 return 0; 902 default: 903 lwkt_reltoken(&kbd_token); 904 return EINVAL; 905 } 906 907 /* obtain the current key input mode */ 908 if (kbd_ioctl(kbd, KDGKBMODE, (caddr_t)&mode)) 909 mode = K_XLATE; 910 911 /* read all pending input */ 912 while (kbd_check_char(kbd)) { 913 c = kbd_read_char(kbd, FALSE); 914 if (c == NOKEY) 915 continue; 916 if (c == ERRKEY) /* XXX: ring bell? */ 917 continue; 918 if (!KBD_IS_BUSY(kbd)) 919 /* the device is not open, discard the input */ 920 continue; 921 922 /* store the byte as is for K_RAW and K_CODE modes */ 923 if (mode != K_XLATE) { 924 genkbd_putc(sc, KEYCHAR(c)); 925 continue; 926 } 927 928 /* K_XLATE */ 929 if (c & RELKEY) /* key release is ignored */ 930 continue; 931 932 /* process special keys; most of them are just ignored... */ 933 if (c & SPCLKEY) { 934 switch (KEYCHAR(c)) { 935 default: 936 /* ignore them... */ 937 continue; 938 case BTAB: /* a backtab: ESC [ Z */ 939 genkbd_putc(sc, 0x1b); 940 genkbd_putc(sc, '['); 941 genkbd_putc(sc, 'Z'); 942 continue; 943 } 944 } 945 946 /* normal chars, normal chars with the META, function keys */ 947 switch (KEYFLAGS(c)) { 948 case 0: /* a normal char */ 949 genkbd_putc(sc, KEYCHAR(c)); 950 break; 951 case MKEY: /* the META flag: prepend ESC */ 952 genkbd_putc(sc, 0x1b); 953 genkbd_putc(sc, KEYCHAR(c)); 954 break; 955 case FKEY | SPCLKEY: /* a function key, return string */ 956 cp = kbd_get_fkeystr(kbd, KEYCHAR(c), &len); 957 if (cp != NULL) { 958 while (len-- > 0) 959 genkbd_putc(sc, *cp++); 960 } 961 break; 962 } 963 } 964 965 /* wake up sleeping/polling processes */ 966 if (sc->gkb_q_length > 0) { 967 if (sc->gkb_flags & KB_ASLEEP) { 968 sc->gkb_flags &= ~KB_ASLEEP; 969 wakeup((caddr_t)sc); 970 } 971 KNOTE(&sc->gkb_rkq.ki_note, 0); 972 } 973 974 lwkt_reltoken(&kbd_token); 975 return 0; 976 } 977 978 #endif /* KBD_INSTALL_CDEV */ 979 980 /* 981 * Generic low-level keyboard functions 982 * The low-level functions in the keyboard subdriver may use these 983 * functions. 984 */ 985 986 int 987 genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 988 { 989 keyarg_t *keyp; 990 fkeyarg_t *fkeyp; 991 int i; 992 993 lwkt_gettoken(&kbd_token); 994 switch (cmd) { 995 996 case KDGKBINFO: /* get keyboard information */ 997 ((keyboard_info_t *)arg)->kb_index = kbd->kb_index; 998 i = imin(strlen(kbd->kb_name) + 1, 999 sizeof(((keyboard_info_t *)arg)->kb_name)); 1000 bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i); 1001 ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit; 1002 ((keyboard_info_t *)arg)->kb_type = kbd->kb_type; 1003 ((keyboard_info_t *)arg)->kb_config = kbd->kb_config; 1004 ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags; 1005 break; 1006 1007 case KDGKBTYPE: /* get keyboard type */ 1008 *(int *)arg = kbd->kb_type; 1009 break; 1010 1011 case KDGETREPEAT: /* get keyboard repeat rate */ 1012 ((int *)arg)[0] = kbd->kb_delay1; 1013 ((int *)arg)[1] = kbd->kb_delay2; 1014 break; 1015 1016 case GIO_KEYMAP: /* get keyboard translation table */ 1017 bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap)); 1018 break; 1019 case PIO_KEYMAP: /* set keyboard translation table */ 1020 #ifndef KBD_DISABLE_KEYMAP_LOAD 1021 bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 1022 bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap)); 1023 break; 1024 #else 1025 lwkt_reltoken(&kbd_token); 1026 return ENODEV; 1027 #endif 1028 1029 case GIO_KEYMAPENT: /* get keyboard translation table entry */ 1030 keyp = (keyarg_t *)arg; 1031 if (keyp->keynum >= sizeof(kbd->kb_keymap->key) 1032 /sizeof(kbd->kb_keymap->key[0])) { 1033 lwkt_reltoken(&kbd_token); 1034 return EINVAL; 1035 } 1036 bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key, 1037 sizeof(keyp->key)); 1038 break; 1039 case PIO_KEYMAPENT: /* set keyboard translation table entry */ 1040 #ifndef KBD_DISABLE_KEYMAP_LOAD 1041 keyp = (keyarg_t *)arg; 1042 if (keyp->keynum >= sizeof(kbd->kb_keymap->key) 1043 /sizeof(kbd->kb_keymap->key[0])) { 1044 lwkt_reltoken(&kbd_token); 1045 return EINVAL; 1046 } 1047 bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum], 1048 sizeof(keyp->key)); 1049 break; 1050 #else 1051 lwkt_reltoken(&kbd_token); 1052 return ENODEV; 1053 #endif 1054 1055 case GIO_DEADKEYMAP: /* get accent key translation table */ 1056 bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap)); 1057 break; 1058 case PIO_DEADKEYMAP: /* set accent key translation table */ 1059 #ifndef KBD_DISABLE_KEYMAP_LOAD 1060 bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 1061 break; 1062 #else 1063 lwkt_reltoken(&kbd_token); 1064 return ENODEV; 1065 #endif 1066 1067 case GETFKEY: /* get functionkey string */ 1068 fkeyp = (fkeyarg_t *)arg; 1069 if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 1070 lwkt_reltoken(&kbd_token); 1071 return EINVAL; 1072 } 1073 bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef, 1074 kbd->kb_fkeytab[fkeyp->keynum].len); 1075 fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len; 1076 break; 1077 case SETFKEY: /* set functionkey string */ 1078 #ifndef KBD_DISABLE_KEYMAP_LOAD 1079 fkeyp = (fkeyarg_t *)arg; 1080 if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 1081 lwkt_reltoken(&kbd_token); 1082 return EINVAL; 1083 } 1084 kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK); 1085 bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str, 1086 kbd->kb_fkeytab[fkeyp->keynum].len); 1087 break; 1088 #else 1089 lwkt_reltoken(&kbd_token); 1090 return ENODEV; 1091 #endif 1092 1093 default: 1094 lwkt_reltoken(&kbd_token); 1095 return ENOIOCTL; 1096 } 1097 1098 lwkt_reltoken(&kbd_token); 1099 return 0; 1100 } 1101 1102 /* get a pointer to the string associated with the given function key */ 1103 u_char * 1104 genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len) 1105 { 1106 u_char *ch; 1107 1108 if (kbd == NULL) 1109 return NULL; 1110 1111 lwkt_gettoken(&kbd_token); 1112 fkey -= F_FN; 1113 if (fkey > kbd->kb_fkeytab_size) { 1114 lwkt_reltoken(&kbd_token); 1115 return NULL; 1116 } 1117 *len = kbd->kb_fkeytab[fkey].len; 1118 ch = kbd->kb_fkeytab[fkey].str; 1119 1120 lwkt_reltoken(&kbd_token); 1121 return ch; 1122 } 1123 1124 /* diagnostic dump */ 1125 static char * 1126 get_kbd_type_name(int type) 1127 { 1128 static struct { 1129 int type; 1130 char *name; 1131 } name_table[] = { 1132 { KB_84, "AT 84" }, 1133 { KB_101, "AT 101/102" }, 1134 { KB_OTHER, "generic" }, 1135 }; 1136 int i; 1137 1138 for (i = 0; i < NELEM(name_table); ++i) { 1139 if (type == name_table[i].type) 1140 return name_table[i].name; 1141 } 1142 return "unknown"; 1143 } 1144 1145 void 1146 genkbd_diag(keyboard_t *kbd, int level) 1147 { 1148 if (level > 0) { 1149 kprintf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x", 1150 kbd->kb_index, kbd->kb_name, kbd->kb_unit, 1151 get_kbd_type_name(kbd->kb_type), kbd->kb_type, 1152 kbd->kb_config, kbd->kb_flags); 1153 if (kbd->kb_io_base > 0) 1154 kprintf(", port:0x%x-0x%x", kbd->kb_io_base, 1155 kbd->kb_io_base + kbd->kb_io_size - 1); 1156 kprintf("\n"); 1157 } 1158 } 1159 1160 #define set_lockkey_state(k, s, l) \ 1161 if (!((s) & l ## DOWN)) { \ 1162 int i; \ 1163 (s) |= l ## DOWN; \ 1164 (s) ^= l ## ED; \ 1165 i = (s) & LOCK_MASK; \ 1166 kbd_ioctl((k), KDSETLED, (caddr_t)&i); \ 1167 } 1168 1169 static u_int 1170 save_accent_key(keyboard_t *kbd, u_int key, int *accents) 1171 { 1172 int i; 1173 1174 lwkt_gettoken(&kbd_token); 1175 /* make an index into the accent map */ 1176 i = key - F_ACC + 1; 1177 if ((i > kbd->kb_accentmap->n_accs) 1178 || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) { 1179 /* the index is out of range or pointing to an empty entry */ 1180 *accents = 0; 1181 lwkt_reltoken(&kbd_token); 1182 return ERRKEY; 1183 } 1184 1185 /* 1186 * If the same accent key has been hit twice, produce the accent char 1187 * itself. 1188 */ 1189 if (i == *accents) { 1190 key = kbd->kb_accentmap->acc[i - 1].accchar; 1191 *accents = 0; 1192 lwkt_reltoken(&kbd_token); 1193 return key; 1194 } 1195 1196 /* remember the index and wait for the next key */ 1197 *accents = i; 1198 lwkt_reltoken(&kbd_token); 1199 return NOKEY; 1200 } 1201 1202 static u_int 1203 make_accent_char(keyboard_t *kbd, u_int ch, int *accents) 1204 { 1205 struct acc_t *acc; 1206 int i; 1207 1208 lwkt_gettoken(&kbd_token); 1209 acc = &kbd->kb_accentmap->acc[*accents - 1]; 1210 *accents = 0; 1211 1212 /* 1213 * If the accent key is followed by the space key, 1214 * produce the accent char itself. 1215 */ 1216 if (ch == ' ') { 1217 lwkt_reltoken(&kbd_token); 1218 return acc->accchar; 1219 } 1220 1221 /* scan the accent map */ 1222 for (i = 0; i < NUM_ACCENTCHARS; ++i) { 1223 if (acc->map[i][0] == 0) /* end of table */ 1224 break; 1225 if (acc->map[i][0] == ch) { 1226 lwkt_reltoken(&kbd_token); 1227 return acc->map[i][1]; 1228 } 1229 } 1230 lwkt_reltoken(&kbd_token); 1231 /* this char cannot be accented... */ 1232 return ERRKEY; 1233 } 1234 1235 int 1236 genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate, 1237 int *accents) 1238 { 1239 struct keyent_t *key; 1240 int state = *shiftstate; 1241 int action; 1242 int f; 1243 int i; 1244 1245 lwkt_gettoken(&kbd_token); 1246 i = keycode; 1247 f = state & (AGRS | ALKED); 1248 if ((f == AGRS1) || (f == AGRS2) || (f == ALKED)) 1249 i += ALTGR_OFFSET; 1250 key = &kbd->kb_keymap->key[i]; 1251 i = ((state & SHIFTS) ? 1 : 0) 1252 | ((state & CTLS) ? 2 : 0) 1253 | ((state & ALTS) ? 4 : 0); 1254 if (((key->flgs & FLAG_LOCK_C) && (state & CLKED)) 1255 || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) ) 1256 i ^= 1; 1257 1258 if (up) { /* break: key released */ 1259 action = kbd->kb_lastact[keycode]; 1260 kbd->kb_lastact[keycode] = NOP; 1261 switch (action) { 1262 case LSHA: 1263 if (state & SHIFTAON) { 1264 set_lockkey_state(kbd, state, ALK); 1265 state &= ~ALKDOWN; 1266 } 1267 action = LSH; 1268 /* FALL THROUGH */ 1269 case LSH: 1270 state &= ~SHIFTS1; 1271 break; 1272 case RSHA: 1273 if (state & SHIFTAON) { 1274 set_lockkey_state(kbd, state, ALK); 1275 state &= ~ALKDOWN; 1276 } 1277 action = RSH; 1278 /* FALL THROUGH */ 1279 case RSH: 1280 state &= ~SHIFTS2; 1281 break; 1282 case LCTRA: 1283 if (state & SHIFTAON) { 1284 set_lockkey_state(kbd, state, ALK); 1285 state &= ~ALKDOWN; 1286 } 1287 action = LCTR; 1288 /* FALL THROUGH */ 1289 case LCTR: 1290 state &= ~CTLS1; 1291 break; 1292 case RCTRA: 1293 if (state & SHIFTAON) { 1294 set_lockkey_state(kbd, state, ALK); 1295 state &= ~ALKDOWN; 1296 } 1297 action = RCTR; 1298 /* FALL THROUGH */ 1299 case RCTR: 1300 state &= ~CTLS2; 1301 break; 1302 case LALTA: 1303 if (state & SHIFTAON) { 1304 set_lockkey_state(kbd, state, ALK); 1305 state &= ~ALKDOWN; 1306 } 1307 action = LALT; 1308 /* FALL THROUGH */ 1309 case LALT: 1310 state &= ~ALTS1; 1311 break; 1312 case RALTA: 1313 if (state & SHIFTAON) { 1314 set_lockkey_state(kbd, state, ALK); 1315 state &= ~ALKDOWN; 1316 } 1317 action = RALT; 1318 /* FALL THROUGH */ 1319 case RALT: 1320 state &= ~ALTS2; 1321 break; 1322 case ASH: 1323 state &= ~AGRS1; 1324 break; 1325 case META: 1326 state &= ~METAS1; 1327 break; 1328 case NLK: 1329 state &= ~NLKDOWN; 1330 break; 1331 case CLK: 1332 state &= ~CLKDOWN; 1333 break; 1334 case SLK: 1335 state &= ~SLKDOWN; 1336 break; 1337 case ALK: 1338 state &= ~ALKDOWN; 1339 break; 1340 case NOP: 1341 /* release events of regular keys are not reported */ 1342 *shiftstate &= ~SHIFTAON; 1343 lwkt_reltoken(&kbd_token); 1344 return NOKEY; 1345 } 1346 *shiftstate = state & ~SHIFTAON; 1347 lwkt_reltoken(&kbd_token); 1348 return (SPCLKEY | RELKEY | action); 1349 } else { /* make: key pressed */ 1350 action = key->map[i]; 1351 state &= ~SHIFTAON; 1352 if (key->spcl & (0x80 >> i)) { 1353 /* special keys */ 1354 if (kbd->kb_lastact[keycode] == NOP) 1355 kbd->kb_lastact[keycode] = action; 1356 if (kbd->kb_lastact[keycode] != action) 1357 action = NOP; 1358 switch (action) { 1359 /* LOCKING KEYS */ 1360 case NLK: 1361 set_lockkey_state(kbd, state, NLK); 1362 break; 1363 case CLK: 1364 set_lockkey_state(kbd, state, CLK); 1365 break; 1366 case SLK: 1367 set_lockkey_state(kbd, state, SLK); 1368 break; 1369 case ALK: 1370 set_lockkey_state(kbd, state, ALK); 1371 break; 1372 /* NON-LOCKING KEYS */ 1373 case SPSC: case RBT: case SUSP: case STBY: 1374 case DBG: case NEXT: case PREV: case PNC: 1375 case HALT: case PDWN: 1376 *accents = 0; 1377 break; 1378 case BTAB: 1379 *accents = 0; 1380 action |= BKEY; 1381 break; 1382 case LSHA: 1383 state |= SHIFTAON; 1384 action = LSH; 1385 /* FALL THROUGH */ 1386 case LSH: 1387 state |= SHIFTS1; 1388 break; 1389 case RSHA: 1390 state |= SHIFTAON; 1391 action = RSH; 1392 /* FALL THROUGH */ 1393 case RSH: 1394 state |= SHIFTS2; 1395 break; 1396 case LCTRA: 1397 state |= SHIFTAON; 1398 action = LCTR; 1399 /* FALL THROUGH */ 1400 case LCTR: 1401 state |= CTLS1; 1402 break; 1403 case RCTRA: 1404 state |= SHIFTAON; 1405 action = RCTR; 1406 /* FALL THROUGH */ 1407 case RCTR: 1408 state |= CTLS2; 1409 break; 1410 case LALTA: 1411 state |= SHIFTAON; 1412 action = LALT; 1413 /* FALL THROUGH */ 1414 case LALT: 1415 state |= ALTS1; 1416 break; 1417 case RALTA: 1418 state |= SHIFTAON; 1419 action = RALT; 1420 /* FALL THROUGH */ 1421 case RALT: 1422 state |= ALTS2; 1423 break; 1424 case ASH: 1425 state |= AGRS1; 1426 break; 1427 case META: 1428 state |= METAS1; 1429 break; 1430 case NOP: 1431 *shiftstate = state; 1432 lwkt_reltoken(&kbd_token); 1433 return NOKEY; 1434 default: 1435 /* is this an accent (dead) key? */ 1436 *shiftstate = state; 1437 if (action >= F_ACC && action <= L_ACC) { 1438 action = save_accent_key(kbd, action, 1439 accents); 1440 switch (action) { 1441 case NOKEY: 1442 case ERRKEY: 1443 lwkt_reltoken(&kbd_token); 1444 return action; 1445 default: 1446 if (state & METAS) { 1447 lwkt_reltoken(&kbd_token); 1448 return (action | MKEY); 1449 } else { 1450 lwkt_reltoken(&kbd_token); 1451 return action; 1452 } 1453 } 1454 /* NOT REACHED */ 1455 } 1456 /* other special keys */ 1457 if (*accents > 0) { 1458 *accents = 0; 1459 lwkt_reltoken(&kbd_token); 1460 return ERRKEY; 1461 } 1462 if (action >= F_FN && action <= L_FN) 1463 action |= FKEY; 1464 /* XXX: return fkey string for the FKEY? */ 1465 lwkt_reltoken(&kbd_token); 1466 return (SPCLKEY | action); 1467 } 1468 *shiftstate = state; 1469 lwkt_reltoken(&kbd_token); 1470 return (SPCLKEY | action); 1471 } else { 1472 /* regular keys */ 1473 kbd->kb_lastact[keycode] = NOP; 1474 *shiftstate = state; 1475 if (*accents > 0) { 1476 /* make an accented char */ 1477 action = make_accent_char(kbd, action, accents); 1478 if (action == ERRKEY) { 1479 lwkt_reltoken(&kbd_token); 1480 return action; 1481 } 1482 } 1483 if (state & METAS) 1484 action |= MKEY; 1485 lwkt_reltoken(&kbd_token); 1486 return action; 1487 } 1488 } 1489 /* NOT REACHED */ 1490 lwkt_reltoken(&kbd_token); 1491 } 1492