kbdmux.c revision 156086
1/* 2 * kbdmux.c 3 */ 4 5/*- 6 * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7 * All rights reserved. 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 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $ 31 * $FreeBSD: head/sys/dev/kbdmux/kbdmux.c 156086 2006-02-27 21:47:38Z emax $ 32 */ 33 34#include "opt_kbd.h" 35 36#include <sys/param.h> 37#include <sys/conf.h> 38#include <sys/consio.h> 39#include <sys/fcntl.h> 40#include <sys/kbio.h> 41#include <sys/kernel.h> 42#include <sys/limits.h> 43#include <sys/lock.h> 44#include <sys/malloc.h> 45#include <sys/module.h> 46#include <sys/mutex.h> 47#include <sys/poll.h> 48#include <sys/proc.h> 49#include <sys/queue.h> 50#include <sys/selinfo.h> 51#include <sys/systm.h> 52#include <sys/taskqueue.h> 53#include <sys/tty.h> 54#include <sys/uio.h> 55#include <dev/kbd/kbdreg.h> 56#include <dev/kbd/kbdtables.h> 57 58#define KEYBOARD_NAME "kbdmux" 59 60MALLOC_DECLARE(M_KBDMUX); 61MALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor"); 62 63/***************************************************************************** 64 ***************************************************************************** 65 ** Keyboard state 66 ***************************************************************************** 67 *****************************************************************************/ 68 69#define KBDMUX_Q_SIZE 512 /* input queue size */ 70 71/* 72 * XXX 73 * For now rely on Giant mutex to protect our data structures. 74 * Just like the rest of keyboard drivers and syscons(4) do. 75 * Note that callout is initialized as not MP-safe to make sure 76 * Giant is held. 77 */ 78 79#if 0 /* not yet */ 80#define KBDMUX_LOCK_DECL_GLOBAL \ 81 struct mtx ks_lock 82#define KBDMUX_LOCK_INIT(s) \ 83 mtx_init(&(s)->ks_lock, "kbdmux", NULL, MTX_DEF|MTX_RECURSE) 84#define KBDMUX_LOCK_DESTROY(s) \ 85 mtx_destroy(&(s)->ks_lock) 86#define KBDMUX_LOCK(s) \ 87 mtx_lock(&(s)->ks_lock) 88#define KBDMUX_UNLOCK(s) \ 89 mtx_unlock(&(s)->ks_lock) 90#define KBDMUX_LOCK_ASSERT(s, w) \ 91 mtx_assert(&(s)->ks_lock, (w)) 92#define KBDMUX_SLEEP(s, f, d, t) \ 93 msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), (d), (t)) 94#define KBDMUX_CALLOUT_INIT(s) \ 95 callout_init_mtx(&(s)->ks_timo, &(s)->ks_lock, 0) 96#define KBDMUX_QUEUE_INTR(s) \ 97 taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task) 98#else 99#define KBDMUX_LOCK_DECL_GLOBAL 100 101#define KBDMUX_LOCK_INIT(s) 102 103#define KBDMUX_LOCK_DESTROY(s) 104 105#define KBDMUX_LOCK(s) 106 107#define KBDMUX_UNLOCK(s) 108 109#define KBDMUX_LOCK_ASSERT(s, w) 110 111#define KBDMUX_SLEEP(s, f, d, t) \ 112 tsleep(&(s)->f, PCATCH | (PZERO + 1), (d), (t)) 113#define KBDMUX_CALLOUT_INIT(s) \ 114 callout_init(&(s)->ks_timo, 0) 115#define KBDMUX_QUEUE_INTR(s) \ 116 taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task) 117#endif /* not yet */ 118 119#define KBDMUX_INTR(kbd, arg) \ 120 (*kbdsw[(kbd)->kb_index]->intr)((kbd), (arg)) 121 122#define KBDMUX_IOCTL(kbd, cmd, arg) \ 123 (*kbdsw[(kbd)->kb_index]->ioctl)((kbd), (cmd), (caddr_t) (arg)) 124 125#define KBDMUX_CHECK_CHAR(kbd) \ 126 (*kbdsw[(kbd)->kb_index]->check_char)((kbd)) 127 128#define KBDMUX_READ_CHAR(kbd, wait) \ 129 (*kbdsw[(kbd)->kb_index]->read_char)((kbd), (wait)) 130 131#define KBDMUX_ENABLE(kbd) \ 132 (*kbdsw[(kbd)->kb_index]->enable)((kbd)) 133 134#define KBDMUX_POLL(kbd, on) \ 135 (*kbdsw[(kbd)->kb_index]->poll)((kbd), (on)) 136 137#define KBDMUX_CLEAR_STATE(kbd) \ 138 (*kbdsw[(kbd)->kb_index]->clear_state)((kbd)) 139 140/* 141 * kbdmux keyboard 142 */ 143struct kbdmux_kbd 144{ 145 keyboard_t *kbd; /* keyboard */ 146 SLIST_ENTRY(kbdmux_kbd) next; /* link to next */ 147}; 148 149typedef struct kbdmux_kbd kbdmux_kbd_t; 150 151/* 152 * kbdmux state 153 */ 154struct kbdmux_state 155{ 156 struct clist ks_inq; /* input chars queue */ 157 struct task ks_task; /* interrupt task */ 158 struct callout ks_timo; /* timeout handler */ 159#define TICKS (hz) /* rate */ 160 161 int ks_flags; /* flags */ 162#define COMPOSE (1 << 0) /* compose char flag */ 163#define POLLING (1 << 1) /* polling */ 164#define TASK (1 << 2) /* interrupt task queued */ 165 166 int ks_mode; /* K_XLATE, K_RAW, K_CODE */ 167 int ks_state; /* state */ 168 int ks_accents; /* accent key index (> 0) */ 169 u_int ks_composed_char; /* composed char code */ 170 u_char ks_prefix; /* AT scan code prefix */ 171 172 SLIST_HEAD(, kbdmux_kbd) ks_kbds; /* keyboards */ 173 174 KBDMUX_LOCK_DECL_GLOBAL; 175}; 176 177typedef struct kbdmux_state kbdmux_state_t; 178 179/***************************************************************************** 180 ***************************************************************************** 181 ** Helper functions 182 ***************************************************************************** 183 *****************************************************************************/ 184 185static task_fn_t kbdmux_kbd_intr; 186static timeout_t kbdmux_kbd_intr_timo; 187static kbd_callback_func_t kbdmux_kbd_event; 188 189/* 190 * Interrupt handler task 191 */ 192void 193kbdmux_kbd_intr(void *xkbd, int pending) 194{ 195 keyboard_t *kbd = (keyboard_t *) xkbd; 196 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 197 198 KBDMUX_INTR(kbd, NULL); 199 200 KBDMUX_LOCK(state); 201 202 state->ks_flags &= ~TASK; 203 wakeup(&state->ks_task); 204 205 KBDMUX_UNLOCK(state); 206} 207 208/* 209 * Schedule interrupt handler on timeout. Called with locked state. 210 */ 211void 212kbdmux_kbd_intr_timo(void *xstate) 213{ 214 kbdmux_state_t *state = (kbdmux_state_t *) xstate; 215 216 KBDMUX_LOCK_ASSERT(state, MA_OWNED); 217 218 if (callout_pending(&state->ks_timo)) 219 return; /* callout was reset */ 220 221 if (!callout_active(&state->ks_timo)) 222 return; /* callout was stopped */ 223 224 callout_deactivate(&state->ks_timo); 225 226 /* queue interrupt task if needed */ 227 if (state->ks_inq.c_cc > 0 && !(state->ks_flags & TASK) && 228 KBDMUX_QUEUE_INTR(state) == 0) 229 state->ks_flags |= TASK; 230 231 /* re-schedule timeout */ 232 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state); 233} 234 235/* 236 * Process event from one of our keyboards 237 */ 238static int 239kbdmux_kbd_event(keyboard_t *kbd, int event, void *arg) 240{ 241 kbdmux_state_t *state = (kbdmux_state_t *) arg; 242 243 switch (event) { 244 case KBDIO_KEYINPUT: { 245 int c; 246 247 KBDMUX_LOCK(state); 248 249 /* 250 * Read all chars from the keyboard 251 * 252 * Turns out that atkbd(4) check_char() method may return 253 * "true" while read_char() method returns NOKEY. If this 254 * happens we could stuck in the loop below. Avoid this 255 * by breaking out of the loop if read_char() method returns 256 * NOKEY. 257 */ 258 259 while (KBDMUX_CHECK_CHAR(kbd)) { 260 c = KBDMUX_READ_CHAR(kbd, 0); 261 if (c == NOKEY) 262 break; 263 if (c == ERRKEY) 264 continue; /* XXX ring bell */ 265 if (!KBD_IS_BUSY(kbd)) 266 continue; /* not open - discard the input */ 267 268 putc(c, &state->ks_inq); 269 } 270 271 /* queue interrupt task if needed */ 272 if (state->ks_inq.c_cc > 0 && !(state->ks_flags & TASK) && 273 KBDMUX_QUEUE_INTR(state) == 0) 274 state->ks_flags |= TASK; 275 276 KBDMUX_UNLOCK(state); 277 } break; 278 279 case KBDIO_UNLOADING: { 280 kbdmux_kbd_t *k; 281 282 KBDMUX_LOCK(state); 283 284 SLIST_FOREACH(k, &state->ks_kbds, next) 285 if (k->kbd == kbd) 286 break; 287 288 if (k != NULL) { 289 kbd_release(k->kbd, &k->kbd); 290 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next); 291 292 k->kbd = NULL; 293 294 free(k, M_KBDMUX); 295 } 296 297 KBDMUX_UNLOCK(state); 298 } break; 299 300 default: 301 return (EINVAL); 302 /* NOT REACHED */ 303 } 304 305 return (0); 306} 307 308/**************************************************************************** 309 **************************************************************************** 310 ** Keyboard driver 311 **************************************************************************** 312 ****************************************************************************/ 313 314static int kbdmux_configure(int flags); 315static kbd_probe_t kbdmux_probe; 316static kbd_init_t kbdmux_init; 317static kbd_term_t kbdmux_term; 318static kbd_intr_t kbdmux_intr; 319static kbd_test_if_t kbdmux_test_if; 320static kbd_enable_t kbdmux_enable; 321static kbd_disable_t kbdmux_disable; 322static kbd_read_t kbdmux_read; 323static kbd_check_t kbdmux_check; 324static kbd_read_char_t kbdmux_read_char; 325static kbd_check_char_t kbdmux_check_char; 326static kbd_ioctl_t kbdmux_ioctl; 327static kbd_lock_t kbdmux_lock; 328static void kbdmux_clear_state_locked(kbdmux_state_t *state); 329static kbd_clear_state_t kbdmux_clear_state; 330static kbd_get_state_t kbdmux_get_state; 331static kbd_set_state_t kbdmux_set_state; 332static kbd_poll_mode_t kbdmux_poll; 333 334static keyboard_switch_t kbdmuxsw = { 335 .probe = kbdmux_probe, 336 .init = kbdmux_init, 337 .term = kbdmux_term, 338 .intr = kbdmux_intr, 339 .test_if = kbdmux_test_if, 340 .enable = kbdmux_enable, 341 .disable = kbdmux_disable, 342 .read = kbdmux_read, 343 .check = kbdmux_check, 344 .read_char = kbdmux_read_char, 345 .check_char = kbdmux_check_char, 346 .ioctl = kbdmux_ioctl, 347 .lock = kbdmux_lock, 348 .clear_state = kbdmux_clear_state, 349 .get_state = kbdmux_get_state, 350 .set_state = kbdmux_set_state, 351 .get_fkeystr = genkbd_get_fkeystr, 352 .poll = kbdmux_poll, 353 .diag = genkbd_diag, 354}; 355 356/* 357 * Return the number of found keyboards 358 */ 359static int 360kbdmux_configure(int flags) 361{ 362 return (1); 363} 364 365/* 366 * Detect a keyboard 367 */ 368static int 369kbdmux_probe(int unit, void *arg, int flags) 370{ 371 return (0); 372} 373 374/* 375 * Reset and initialize the keyboard (stolen from atkbd.c) 376 */ 377static int 378kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags) 379{ 380 keyboard_t *kbd = NULL; 381 kbdmux_state_t *state = NULL; 382 keymap_t *keymap = NULL; 383 accentmap_t *accmap = NULL; 384 fkeytab_t *fkeymap = NULL; 385 int error, needfree, fkeymap_size, delay[2]; 386 387 if (*kbdp == NULL) { 388 *kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO); 389 state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO); 390 keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT); 391 accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT); 392 fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT); 393 fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); 394 needfree = 1; 395 396 if ((kbd == NULL) || (state == NULL) || (keymap == NULL) || 397 (accmap == NULL) || (fkeymap == NULL)) { 398 error = ENOMEM; 399 goto bad; 400 } 401 402 KBDMUX_LOCK_INIT(state); 403 clist_alloc_cblocks(&state->ks_inq, 404 KBDMUX_Q_SIZE, KBDMUX_Q_SIZE / 2); 405 TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd); 406 KBDMUX_CALLOUT_INIT(state); 407 SLIST_INIT(&state->ks_kbds); 408 } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { 409 return (0); 410 } else { 411 kbd = *kbdp; 412 state = (kbdmux_state_t *) kbd->kb_data; 413 keymap = kbd->kb_keymap; 414 accmap = kbd->kb_accentmap; 415 fkeymap = kbd->kb_fkeytab; 416 fkeymap_size = kbd->kb_fkeytab_size; 417 needfree = 0; 418 } 419 420 if (!KBD_IS_PROBED(kbd)) { 421 /* XXX assume 101/102 keys keyboard */ 422 kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0); 423 bcopy(&key_map, keymap, sizeof(key_map)); 424 bcopy(&accent_map, accmap, sizeof(accent_map)); 425 bcopy(fkey_tab, fkeymap, 426 imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 427 kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 428 kbd->kb_data = (void *)state; 429 430 KBD_FOUND_DEVICE(kbd); 431 KBD_PROBE_DONE(kbd); 432 433 KBDMUX_LOCK(state); 434 kbdmux_clear_state_locked(state); 435 state->ks_mode = K_XLATE; 436 KBDMUX_UNLOCK(state); 437 } 438 439 if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 440 kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; 441 442 kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 443 444 delay[0] = kbd->kb_delay1; 445 delay[1] = kbd->kb_delay2; 446 kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); 447 448 KBD_INIT_DONE(kbd); 449 } 450 451 if (!KBD_IS_CONFIGURED(kbd)) { 452 if (kbd_register(kbd) < 0) { 453 error = ENXIO; 454 goto bad; 455 } 456 457 KBD_CONFIG_DONE(kbd); 458 459 KBDMUX_LOCK(state); 460 callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state); 461 KBDMUX_UNLOCK(state); 462 } 463 464 return (0); 465bad: 466 if (needfree) { 467 if (state != NULL) { 468 clist_free_cblocks(&state->ks_inq); 469 free(state, M_KBDMUX); 470 } 471 if (keymap != NULL) 472 free(keymap, M_KBDMUX); 473 if (accmap != NULL) 474 free(accmap, M_KBDMUX); 475 if (fkeymap != NULL) 476 free(fkeymap, M_KBDMUX); 477 if (kbd != NULL) { 478 free(kbd, M_KBDMUX); 479 *kbdp = NULL; /* insure ref doesn't leak to caller */ 480 } 481 } 482 483 return (error); 484} 485 486/* 487 * Finish using this keyboard 488 */ 489static int 490kbdmux_term(keyboard_t *kbd) 491{ 492 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 493 kbdmux_kbd_t *k; 494 495 KBDMUX_LOCK(state); 496 497 /* kill callout */ 498 callout_stop(&state->ks_timo); 499 500 /* wait for interrupt task */ 501 while (state->ks_flags & TASK) 502 KBDMUX_SLEEP(state, ks_task, "kbdmuxc", 0); 503 504 /* release all keyboards from the mux */ 505 while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) { 506 kbd_release(k->kbd, &k->kbd); 507 SLIST_REMOVE_HEAD(&state->ks_kbds, next); 508 509 k->kbd = NULL; 510 511 free(k, M_KBDMUX); 512 } 513 514 /* flush input queue */ 515 ndflush(&state->ks_inq, state->ks_inq.c_cc); 516 clist_free_cblocks(&state->ks_inq); 517 518 KBDMUX_UNLOCK(state); 519 520 kbd_unregister(kbd); 521 522 KBDMUX_LOCK_DESTROY(state); 523 bzero(state, sizeof(*state)); 524 free(state, M_KBDMUX); 525 526 free(kbd->kb_keymap, M_KBDMUX); 527 free(kbd->kb_accentmap, M_KBDMUX); 528 free(kbd->kb_fkeytab, M_KBDMUX); 529 free(kbd, M_KBDMUX); 530 531 return (0); 532} 533 534/* 535 * Keyboard interrupt routine 536 */ 537static int 538kbdmux_intr(keyboard_t *kbd, void *arg) 539{ 540 int c; 541 542 if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 543 /* let the callback function to process the input */ 544 (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 545 kbd->kb_callback.kc_arg); 546 } else { 547 /* read and discard the input; no one is waiting for input */ 548 do { 549 c = kbdmux_read_char(kbd, FALSE); 550 } while (c != NOKEY); 551 } 552 553 return (0); 554} 555 556/* 557 * Test the interface to the device 558 */ 559static int 560kbdmux_test_if(keyboard_t *kbd) 561{ 562 return (0); 563} 564 565/* 566 * Enable the access to the device; until this function is called, 567 * the client cannot read from the keyboard. 568 */ 569static int 570kbdmux_enable(keyboard_t *kbd) 571{ 572 KBD_ACTIVATE(kbd); 573 return (0); 574} 575 576/* 577 * Disallow the access to the device 578 */ 579static int 580kbdmux_disable(keyboard_t *kbd) 581{ 582 KBD_DEACTIVATE(kbd); 583 return (0); 584} 585 586/* 587 * Read one byte from the keyboard if it's allowed 588 */ 589static int 590kbdmux_read(keyboard_t *kbd, int wait) 591{ 592 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 593 int c; 594 595 KBDMUX_LOCK(state); 596 c = getc(&state->ks_inq); 597 KBDMUX_UNLOCK(state); 598 599 if (c != -1) 600 kbd->kb_count ++; 601 602 return (KBD_IS_ACTIVE(kbd)? c : -1); 603} 604 605/* 606 * Check if data is waiting 607 */ 608static int 609kbdmux_check(keyboard_t *kbd) 610{ 611 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 612 int ready; 613 614 if (!KBD_IS_ACTIVE(kbd)) 615 return (FALSE); 616 617 KBDMUX_LOCK(state); 618 ready = (state->ks_inq.c_cc > 0)? TRUE : FALSE; 619 KBDMUX_UNLOCK(state); 620 621 return (ready); 622} 623 624/* 625 * Read char from the keyboard (stolen from atkbd.c) 626 */ 627static u_int 628kbdmux_read_char(keyboard_t *kbd, int wait) 629{ 630 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 631 u_int action; 632 int scancode, keycode; 633 634 KBDMUX_LOCK(state); 635 636next_code: 637 638 /* do we have a composed char to return? */ 639 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 640 action = state->ks_composed_char; 641 state->ks_composed_char = 0; 642 if (action > UCHAR_MAX) { 643 KBDMUX_UNLOCK(state); 644 645 return (ERRKEY); 646 } 647 648 KBDMUX_UNLOCK(state); 649 650 return (action); 651 } 652 653 /* see if there is something in the keyboard queue */ 654 scancode = getc(&state->ks_inq); 655 if (scancode == -1) { 656 KBDMUX_UNLOCK(state); 657 return (NOKEY); 658 } 659 /* XXX FIXME: check for -1 if wait == 1! */ 660 661 kbd->kb_count ++; 662 663 /* return the byte as is for the K_RAW mode */ 664 if (state->ks_mode == K_RAW) { 665 KBDMUX_UNLOCK(state); 666 return (scancode); 667 } 668 669 /* translate the scan code into a keycode */ 670 keycode = scancode & 0x7F; 671 switch (state->ks_prefix) { 672 case 0x00: /* normal scancode */ 673 switch(scancode) { 674 case 0xB8: /* left alt (compose key) released */ 675 if (state->ks_flags & COMPOSE) { 676 state->ks_flags &= ~COMPOSE; 677 if (state->ks_composed_char > UCHAR_MAX) 678 state->ks_composed_char = 0; 679 } 680 break; 681 case 0x38: /* left alt (compose key) pressed */ 682 if (!(state->ks_flags & COMPOSE)) { 683 state->ks_flags |= COMPOSE; 684 state->ks_composed_char = 0; 685 } 686 break; 687 case 0xE0: 688 case 0xE1: 689 state->ks_prefix = scancode; 690 goto next_code; 691 } 692 break; 693 case 0xE0: /* 0xE0 prefix */ 694 state->ks_prefix = 0; 695 switch (keycode) { 696 case 0x1C: /* right enter key */ 697 keycode = 0x59; 698 break; 699 case 0x1D: /* right ctrl key */ 700 keycode = 0x5A; 701 break; 702 case 0x35: /* keypad divide key */ 703 keycode = 0x5B; 704 break; 705 case 0x37: /* print scrn key */ 706 keycode = 0x5C; 707 break; 708 case 0x38: /* right alt key (alt gr) */ 709 keycode = 0x5D; 710 break; 711 case 0x46: /* ctrl-pause/break on AT 101 (see below) */ 712 keycode = 0x68; 713 break; 714 case 0x47: /* grey home key */ 715 keycode = 0x5E; 716 break; 717 case 0x48: /* grey up arrow key */ 718 keycode = 0x5F; 719 break; 720 case 0x49: /* grey page up key */ 721 keycode = 0x60; 722 break; 723 case 0x4B: /* grey left arrow key */ 724 keycode = 0x61; 725 break; 726 case 0x4D: /* grey right arrow key */ 727 keycode = 0x62; 728 break; 729 case 0x4F: /* grey end key */ 730 keycode = 0x63; 731 break; 732 case 0x50: /* grey down arrow key */ 733 keycode = 0x64; 734 break; 735 case 0x51: /* grey page down key */ 736 keycode = 0x65; 737 break; 738 case 0x52: /* grey insert key */ 739 keycode = 0x66; 740 break; 741 case 0x53: /* grey delete key */ 742 keycode = 0x67; 743 break; 744 /* the following 3 are only used on the MS "Natural" keyboard */ 745 case 0x5b: /* left Window key */ 746 keycode = 0x69; 747 break; 748 case 0x5c: /* right Window key */ 749 keycode = 0x6a; 750 break; 751 case 0x5d: /* menu key */ 752 keycode = 0x6b; 753 break; 754 case 0x5e: /* power key */ 755 keycode = 0x6d; 756 break; 757 case 0x5f: /* sleep key */ 758 keycode = 0x6e; 759 break; 760 case 0x63: /* wake key */ 761 keycode = 0x6f; 762 break; 763 default: /* ignore everything else */ 764 goto next_code; 765 } 766 break; 767 case 0xE1: /* 0xE1 prefix */ 768 /* 769 * The pause/break key on the 101 keyboard produces: 770 * E1-1D-45 E1-9D-C5 771 * Ctrl-pause/break produces: 772 * E0-46 E0-C6 (See above.) 773 */ 774 state->ks_prefix = 0; 775 if (keycode == 0x1D) 776 state->ks_prefix = 0x1D; 777 goto next_code; 778 /* NOT REACHED */ 779 case 0x1D: /* pause / break */ 780 state->ks_prefix = 0; 781 if (keycode != 0x45) 782 goto next_code; 783 keycode = 0x68; 784 break; 785 } 786 787 /* XXX assume 101/102 keys AT keyboard */ 788 switch (keycode) { 789 case 0x5c: /* print screen */ 790 if (state->ks_flags & ALTS) 791 keycode = 0x54; /* sysrq */ 792 break; 793 case 0x68: /* pause/break */ 794 if (state->ks_flags & CTLS) 795 keycode = 0x6c; /* break */ 796 break; 797 } 798 799 /* return the key code in the K_CODE mode */ 800 if (state->ks_mode == K_CODE) { 801 KBDMUX_UNLOCK(state); 802 return (keycode | (scancode & 0x80)); 803 } 804 805 /* compose a character code */ 806 if (state->ks_flags & COMPOSE) { 807 switch (keycode | (scancode & 0x80)) { 808 /* key pressed, process it */ 809 case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 810 state->ks_composed_char *= 10; 811 state->ks_composed_char += keycode - 0x40; 812 if (state->ks_composed_char > UCHAR_MAX) { 813 KBDMUX_UNLOCK(state); 814 return (ERRKEY); 815 } 816 goto next_code; 817 case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 818 state->ks_composed_char *= 10; 819 state->ks_composed_char += keycode - 0x47; 820 if (state->ks_composed_char > UCHAR_MAX) { 821 KBDMUX_UNLOCK(state); 822 return (ERRKEY); 823 } 824 goto next_code; 825 case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 826 state->ks_composed_char *= 10; 827 state->ks_composed_char += keycode - 0x4E; 828 if (state->ks_composed_char > UCHAR_MAX) { 829 KBDMUX_UNLOCK(state); 830 return (ERRKEY); 831 } 832 goto next_code; 833 case 0x52: /* keypad 0 */ 834 state->ks_composed_char *= 10; 835 if (state->ks_composed_char > UCHAR_MAX) { 836 KBDMUX_UNLOCK(state); 837 return (ERRKEY); 838 } 839 goto next_code; 840 841 /* key released, no interest here */ 842 case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 843 case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 844 case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 845 case 0xD2: /* keypad 0 */ 846 goto next_code; 847 848 case 0x38: /* left alt key */ 849 break; 850 851 default: 852 if (state->ks_composed_char > 0) { 853 state->ks_flags &= ~COMPOSE; 854 state->ks_composed_char = 0; 855 KBDMUX_UNLOCK(state); 856 return (ERRKEY); 857 } 858 break; 859 } 860 } 861 862 /* keycode to key action */ 863 action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 864 &state->ks_state, &state->ks_accents); 865 if (action == NOKEY) 866 goto next_code; 867 868 KBDMUX_UNLOCK(state); 869 870 return (action); 871} 872 873/* 874 * Check if char is waiting 875 */ 876static int 877kbdmux_check_char(keyboard_t *kbd) 878{ 879 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 880 int ready; 881 882 if (!KBD_IS_ACTIVE(kbd)) 883 return (FALSE); 884 885 KBDMUX_LOCK(state); 886 887 if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0)) 888 ready = TRUE; 889 else 890 ready = (state->ks_inq.c_cc > 0)? TRUE : FALSE; 891 892 KBDMUX_UNLOCK(state); 893 894 return (ready); 895} 896 897/* 898 * Keyboard ioctl's 899 */ 900static int 901kbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 902{ 903 static int delays[] = { 904 250, 500, 750, 1000 905 }; 906 907 static int rates[] = { 908 34, 38, 42, 46, 50, 55, 59, 63, 909 68, 76, 84, 92, 100, 110, 118, 126, 910 136, 152, 168, 184, 200, 220, 236, 252, 911 272, 304, 336, 368, 400, 440, 472, 504 912 }; 913 914 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 915 kbdmux_kbd_t *k; 916 keyboard_info_t *ki; 917 int error = 0, mode; 918 919 if (state == NULL) 920 return (ENXIO); 921 922 switch (cmd) { 923 case KBADDKBD: /* add keyboard to the mux */ 924 ki = (keyboard_info_t *) arg; 925 926 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' || 927 strcmp(ki->kb_name, "*") == 0) 928 return (EINVAL); /* bad input */ 929 930 KBDMUX_LOCK(state); 931 932 SLIST_FOREACH(k, &state->ks_kbds, next) 933 if (k->kbd->kb_unit == ki->kb_unit && 934 strcmp(k->kbd->kb_name, ki->kb_name) == 0) 935 break; 936 937 if (k != NULL) { 938 KBDMUX_UNLOCK(state); 939 940 return (0); /* keyboard already in the mux */ 941 } 942 943 k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO); 944 if (k == NULL) { 945 KBDMUX_UNLOCK(state); 946 947 return (ENOMEM); /* out of memory */ 948 } 949 950 k->kbd = kbd_get_keyboard( 951 kbd_allocate( 952 ki->kb_name, 953 ki->kb_unit, 954 (void *) &k->kbd, 955 kbdmux_kbd_event, (void *) state)); 956 if (k->kbd == NULL) { 957 KBDMUX_UNLOCK(state); 958 free(k, M_KBDMUX); 959 960 return (EINVAL); /* bad keyboard */ 961 } 962 963 KBDMUX_ENABLE(k->kbd); 964 KBDMUX_CLEAR_STATE(k->kbd); 965 966 /* set K_RAW mode on slave keyboard */ 967 mode = K_RAW; 968 error = KBDMUX_IOCTL(k->kbd, KDSKBMODE, &mode); 969 if (error == 0) { 970 /* set lock keys state on slave keyboard */ 971 mode = state->ks_state & LOCK_MASK; 972 error = KBDMUX_IOCTL(k->kbd, KDSKBSTATE, &mode); 973 } 974 975 if (error != 0) { 976 KBDMUX_UNLOCK(state); 977 978 kbd_release(k->kbd, &k->kbd); 979 k->kbd = NULL; 980 981 free(k, M_KBDMUX); 982 983 return (error); /* could not set mode */ 984 } 985 986 SLIST_INSERT_HEAD(&state->ks_kbds, k, next); 987 988 KBDMUX_UNLOCK(state); 989 break; 990 991 case KBRELKBD: /* release keyboard from the mux */ 992 ki = (keyboard_info_t *) arg; 993 994 if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' || 995 strcmp(ki->kb_name, "*") == 0) 996 return (EINVAL); /* bad input */ 997 998 KBDMUX_LOCK(state); 999 1000 SLIST_FOREACH(k, &state->ks_kbds, next) 1001 if (k->kbd->kb_unit == ki->kb_unit && 1002 strcmp(k->kbd->kb_name, ki->kb_name) == 0) 1003 break; 1004 1005 if (k != NULL) { 1006 error = kbd_release(k->kbd, &k->kbd); 1007 if (error == 0) { 1008 SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next); 1009 1010 k->kbd = NULL; 1011 1012 free(k, M_KBDMUX); 1013 } 1014 } else 1015 error = ENXIO; /* keyboard is not in the mux */ 1016 1017 KBDMUX_UNLOCK(state); 1018 break; 1019 1020 case KDGKBMODE: /* get kyboard mode */ 1021 KBDMUX_LOCK(state); 1022 *((int *) arg) = state->ks_mode; 1023 KBDMUX_UNLOCK(state); 1024 break; 1025 1026 case KDSKBMODE: /* set keyboard mode */ 1027 KBDMUX_LOCK(state); 1028 1029 switch (*((int *) arg)) { 1030 case K_XLATE: 1031 if (state->ks_mode != K_XLATE) { 1032 /* make lock key state and LED state match */ 1033 state->ks_state &= ~LOCK_MASK; 1034 state->ks_state |= KBD_LED_VAL(kbd); 1035 } 1036 /* FALLTHROUGH */ 1037 1038 case K_RAW: 1039 case K_CODE: 1040 if (state->ks_mode != *((int *) arg)) { 1041 kbdmux_clear_state_locked(state); 1042 state->ks_mode = *((int *) arg); 1043 } 1044 break; 1045 1046 default: 1047 error = EINVAL; 1048 break; 1049 } 1050 1051 KBDMUX_UNLOCK(state); 1052 break; 1053 1054 case KDGETLED: /* get keyboard LED */ 1055 KBDMUX_LOCK(state); 1056 *((int *) arg) = KBD_LED_VAL(kbd); 1057 KBDMUX_UNLOCK(state); 1058 break; 1059 1060 case KDSETLED: /* set keyboard LED */ 1061 KBDMUX_LOCK(state); 1062 1063 /* NOTE: lock key state in ks_state won't be changed */ 1064 if (*((int *) arg) & ~LOCK_MASK) { 1065 KBDMUX_UNLOCK(state); 1066 1067 return (EINVAL); 1068 } 1069 1070 KBD_LED_VAL(kbd) = *((int *) arg); 1071 1072 /* KDSETLED on all slave keyboards */ 1073 SLIST_FOREACH(k, &state->ks_kbds, next) 1074 KBDMUX_IOCTL(k->kbd, KDSETLED, arg); 1075 1076 KBDMUX_UNLOCK(state); 1077 break; 1078 1079 case KDGKBSTATE: /* get lock key state */ 1080 KBDMUX_LOCK(state); 1081 *((int *) arg) = state->ks_state & LOCK_MASK; 1082 KBDMUX_UNLOCK(state); 1083 break; 1084 1085 case KDSKBSTATE: /* set lock key state */ 1086 KBDMUX_LOCK(state); 1087 1088 if (*((int *) arg) & ~LOCK_MASK) { 1089 KBDMUX_UNLOCK(state); 1090 1091 return (EINVAL); 1092 } 1093 1094 state->ks_state &= ~LOCK_MASK; 1095 state->ks_state |= *((int *) arg); 1096 1097 /* KDSKBSTATE on all slave keyboards */ 1098 SLIST_FOREACH(k, &state->ks_kbds, next) 1099 KBDMUX_IOCTL(k->kbd, KDSKBSTATE, arg); 1100 1101 KBDMUX_UNLOCK(state); 1102 1103 return (kbdmux_ioctl(kbd, KDSETLED, arg)); 1104 /* NOT REACHED */ 1105 1106 case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 1107 case KDSETRAD: /* set keyboard repeat rate (old interface) */ 1108 KBDMUX_LOCK(state); 1109 1110 if (cmd == KDSETREPEAT) { 1111 int i; 1112 1113 /* lookup delay */ 1114 for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --) 1115 if (((int *) arg)[0] >= delays[i]) 1116 break; 1117 mode = i << 5; 1118 1119 /* lookup rate */ 1120 for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --) 1121 if (((int *) arg)[1] >= rates[i]) 1122 break; 1123 mode |= i; 1124 } else 1125 mode = *((int *) arg); 1126 1127 if (mode & ~0x7f) { 1128 KBDMUX_UNLOCK(state); 1129 1130 return (EINVAL); 1131 } 1132 1133 kbd->kb_delay1 = delays[(mode >> 5) & 3]; 1134 kbd->kb_delay2 = rates[mode & 0x1f]; 1135 1136 /* perform command on all slave keyboards */ 1137 SLIST_FOREACH(k, &state->ks_kbds, next) 1138 KBDMUX_IOCTL(k->kbd, cmd, arg); 1139 1140 KBDMUX_UNLOCK(state); 1141 break; 1142 1143 case PIO_KEYMAP: /* set keyboard translation table */ 1144 case PIO_KEYMAPENT: /* set keyboard translation table entry */ 1145 case PIO_DEADKEYMAP: /* set accent key translation table */ 1146 KBDMUX_LOCK(state); 1147 state->ks_accents = 0; 1148 1149 /* perform command on all slave keyboards */ 1150 SLIST_FOREACH(k, &state->ks_kbds, next) 1151 KBDMUX_IOCTL(k->kbd, cmd, arg); 1152 1153 KBDMUX_UNLOCK(state); 1154 /* FALLTHROUGH */ 1155 1156 default: 1157 error = genkbd_commonioctl(kbd, cmd, arg); 1158 break; 1159 } 1160 1161 return (error); 1162} 1163 1164/* 1165 * Lock the access to the keyboard 1166 */ 1167static int 1168kbdmux_lock(keyboard_t *kbd, int lock) 1169{ 1170 return (1); /* XXX */ 1171} 1172 1173/* 1174 * Clear the internal state of the keyboard 1175 */ 1176static void 1177kbdmux_clear_state_locked(kbdmux_state_t *state) 1178{ 1179 KBDMUX_LOCK_ASSERT(state, MA_OWNED); 1180 1181 state->ks_flags &= ~(COMPOSE|POLLING); 1182 state->ks_state &= LOCK_MASK; /* preserve locking key state */ 1183 state->ks_accents = 0; 1184 state->ks_composed_char = 0; 1185/* state->ks_prefix = 0; XXX */ 1186 1187 ndflush(&state->ks_inq, state->ks_inq.c_cc); 1188} 1189 1190static void 1191kbdmux_clear_state(keyboard_t *kbd) 1192{ 1193 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 1194 1195 KBDMUX_LOCK(state); 1196 kbdmux_clear_state_locked(state); 1197 KBDMUX_UNLOCK(state); 1198} 1199 1200/* 1201 * Save the internal state 1202 */ 1203static int 1204kbdmux_get_state(keyboard_t *kbd, void *buf, size_t len) 1205{ 1206 if (len == 0) 1207 return (sizeof(kbdmux_state_t)); 1208 if (len < sizeof(kbdmux_state_t)) 1209 return (-1); 1210 1211 bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */ 1212 1213 return (0); 1214} 1215 1216/* 1217 * Set the internal state 1218 */ 1219static int 1220kbdmux_set_state(keyboard_t *kbd, void *buf, size_t len) 1221{ 1222 if (len < sizeof(kbdmux_state_t)) 1223 return (ENOMEM); 1224 1225 bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */ 1226 1227 return (0); 1228} 1229 1230/* 1231 * Set polling 1232 */ 1233static int 1234kbdmux_poll(keyboard_t *kbd, int on) 1235{ 1236 kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 1237 kbdmux_kbd_t *k; 1238 1239 KBDMUX_LOCK(state); 1240 1241 if (on) 1242 state->ks_flags |= POLLING; 1243 else 1244 state->ks_flags &= ~POLLING; 1245 1246 /* set poll on slave keyboards */ 1247 SLIST_FOREACH(k, &state->ks_kbds, next) 1248 KBDMUX_POLL(k->kbd, on); 1249 1250 KBDMUX_UNLOCK(state); 1251 1252 return (0); 1253} 1254 1255/***************************************************************************** 1256 ***************************************************************************** 1257 ** Module 1258 ***************************************************************************** 1259 *****************************************************************************/ 1260 1261KEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure); 1262 1263static int 1264kbdmux_modevent(module_t mod, int type, void *data) 1265{ 1266 keyboard_switch_t *sw; 1267 keyboard_t *kbd; 1268 int error; 1269 1270 switch (type) { 1271 case MOD_LOAD: 1272 if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0) 1273 break; 1274 1275 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) { 1276 kbd_delete_driver(&kbdmux_kbd_driver); 1277 error = ENXIO; 1278 break; 1279 } 1280 1281 kbd = NULL; 1282 1283 if ((error = (*sw->probe)(0, NULL, 0)) != 0 || 1284 (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) { 1285 kbd_delete_driver(&kbdmux_kbd_driver); 1286 break; 1287 } 1288 1289#ifdef KBD_INSTALL_CDEV 1290 if ((error = kbd_attach(kbd)) != 0) { 1291 (*sw->term)(kbd); 1292 kbd_delete_driver(&kbdmux_kbd_driver); 1293 break; 1294 } 1295#endif 1296 1297 if ((error = (*sw->enable)(kbd)) != 0) { 1298 (*sw->disable)(kbd); 1299#ifdef KBD_INSTALL_CDEV 1300 kbd_detach(kbd); 1301#endif 1302 (*sw->term)(kbd); 1303 kbd_delete_driver(&kbdmux_kbd_driver); 1304 break; 1305 } 1306 break; 1307 1308 case MOD_UNLOAD: 1309 if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) 1310 panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL"); 1311 1312 kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0)); 1313 if (kbd == NULL) 1314 panic("kbd_get_keyboard(kbd_find_keyboard(" KEYBOARD_NAME ", 0)) == NULL"); 1315 1316 (*sw->disable)(kbd); 1317#ifdef KBD_INSTALL_CDEV 1318 kbd_detach(kbd); 1319#endif 1320 (*sw->term)(kbd); 1321 kbd_delete_driver(&kbdmux_kbd_driver); 1322 error = 0; 1323 break; 1324 1325 default: 1326 error = EOPNOTSUPP; 1327 break; 1328 } 1329 1330 return (0); 1331} 1332 1333DEV_MODULE(kbdmux, kbdmux_modevent, NULL); 1334 1335