1147999Semax/* 2147999Semax * kbdmux.c 3147999Semax */ 4147999Semax 5147999Semax/*- 6147999Semax * Copyright (c) 2005 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7147999Semax * All rights reserved. 8147999Semax * 9147999Semax * Redistribution and use in source and binary forms, with or without 10147999Semax * modification, are permitted provided that the following conditions 11147999Semax * are met: 12147999Semax * 1. Redistributions of source code must retain the above copyright 13147999Semax * notice, this list of conditions and the following disclaimer. 14147999Semax * 2. Redistributions in binary form must reproduce the above copyright 15147999Semax * notice, this list of conditions and the following disclaimer in the 16147999Semax * documentation and/or other materials provided with the distribution. 17147999Semax * 18147999Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19147999Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20147999Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21147999Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22147999Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23147999Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24147999Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25147999Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26147999Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27147999Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28147999Semax * SUCH DAMAGE. 29147999Semax * 30147999Semax * $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $ 31147999Semax * $FreeBSD: releng/10.3/sys/dev/kbdmux/kbdmux.c 241885 2012-10-22 13:06:09Z eadler $ 32147999Semax */ 33147999Semax 34162711Sru#include "opt_compat.h" 35147999Semax#include "opt_kbd.h" 36147999Semax 37147999Semax#include <sys/param.h> 38156167Semax#include <sys/bus.h> 39147999Semax#include <sys/conf.h> 40147999Semax#include <sys/consio.h> 41147999Semax#include <sys/fcntl.h> 42147999Semax#include <sys/kbio.h> 43147999Semax#include <sys/kernel.h> 44147999Semax#include <sys/limits.h> 45147999Semax#include <sys/lock.h> 46147999Semax#include <sys/malloc.h> 47147999Semax#include <sys/module.h> 48147999Semax#include <sys/mutex.h> 49147999Semax#include <sys/poll.h> 50147999Semax#include <sys/proc.h> 51147999Semax#include <sys/queue.h> 52147999Semax#include <sys/selinfo.h> 53147999Semax#include <sys/systm.h> 54147999Semax#include <sys/taskqueue.h> 55147999Semax#include <sys/uio.h> 56147999Semax#include <dev/kbd/kbdreg.h> 57147999Semax#include <dev/kbd/kbdtables.h> 58147999Semax 59147999Semax#define KEYBOARD_NAME "kbdmux" 60147999Semax 61147999SemaxMALLOC_DECLARE(M_KBDMUX); 62147999SemaxMALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor"); 63147999Semax 64147999Semax/***************************************************************************** 65147999Semax ***************************************************************************** 66147999Semax ** Keyboard state 67147999Semax ***************************************************************************** 68147999Semax *****************************************************************************/ 69147999Semax 70147999Semax#define KBDMUX_Q_SIZE 512 /* input queue size */ 71147999Semax 72147999Semax/* 73147999Semax * XXX 74147999Semax * For now rely on Giant mutex to protect our data structures. 75147999Semax * Just like the rest of keyboard drivers and syscons(4) do. 76147999Semax * Note that callout is initialized as not MP-safe to make sure 77147999Semax * Giant is held. 78147999Semax */ 79147999Semax 80147999Semax#if 0 /* not yet */ 81147999Semax#define KBDMUX_LOCK_DECL_GLOBAL \ 82147999Semax struct mtx ks_lock 83147999Semax#define KBDMUX_LOCK_INIT(s) \ 84147999Semax mtx_init(&(s)->ks_lock, "kbdmux", NULL, MTX_DEF|MTX_RECURSE) 85147999Semax#define KBDMUX_LOCK_DESTROY(s) \ 86147999Semax mtx_destroy(&(s)->ks_lock) 87147999Semax#define KBDMUX_LOCK(s) \ 88147999Semax mtx_lock(&(s)->ks_lock) 89147999Semax#define KBDMUX_UNLOCK(s) \ 90147999Semax mtx_unlock(&(s)->ks_lock) 91147999Semax#define KBDMUX_LOCK_ASSERT(s, w) \ 92147999Semax mtx_assert(&(s)->ks_lock, (w)) 93147999Semax#define KBDMUX_SLEEP(s, f, d, t) \ 94147999Semax msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), (d), (t)) 95147999Semax#define KBDMUX_CALLOUT_INIT(s) \ 96147999Semax callout_init_mtx(&(s)->ks_timo, &(s)->ks_lock, 0) 97147999Semax#define KBDMUX_QUEUE_INTR(s) \ 98147999Semax taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task) 99147999Semax#else 100147999Semax#define KBDMUX_LOCK_DECL_GLOBAL 101147999Semax 102147999Semax#define KBDMUX_LOCK_INIT(s) 103147999Semax 104147999Semax#define KBDMUX_LOCK_DESTROY(s) 105147999Semax 106190857Semax#define KBDMUX_LOCK(s) 107190857Semax 108190857Semax#define KBDMUX_UNLOCK(s) 109190857Semax 110147999Semax#define KBDMUX_LOCK_ASSERT(s, w) 111147999Semax 112147999Semax#define KBDMUX_SLEEP(s, f, d, t) \ 113147999Semax tsleep(&(s)->f, PCATCH | (PZERO + 1), (d), (t)) 114147999Semax#define KBDMUX_CALLOUT_INIT(s) \ 115147999Semax callout_init(&(s)->ks_timo, 0) 116147999Semax#define KBDMUX_QUEUE_INTR(s) \ 117147999Semax taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task) 118147999Semax#endif /* not yet */ 119147999Semax 120147999Semax/* 121147999Semax * kbdmux keyboard 122147999Semax */ 123147999Semaxstruct kbdmux_kbd 124147999Semax{ 125147999Semax keyboard_t *kbd; /* keyboard */ 126147999Semax SLIST_ENTRY(kbdmux_kbd) next; /* link to next */ 127147999Semax}; 128147999Semax 129147999Semaxtypedef struct kbdmux_kbd kbdmux_kbd_t; 130147999Semax 131147999Semax/* 132147999Semax * kbdmux state 133147999Semax */ 134147999Semaxstruct kbdmux_state 135147999Semax{ 136193512Sed char ks_inq[KBDMUX_Q_SIZE]; /* input chars queue */ 137193512Sed unsigned int ks_inq_start; 138193512Sed unsigned int ks_inq_length; 139147999Semax struct task ks_task; /* interrupt task */ 140147999Semax struct callout ks_timo; /* timeout handler */ 141147999Semax#define TICKS (hz) /* rate */ 142147999Semax 143147999Semax int ks_flags; /* flags */ 144147999Semax#define COMPOSE (1 << 0) /* compose char flag */ 145147999Semax#define POLLING (1 << 1) /* polling */ 146147999Semax#define TASK (1 << 2) /* interrupt task queued */ 147147999Semax 148147999Semax int ks_mode; /* K_XLATE, K_RAW, K_CODE */ 149147999Semax int ks_state; /* state */ 150147999Semax int ks_accents; /* accent key index (> 0) */ 151147999Semax u_int ks_composed_char; /* composed char code */ 152147999Semax u_char ks_prefix; /* AT scan code prefix */ 153147999Semax 154147999Semax SLIST_HEAD(, kbdmux_kbd) ks_kbds; /* keyboards */ 155147999Semax 156147999Semax KBDMUX_LOCK_DECL_GLOBAL; 157147999Semax}; 158147999Semax 159147999Semaxtypedef struct kbdmux_state kbdmux_state_t; 160147999Semax 161147999Semax/***************************************************************************** 162147999Semax ***************************************************************************** 163147999Semax ** Helper functions 164147999Semax ***************************************************************************** 165147999Semax *****************************************************************************/ 166147999Semax 167147999Semaxstatic task_fn_t kbdmux_kbd_intr; 168147999Semaxstatic timeout_t kbdmux_kbd_intr_timo; 169147999Semaxstatic kbd_callback_func_t kbdmux_kbd_event; 170147999Semax 171193512Sedstatic void 172193512Sedkbdmux_kbd_putc(kbdmux_state_t *state, char c) 173193512Sed{ 174193512Sed unsigned int p; 175193512Sed 176193512Sed if (state->ks_inq_length == KBDMUX_Q_SIZE) 177193512Sed return; 178193512Sed 179193512Sed p = (state->ks_inq_start + state->ks_inq_length) % KBDMUX_Q_SIZE; 180193512Sed state->ks_inq[p] = c; 181193512Sed state->ks_inq_length++; 182193512Sed} 183193512Sed 184193752Sedstatic int 185193512Sedkbdmux_kbd_getc(kbdmux_state_t *state) 186193512Sed{ 187193752Sed unsigned char c; 188193512Sed 189193512Sed if (state->ks_inq_length == 0) 190193512Sed return (-1); 191193512Sed 192193512Sed c = state->ks_inq[state->ks_inq_start]; 193193512Sed state->ks_inq_start = (state->ks_inq_start + 1) % KBDMUX_Q_SIZE; 194193512Sed state->ks_inq_length--; 195193512Sed 196193512Sed return (c); 197193512Sed} 198193512Sed 199147999Semax/* 200147999Semax * Interrupt handler task 201147999Semax */ 202147999Semaxvoid 203147999Semaxkbdmux_kbd_intr(void *xkbd, int pending) 204147999Semax{ 205147999Semax keyboard_t *kbd = (keyboard_t *) xkbd; 206147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 207147999Semax 208174984Swkoszek kbdd_intr(kbd, NULL); 209147999Semax 210147999Semax KBDMUX_LOCK(state); 211147999Semax 212147999Semax state->ks_flags &= ~TASK; 213147999Semax wakeup(&state->ks_task); 214147999Semax 215147999Semax KBDMUX_UNLOCK(state); 216147999Semax} 217147999Semax 218147999Semax/* 219147999Semax * Schedule interrupt handler on timeout. Called with locked state. 220147999Semax */ 221147999Semaxvoid 222147999Semaxkbdmux_kbd_intr_timo(void *xstate) 223147999Semax{ 224147999Semax kbdmux_state_t *state = (kbdmux_state_t *) xstate; 225147999Semax 226147999Semax KBDMUX_LOCK_ASSERT(state, MA_OWNED); 227147999Semax 228147999Semax if (callout_pending(&state->ks_timo)) 229147999Semax return; /* callout was reset */ 230147999Semax 231147999Semax if (!callout_active(&state->ks_timo)) 232147999Semax return; /* callout was stopped */ 233147999Semax 234147999Semax callout_deactivate(&state->ks_timo); 235147999Semax 236147999Semax /* queue interrupt task if needed */ 237193512Sed if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) && 238147999Semax KBDMUX_QUEUE_INTR(state) == 0) 239147999Semax state->ks_flags |= TASK; 240147999Semax 241147999Semax /* re-schedule timeout */ 242147999Semax callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state); 243147999Semax} 244147999Semax 245147999Semax/* 246147999Semax * Process event from one of our keyboards 247147999Semax */ 248147999Semaxstatic int 249147999Semaxkbdmux_kbd_event(keyboard_t *kbd, int event, void *arg) 250147999Semax{ 251147999Semax kbdmux_state_t *state = (kbdmux_state_t *) arg; 252147999Semax 253147999Semax switch (event) { 254147999Semax case KBDIO_KEYINPUT: { 255147999Semax int c; 256147999Semax 257147999Semax KBDMUX_LOCK(state); 258147999Semax 259156013Semax /* 260156013Semax * Read all chars from the keyboard 261156013Semax * 262156013Semax * Turns out that atkbd(4) check_char() method may return 263156013Semax * "true" while read_char() method returns NOKEY. If this 264156013Semax * happens we could stuck in the loop below. Avoid this 265156013Semax * by breaking out of the loop if read_char() method returns 266156013Semax * NOKEY. 267156013Semax */ 268156013Semax 269174984Swkoszek while (kbdd_check_char(kbd)) { 270174984Swkoszek c = kbdd_read_char(kbd, 0); 271147999Semax if (c == NOKEY) 272156010Semax break; 273147999Semax if (c == ERRKEY) 274147999Semax continue; /* XXX ring bell */ 275147999Semax if (!KBD_IS_BUSY(kbd)) 276147999Semax continue; /* not open - discard the input */ 277147999Semax 278193512Sed kbdmux_kbd_putc(state, c); 279147999Semax } 280147999Semax 281147999Semax /* queue interrupt task if needed */ 282193512Sed if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) && 283147999Semax KBDMUX_QUEUE_INTR(state) == 0) 284147999Semax state->ks_flags |= TASK; 285147999Semax 286147999Semax KBDMUX_UNLOCK(state); 287147999Semax } break; 288147999Semax 289147999Semax case KBDIO_UNLOADING: { 290147999Semax kbdmux_kbd_t *k; 291147999Semax 292147999Semax KBDMUX_LOCK(state); 293147999Semax 294147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 295147999Semax if (k->kbd == kbd) 296147999Semax break; 297147999Semax 298147999Semax if (k != NULL) { 299147999Semax kbd_release(k->kbd, &k->kbd); 300147999Semax SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next); 301147999Semax 302147999Semax k->kbd = NULL; 303147999Semax 304147999Semax free(k, M_KBDMUX); 305147999Semax } 306147999Semax 307147999Semax KBDMUX_UNLOCK(state); 308147999Semax } break; 309147999Semax 310147999Semax default: 311147999Semax return (EINVAL); 312147999Semax /* NOT REACHED */ 313147999Semax } 314147999Semax 315147999Semax return (0); 316147999Semax} 317147999Semax 318147999Semax/**************************************************************************** 319147999Semax **************************************************************************** 320147999Semax ** Keyboard driver 321147999Semax **************************************************************************** 322147999Semax ****************************************************************************/ 323147999Semax 324147999Semaxstatic int kbdmux_configure(int flags); 325147999Semaxstatic kbd_probe_t kbdmux_probe; 326147999Semaxstatic kbd_init_t kbdmux_init; 327147999Semaxstatic kbd_term_t kbdmux_term; 328147999Semaxstatic kbd_intr_t kbdmux_intr; 329147999Semaxstatic kbd_test_if_t kbdmux_test_if; 330147999Semaxstatic kbd_enable_t kbdmux_enable; 331147999Semaxstatic kbd_disable_t kbdmux_disable; 332147999Semaxstatic kbd_read_t kbdmux_read; 333147999Semaxstatic kbd_check_t kbdmux_check; 334147999Semaxstatic kbd_read_char_t kbdmux_read_char; 335147999Semaxstatic kbd_check_char_t kbdmux_check_char; 336147999Semaxstatic kbd_ioctl_t kbdmux_ioctl; 337147999Semaxstatic kbd_lock_t kbdmux_lock; 338147999Semaxstatic void kbdmux_clear_state_locked(kbdmux_state_t *state); 339147999Semaxstatic kbd_clear_state_t kbdmux_clear_state; 340147999Semaxstatic kbd_get_state_t kbdmux_get_state; 341147999Semaxstatic kbd_set_state_t kbdmux_set_state; 342147999Semaxstatic kbd_poll_mode_t kbdmux_poll; 343147999Semax 344147999Semaxstatic keyboard_switch_t kbdmuxsw = { 345147999Semax .probe = kbdmux_probe, 346147999Semax .init = kbdmux_init, 347147999Semax .term = kbdmux_term, 348147999Semax .intr = kbdmux_intr, 349147999Semax .test_if = kbdmux_test_if, 350147999Semax .enable = kbdmux_enable, 351147999Semax .disable = kbdmux_disable, 352147999Semax .read = kbdmux_read, 353147999Semax .check = kbdmux_check, 354147999Semax .read_char = kbdmux_read_char, 355147999Semax .check_char = kbdmux_check_char, 356147999Semax .ioctl = kbdmux_ioctl, 357147999Semax .lock = kbdmux_lock, 358147999Semax .clear_state = kbdmux_clear_state, 359147999Semax .get_state = kbdmux_get_state, 360147999Semax .set_state = kbdmux_set_state, 361147999Semax .get_fkeystr = genkbd_get_fkeystr, 362147999Semax .poll = kbdmux_poll, 363147999Semax .diag = genkbd_diag, 364147999Semax}; 365147999Semax 366147999Semax/* 367147999Semax * Return the number of found keyboards 368147999Semax */ 369147999Semaxstatic int 370147999Semaxkbdmux_configure(int flags) 371147999Semax{ 372147999Semax return (1); 373147999Semax} 374147999Semax 375147999Semax/* 376147999Semax * Detect a keyboard 377147999Semax */ 378147999Semaxstatic int 379147999Semaxkbdmux_probe(int unit, void *arg, int flags) 380147999Semax{ 381241885Seadler if (resource_disabled(KEYBOARD_NAME, unit)) 382241885Seadler return (ENXIO); 383156167Semax 384147999Semax return (0); 385147999Semax} 386147999Semax 387147999Semax/* 388147999Semax * Reset and initialize the keyboard (stolen from atkbd.c) 389147999Semax */ 390147999Semaxstatic int 391147999Semaxkbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags) 392147999Semax{ 393147999Semax keyboard_t *kbd = NULL; 394147999Semax kbdmux_state_t *state = NULL; 395147999Semax keymap_t *keymap = NULL; 396147999Semax accentmap_t *accmap = NULL; 397147999Semax fkeytab_t *fkeymap = NULL; 398147999Semax int error, needfree, fkeymap_size, delay[2]; 399147999Semax 400147999Semax if (*kbdp == NULL) { 401147999Semax *kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO); 402147999Semax state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO); 403147999Semax keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT); 404147999Semax accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT); 405147999Semax fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT); 406147999Semax fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); 407147999Semax needfree = 1; 408147999Semax 409147999Semax if ((kbd == NULL) || (state == NULL) || (keymap == NULL) || 410147999Semax (accmap == NULL) || (fkeymap == NULL)) { 411147999Semax error = ENOMEM; 412147999Semax goto bad; 413147999Semax } 414147999Semax 415147999Semax KBDMUX_LOCK_INIT(state); 416147999Semax TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd); 417147999Semax KBDMUX_CALLOUT_INIT(state); 418147999Semax SLIST_INIT(&state->ks_kbds); 419147999Semax } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { 420147999Semax return (0); 421147999Semax } else { 422147999Semax kbd = *kbdp; 423147999Semax state = (kbdmux_state_t *) kbd->kb_data; 424147999Semax keymap = kbd->kb_keymap; 425147999Semax accmap = kbd->kb_accentmap; 426147999Semax fkeymap = kbd->kb_fkeytab; 427147999Semax fkeymap_size = kbd->kb_fkeytab_size; 428147999Semax needfree = 0; 429147999Semax } 430147999Semax 431147999Semax if (!KBD_IS_PROBED(kbd)) { 432147999Semax /* XXX assume 101/102 keys keyboard */ 433147999Semax kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0); 434147999Semax bcopy(&key_map, keymap, sizeof(key_map)); 435147999Semax bcopy(&accent_map, accmap, sizeof(accent_map)); 436147999Semax bcopy(fkey_tab, fkeymap, 437147999Semax imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 438147999Semax kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 439147999Semax kbd->kb_data = (void *)state; 440147999Semax 441147999Semax KBD_FOUND_DEVICE(kbd); 442147999Semax KBD_PROBE_DONE(kbd); 443147999Semax 444147999Semax KBDMUX_LOCK(state); 445147999Semax kbdmux_clear_state_locked(state); 446147999Semax state->ks_mode = K_XLATE; 447147999Semax KBDMUX_UNLOCK(state); 448147999Semax } 449147999Semax 450147999Semax if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 451147999Semax kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; 452147999Semax 453147999Semax kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 454147999Semax 455147999Semax delay[0] = kbd->kb_delay1; 456147999Semax delay[1] = kbd->kb_delay2; 457147999Semax kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); 458147999Semax 459147999Semax KBD_INIT_DONE(kbd); 460147999Semax } 461147999Semax 462147999Semax if (!KBD_IS_CONFIGURED(kbd)) { 463147999Semax if (kbd_register(kbd) < 0) { 464147999Semax error = ENXIO; 465147999Semax goto bad; 466147999Semax } 467147999Semax 468147999Semax KBD_CONFIG_DONE(kbd); 469147999Semax 470147999Semax KBDMUX_LOCK(state); 471147999Semax callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state); 472147999Semax KBDMUX_UNLOCK(state); 473147999Semax } 474147999Semax 475147999Semax return (0); 476147999Semaxbad: 477147999Semax if (needfree) { 478193512Sed if (state != NULL) 479147999Semax free(state, M_KBDMUX); 480147999Semax if (keymap != NULL) 481147999Semax free(keymap, M_KBDMUX); 482147999Semax if (accmap != NULL) 483147999Semax free(accmap, M_KBDMUX); 484147999Semax if (fkeymap != NULL) 485147999Semax free(fkeymap, M_KBDMUX); 486147999Semax if (kbd != NULL) { 487147999Semax free(kbd, M_KBDMUX); 488147999Semax *kbdp = NULL; /* insure ref doesn't leak to caller */ 489147999Semax } 490147999Semax } 491147999Semax 492147999Semax return (error); 493147999Semax} 494147999Semax 495147999Semax/* 496147999Semax * Finish using this keyboard 497147999Semax */ 498147999Semaxstatic int 499147999Semaxkbdmux_term(keyboard_t *kbd) 500147999Semax{ 501147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 502147999Semax kbdmux_kbd_t *k; 503147999Semax 504147999Semax KBDMUX_LOCK(state); 505147999Semax 506147999Semax /* kill callout */ 507147999Semax callout_stop(&state->ks_timo); 508147999Semax 509147999Semax /* wait for interrupt task */ 510147999Semax while (state->ks_flags & TASK) 511147999Semax KBDMUX_SLEEP(state, ks_task, "kbdmuxc", 0); 512147999Semax 513147999Semax /* release all keyboards from the mux */ 514147999Semax while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) { 515147999Semax kbd_release(k->kbd, &k->kbd); 516147999Semax SLIST_REMOVE_HEAD(&state->ks_kbds, next); 517147999Semax 518147999Semax k->kbd = NULL; 519147999Semax 520147999Semax free(k, M_KBDMUX); 521147999Semax } 522147999Semax 523147999Semax KBDMUX_UNLOCK(state); 524147999Semax 525147999Semax kbd_unregister(kbd); 526147999Semax 527147999Semax KBDMUX_LOCK_DESTROY(state); 528147999Semax bzero(state, sizeof(*state)); 529147999Semax free(state, M_KBDMUX); 530156086Semax 531156086Semax free(kbd->kb_keymap, M_KBDMUX); 532156086Semax free(kbd->kb_accentmap, M_KBDMUX); 533156086Semax free(kbd->kb_fkeytab, M_KBDMUX); 534147999Semax free(kbd, M_KBDMUX); 535147999Semax 536147999Semax return (0); 537147999Semax} 538147999Semax 539147999Semax/* 540147999Semax * Keyboard interrupt routine 541147999Semax */ 542147999Semaxstatic int 543147999Semaxkbdmux_intr(keyboard_t *kbd, void *arg) 544147999Semax{ 545147999Semax int c; 546147999Semax 547147999Semax if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 548147999Semax /* let the callback function to process the input */ 549147999Semax (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 550147999Semax kbd->kb_callback.kc_arg); 551147999Semax } else { 552147999Semax /* read and discard the input; no one is waiting for input */ 553147999Semax do { 554147999Semax c = kbdmux_read_char(kbd, FALSE); 555147999Semax } while (c != NOKEY); 556147999Semax } 557147999Semax 558147999Semax return (0); 559147999Semax} 560147999Semax 561147999Semax/* 562147999Semax * Test the interface to the device 563147999Semax */ 564147999Semaxstatic int 565147999Semaxkbdmux_test_if(keyboard_t *kbd) 566147999Semax{ 567147999Semax return (0); 568147999Semax} 569147999Semax 570147999Semax/* 571147999Semax * Enable the access to the device; until this function is called, 572147999Semax * the client cannot read from the keyboard. 573147999Semax */ 574147999Semaxstatic int 575147999Semaxkbdmux_enable(keyboard_t *kbd) 576147999Semax{ 577147999Semax KBD_ACTIVATE(kbd); 578147999Semax return (0); 579147999Semax} 580147999Semax 581147999Semax/* 582147999Semax * Disallow the access to the device 583147999Semax */ 584147999Semaxstatic int 585147999Semaxkbdmux_disable(keyboard_t *kbd) 586147999Semax{ 587147999Semax KBD_DEACTIVATE(kbd); 588147999Semax return (0); 589147999Semax} 590147999Semax 591147999Semax/* 592147999Semax * Read one byte from the keyboard if it's allowed 593147999Semax */ 594147999Semaxstatic int 595147999Semaxkbdmux_read(keyboard_t *kbd, int wait) 596147999Semax{ 597147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 598147999Semax int c; 599147999Semax 600147999Semax KBDMUX_LOCK(state); 601193512Sed c = kbdmux_kbd_getc(state); 602147999Semax KBDMUX_UNLOCK(state); 603147999Semax 604147999Semax if (c != -1) 605147999Semax kbd->kb_count ++; 606147999Semax 607147999Semax return (KBD_IS_ACTIVE(kbd)? c : -1); 608147999Semax} 609147999Semax 610147999Semax/* 611147999Semax * Check if data is waiting 612147999Semax */ 613147999Semaxstatic int 614147999Semaxkbdmux_check(keyboard_t *kbd) 615147999Semax{ 616147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 617147999Semax int ready; 618147999Semax 619147999Semax if (!KBD_IS_ACTIVE(kbd)) 620147999Semax return (FALSE); 621147999Semax 622147999Semax KBDMUX_LOCK(state); 623193512Sed ready = (state->ks_inq_length > 0) ? TRUE : FALSE; 624147999Semax KBDMUX_UNLOCK(state); 625147999Semax 626147999Semax return (ready); 627147999Semax} 628147999Semax 629147999Semax/* 630147999Semax * Read char from the keyboard (stolen from atkbd.c) 631147999Semax */ 632147999Semaxstatic u_int 633147999Semaxkbdmux_read_char(keyboard_t *kbd, int wait) 634147999Semax{ 635147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 636147999Semax u_int action; 637147999Semax int scancode, keycode; 638147999Semax 639147999Semax KBDMUX_LOCK(state); 640147999Semax 641147999Semaxnext_code: 642147999Semax 643147999Semax /* do we have a composed char to return? */ 644147999Semax if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 645147999Semax action = state->ks_composed_char; 646147999Semax state->ks_composed_char = 0; 647147999Semax if (action > UCHAR_MAX) { 648147999Semax KBDMUX_UNLOCK(state); 649147999Semax 650147999Semax return (ERRKEY); 651147999Semax } 652147999Semax 653147999Semax KBDMUX_UNLOCK(state); 654147999Semax 655147999Semax return (action); 656147999Semax } 657147999Semax 658147999Semax /* see if there is something in the keyboard queue */ 659193512Sed scancode = kbdmux_kbd_getc(state); 660147999Semax if (scancode == -1) { 661160768Semax if (state->ks_flags & POLLING) { 662160768Semax kbdmux_kbd_t *k; 663160768Semax 664160768Semax SLIST_FOREACH(k, &state->ks_kbds, next) { 665174984Swkoszek while (kbdd_check_char(k->kbd)) { 666174984Swkoszek scancode = kbdd_read_char(k->kbd, 0); 667160768Semax if (scancode == NOKEY) 668160768Semax break; 669160768Semax if (scancode == ERRKEY) 670160768Semax continue; 671160768Semax if (!KBD_IS_BUSY(k->kbd)) 672160768Semax continue; 673160768Semax 674193512Sed kbdmux_kbd_putc(state, scancode); 675160768Semax } 676160768Semax } 677160768Semax 678193512Sed if (state->ks_inq_length > 0) 679160768Semax goto next_code; 680160768Semax } 681160768Semax 682147999Semax KBDMUX_UNLOCK(state); 683147999Semax return (NOKEY); 684147999Semax } 685147999Semax /* XXX FIXME: check for -1 if wait == 1! */ 686147999Semax 687147999Semax kbd->kb_count ++; 688147999Semax 689147999Semax /* return the byte as is for the K_RAW mode */ 690147999Semax if (state->ks_mode == K_RAW) { 691147999Semax KBDMUX_UNLOCK(state); 692147999Semax return (scancode); 693147999Semax } 694147999Semax 695147999Semax /* translate the scan code into a keycode */ 696147999Semax keycode = scancode & 0x7F; 697147999Semax switch (state->ks_prefix) { 698147999Semax case 0x00: /* normal scancode */ 699147999Semax switch(scancode) { 700147999Semax case 0xB8: /* left alt (compose key) released */ 701147999Semax if (state->ks_flags & COMPOSE) { 702147999Semax state->ks_flags &= ~COMPOSE; 703147999Semax if (state->ks_composed_char > UCHAR_MAX) 704147999Semax state->ks_composed_char = 0; 705147999Semax } 706147999Semax break; 707147999Semax case 0x38: /* left alt (compose key) pressed */ 708147999Semax if (!(state->ks_flags & COMPOSE)) { 709147999Semax state->ks_flags |= COMPOSE; 710147999Semax state->ks_composed_char = 0; 711147999Semax } 712147999Semax break; 713147999Semax case 0xE0: 714147999Semax case 0xE1: 715147999Semax state->ks_prefix = scancode; 716147999Semax goto next_code; 717147999Semax } 718147999Semax break; 719147999Semax case 0xE0: /* 0xE0 prefix */ 720147999Semax state->ks_prefix = 0; 721147999Semax switch (keycode) { 722147999Semax case 0x1C: /* right enter key */ 723147999Semax keycode = 0x59; 724147999Semax break; 725147999Semax case 0x1D: /* right ctrl key */ 726147999Semax keycode = 0x5A; 727147999Semax break; 728147999Semax case 0x35: /* keypad divide key */ 729147999Semax keycode = 0x5B; 730147999Semax break; 731147999Semax case 0x37: /* print scrn key */ 732147999Semax keycode = 0x5C; 733147999Semax break; 734147999Semax case 0x38: /* right alt key (alt gr) */ 735147999Semax keycode = 0x5D; 736147999Semax break; 737147999Semax case 0x46: /* ctrl-pause/break on AT 101 (see below) */ 738147999Semax keycode = 0x68; 739147999Semax break; 740147999Semax case 0x47: /* grey home key */ 741147999Semax keycode = 0x5E; 742147999Semax break; 743147999Semax case 0x48: /* grey up arrow key */ 744147999Semax keycode = 0x5F; 745147999Semax break; 746147999Semax case 0x49: /* grey page up key */ 747147999Semax keycode = 0x60; 748147999Semax break; 749147999Semax case 0x4B: /* grey left arrow key */ 750147999Semax keycode = 0x61; 751147999Semax break; 752147999Semax case 0x4D: /* grey right arrow key */ 753147999Semax keycode = 0x62; 754147999Semax break; 755147999Semax case 0x4F: /* grey end key */ 756147999Semax keycode = 0x63; 757147999Semax break; 758147999Semax case 0x50: /* grey down arrow key */ 759147999Semax keycode = 0x64; 760147999Semax break; 761147999Semax case 0x51: /* grey page down key */ 762147999Semax keycode = 0x65; 763147999Semax break; 764147999Semax case 0x52: /* grey insert key */ 765147999Semax keycode = 0x66; 766147999Semax break; 767147999Semax case 0x53: /* grey delete key */ 768147999Semax keycode = 0x67; 769147999Semax break; 770147999Semax /* the following 3 are only used on the MS "Natural" keyboard */ 771147999Semax case 0x5b: /* left Window key */ 772147999Semax keycode = 0x69; 773147999Semax break; 774147999Semax case 0x5c: /* right Window key */ 775147999Semax keycode = 0x6a; 776147999Semax break; 777147999Semax case 0x5d: /* menu key */ 778147999Semax keycode = 0x6b; 779147999Semax break; 780147999Semax case 0x5e: /* power key */ 781147999Semax keycode = 0x6d; 782147999Semax break; 783147999Semax case 0x5f: /* sleep key */ 784147999Semax keycode = 0x6e; 785147999Semax break; 786147999Semax case 0x63: /* wake key */ 787147999Semax keycode = 0x6f; 788147999Semax break; 789171373Semax case 0x64: /* [JP106USB] backslash, underscore */ 790171373Semax keycode = 0x73; 791171373Semax break; 792147999Semax default: /* ignore everything else */ 793147999Semax goto next_code; 794147999Semax } 795147999Semax break; 796147999Semax case 0xE1: /* 0xE1 prefix */ 797147999Semax /* 798147999Semax * The pause/break key on the 101 keyboard produces: 799147999Semax * E1-1D-45 E1-9D-C5 800147999Semax * Ctrl-pause/break produces: 801147999Semax * E0-46 E0-C6 (See above.) 802147999Semax */ 803147999Semax state->ks_prefix = 0; 804147999Semax if (keycode == 0x1D) 805147999Semax state->ks_prefix = 0x1D; 806147999Semax goto next_code; 807147999Semax /* NOT REACHED */ 808147999Semax case 0x1D: /* pause / break */ 809147999Semax state->ks_prefix = 0; 810147999Semax if (keycode != 0x45) 811147999Semax goto next_code; 812147999Semax keycode = 0x68; 813147999Semax break; 814147999Semax } 815147999Semax 816147999Semax /* XXX assume 101/102 keys AT keyboard */ 817147999Semax switch (keycode) { 818147999Semax case 0x5c: /* print screen */ 819147999Semax if (state->ks_flags & ALTS) 820147999Semax keycode = 0x54; /* sysrq */ 821147999Semax break; 822147999Semax case 0x68: /* pause/break */ 823147999Semax if (state->ks_flags & CTLS) 824147999Semax keycode = 0x6c; /* break */ 825147999Semax break; 826147999Semax } 827147999Semax 828147999Semax /* return the key code in the K_CODE mode */ 829147999Semax if (state->ks_mode == K_CODE) { 830147999Semax KBDMUX_UNLOCK(state); 831147999Semax return (keycode | (scancode & 0x80)); 832147999Semax } 833147999Semax 834147999Semax /* compose a character code */ 835147999Semax if (state->ks_flags & COMPOSE) { 836147999Semax switch (keycode | (scancode & 0x80)) { 837147999Semax /* key pressed, process it */ 838147999Semax case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 839147999Semax state->ks_composed_char *= 10; 840147999Semax state->ks_composed_char += keycode - 0x40; 841147999Semax if (state->ks_composed_char > UCHAR_MAX) { 842147999Semax KBDMUX_UNLOCK(state); 843147999Semax return (ERRKEY); 844147999Semax } 845147999Semax goto next_code; 846147999Semax case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 847147999Semax state->ks_composed_char *= 10; 848147999Semax state->ks_composed_char += keycode - 0x47; 849147999Semax if (state->ks_composed_char > UCHAR_MAX) { 850147999Semax KBDMUX_UNLOCK(state); 851147999Semax return (ERRKEY); 852147999Semax } 853147999Semax goto next_code; 854147999Semax case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 855147999Semax state->ks_composed_char *= 10; 856147999Semax state->ks_composed_char += keycode - 0x4E; 857147999Semax if (state->ks_composed_char > UCHAR_MAX) { 858147999Semax KBDMUX_UNLOCK(state); 859147999Semax return (ERRKEY); 860147999Semax } 861147999Semax goto next_code; 862147999Semax case 0x52: /* keypad 0 */ 863147999Semax state->ks_composed_char *= 10; 864147999Semax if (state->ks_composed_char > UCHAR_MAX) { 865147999Semax KBDMUX_UNLOCK(state); 866147999Semax return (ERRKEY); 867147999Semax } 868147999Semax goto next_code; 869147999Semax 870147999Semax /* key released, no interest here */ 871147999Semax case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 872147999Semax case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 873147999Semax case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 874147999Semax case 0xD2: /* keypad 0 */ 875147999Semax goto next_code; 876147999Semax 877147999Semax case 0x38: /* left alt key */ 878147999Semax break; 879147999Semax 880147999Semax default: 881147999Semax if (state->ks_composed_char > 0) { 882147999Semax state->ks_flags &= ~COMPOSE; 883147999Semax state->ks_composed_char = 0; 884147999Semax KBDMUX_UNLOCK(state); 885147999Semax return (ERRKEY); 886147999Semax } 887147999Semax break; 888147999Semax } 889147999Semax } 890147999Semax 891147999Semax /* keycode to key action */ 892147999Semax action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 893147999Semax &state->ks_state, &state->ks_accents); 894147999Semax if (action == NOKEY) 895147999Semax goto next_code; 896147999Semax 897147999Semax KBDMUX_UNLOCK(state); 898147999Semax 899147999Semax return (action); 900147999Semax} 901147999Semax 902147999Semax/* 903147999Semax * Check if char is waiting 904147999Semax */ 905147999Semaxstatic int 906147999Semaxkbdmux_check_char(keyboard_t *kbd) 907147999Semax{ 908147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 909147999Semax int ready; 910147999Semax 911147999Semax if (!KBD_IS_ACTIVE(kbd)) 912147999Semax return (FALSE); 913147999Semax 914147999Semax KBDMUX_LOCK(state); 915147999Semax 916147999Semax if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0)) 917147999Semax ready = TRUE; 918147999Semax else 919193512Sed ready = (state->ks_inq_length > 0) ? TRUE : FALSE; 920147999Semax 921147999Semax KBDMUX_UNLOCK(state); 922147999Semax 923147999Semax return (ready); 924147999Semax} 925147999Semax 926147999Semax/* 927147999Semax * Keyboard ioctl's 928147999Semax */ 929147999Semaxstatic int 930147999Semaxkbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 931147999Semax{ 932147999Semax static int delays[] = { 933147999Semax 250, 500, 750, 1000 934147999Semax }; 935147999Semax 936147999Semax static int rates[] = { 937147999Semax 34, 38, 42, 46, 50, 55, 59, 63, 938147999Semax 68, 76, 84, 92, 100, 110, 118, 126, 939147999Semax 136, 152, 168, 184, 200, 220, 236, 252, 940147999Semax 272, 304, 336, 368, 400, 440, 472, 504 941147999Semax }; 942147999Semax 943147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 944147999Semax kbdmux_kbd_t *k; 945148017Semax keyboard_info_t *ki; 946147999Semax int error = 0, mode; 947162711Sru#ifdef COMPAT_FREEBSD6 948162711Sru int ival; 949162711Sru#endif 950147999Semax 951147999Semax if (state == NULL) 952147999Semax return (ENXIO); 953147999Semax 954147999Semax switch (cmd) { 955147999Semax case KBADDKBD: /* add keyboard to the mux */ 956148017Semax ki = (keyboard_info_t *) arg; 957148017Semax 958148017Semax if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' || 959148017Semax strcmp(ki->kb_name, "*") == 0) 960148017Semax return (EINVAL); /* bad input */ 961148017Semax 962147999Semax KBDMUX_LOCK(state); 963147999Semax 964147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 965148017Semax if (k->kbd->kb_unit == ki->kb_unit && 966148017Semax strcmp(k->kbd->kb_name, ki->kb_name) == 0) 967147999Semax break; 968147999Semax 969147999Semax if (k != NULL) { 970147999Semax KBDMUX_UNLOCK(state); 971147999Semax 972147999Semax return (0); /* keyboard already in the mux */ 973147999Semax } 974147999Semax 975147999Semax k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO); 976147999Semax if (k == NULL) { 977147999Semax KBDMUX_UNLOCK(state); 978147999Semax 979147999Semax return (ENOMEM); /* out of memory */ 980147999Semax } 981147999Semax 982148017Semax k->kbd = kbd_get_keyboard( 983148017Semax kbd_allocate( 984148017Semax ki->kb_name, 985148017Semax ki->kb_unit, 986148017Semax (void *) &k->kbd, 987148017Semax kbdmux_kbd_event, (void *) state)); 988147999Semax if (k->kbd == NULL) { 989147999Semax KBDMUX_UNLOCK(state); 990147999Semax free(k, M_KBDMUX); 991147999Semax 992148017Semax return (EINVAL); /* bad keyboard */ 993147999Semax } 994147999Semax 995174984Swkoszek kbdd_enable(k->kbd); 996174984Swkoszek kbdd_clear_state(k->kbd); 997147999Semax 998147999Semax /* set K_RAW mode on slave keyboard */ 999147999Semax mode = K_RAW; 1000174984Swkoszek error = kbdd_ioctl(k->kbd, KDSKBMODE, (caddr_t)&mode); 1001147999Semax if (error == 0) { 1002147999Semax /* set lock keys state on slave keyboard */ 1003147999Semax mode = state->ks_state & LOCK_MASK; 1004174984Swkoszek error = kbdd_ioctl(k->kbd, KDSKBSTATE, (caddr_t)&mode); 1005147999Semax } 1006147999Semax 1007147999Semax if (error != 0) { 1008147999Semax KBDMUX_UNLOCK(state); 1009147999Semax 1010147999Semax kbd_release(k->kbd, &k->kbd); 1011147999Semax k->kbd = NULL; 1012147999Semax 1013147999Semax free(k, M_KBDMUX); 1014147999Semax 1015147999Semax return (error); /* could not set mode */ 1016147999Semax } 1017147999Semax 1018147999Semax SLIST_INSERT_HEAD(&state->ks_kbds, k, next); 1019147999Semax 1020147999Semax KBDMUX_UNLOCK(state); 1021147999Semax break; 1022147999Semax 1023147999Semax case KBRELKBD: /* release keyboard from the mux */ 1024148017Semax ki = (keyboard_info_t *) arg; 1025148017Semax 1026148017Semax if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' || 1027148017Semax strcmp(ki->kb_name, "*") == 0) 1028148017Semax return (EINVAL); /* bad input */ 1029148017Semax 1030147999Semax KBDMUX_LOCK(state); 1031147999Semax 1032147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 1033148017Semax if (k->kbd->kb_unit == ki->kb_unit && 1034148017Semax strcmp(k->kbd->kb_name, ki->kb_name) == 0) 1035147999Semax break; 1036147999Semax 1037147999Semax if (k != NULL) { 1038147999Semax error = kbd_release(k->kbd, &k->kbd); 1039147999Semax if (error == 0) { 1040147999Semax SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next); 1041147999Semax 1042147999Semax k->kbd = NULL; 1043147999Semax 1044147999Semax free(k, M_KBDMUX); 1045147999Semax } 1046147999Semax } else 1047147999Semax error = ENXIO; /* keyboard is not in the mux */ 1048147999Semax 1049147999Semax KBDMUX_UNLOCK(state); 1050147999Semax break; 1051147999Semax 1052147999Semax case KDGKBMODE: /* get kyboard mode */ 1053147999Semax KBDMUX_LOCK(state); 1054162441Sru *(int *)arg = state->ks_mode; 1055147999Semax KBDMUX_UNLOCK(state); 1056147999Semax break; 1057147999Semax 1058162711Sru#ifdef COMPAT_FREEBSD6 1059162711Sru case _IO('K', 7): 1060162711Sru ival = IOCPARM_IVAL(arg); 1061162711Sru arg = (caddr_t)&ival; 1062162711Sru /* FALLTHROUGH */ 1063162711Sru#endif 1064147999Semax case KDSKBMODE: /* set keyboard mode */ 1065147999Semax KBDMUX_LOCK(state); 1066147999Semax 1067162461Sru switch (*(int *)arg) { 1068147999Semax case K_XLATE: 1069147999Semax if (state->ks_mode != K_XLATE) { 1070147999Semax /* make lock key state and LED state match */ 1071147999Semax state->ks_state &= ~LOCK_MASK; 1072147999Semax state->ks_state |= KBD_LED_VAL(kbd); 1073147999Semax } 1074147999Semax /* FALLTHROUGH */ 1075147999Semax 1076147999Semax case K_RAW: 1077147999Semax case K_CODE: 1078162461Sru if (state->ks_mode != *(int *)arg) { 1079147999Semax kbdmux_clear_state_locked(state); 1080162461Sru state->ks_mode = *(int *)arg; 1081147999Semax } 1082147999Semax break; 1083147999Semax 1084147999Semax default: 1085147999Semax error = EINVAL; 1086147999Semax break; 1087147999Semax } 1088147999Semax 1089147999Semax KBDMUX_UNLOCK(state); 1090147999Semax break; 1091147999Semax 1092147999Semax case KDGETLED: /* get keyboard LED */ 1093147999Semax KBDMUX_LOCK(state); 1094162441Sru *(int *)arg = KBD_LED_VAL(kbd); 1095147999Semax KBDMUX_UNLOCK(state); 1096147999Semax break; 1097147999Semax 1098162711Sru#ifdef COMPAT_FREEBSD6 1099162711Sru case _IO('K', 66): 1100162711Sru ival = IOCPARM_IVAL(arg); 1101162711Sru arg = (caddr_t)&ival; 1102162711Sru /* FALLTHROUGH */ 1103162711Sru#endif 1104147999Semax case KDSETLED: /* set keyboard LED */ 1105147999Semax KBDMUX_LOCK(state); 1106147999Semax 1107147999Semax /* NOTE: lock key state in ks_state won't be changed */ 1108162461Sru if (*(int *)arg & ~LOCK_MASK) { 1109147999Semax KBDMUX_UNLOCK(state); 1110147999Semax 1111147999Semax return (EINVAL); 1112147999Semax } 1113147999Semax 1114162461Sru KBD_LED_VAL(kbd) = *(int *)arg; 1115147999Semax 1116147999Semax /* KDSETLED on all slave keyboards */ 1117147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 1118213770Srpaulo (void)kbdd_ioctl(k->kbd, KDSETLED, arg); 1119147999Semax 1120147999Semax KBDMUX_UNLOCK(state); 1121147999Semax break; 1122147999Semax 1123147999Semax case KDGKBSTATE: /* get lock key state */ 1124147999Semax KBDMUX_LOCK(state); 1125162441Sru *(int *)arg = state->ks_state & LOCK_MASK; 1126147999Semax KBDMUX_UNLOCK(state); 1127147999Semax break; 1128147999Semax 1129162711Sru#ifdef COMPAT_FREEBSD6 1130162711Sru case _IO('K', 20): 1131162711Sru ival = IOCPARM_IVAL(arg); 1132162711Sru arg = (caddr_t)&ival; 1133162711Sru /* FALLTHROUGH */ 1134162711Sru#endif 1135147999Semax case KDSKBSTATE: /* set lock key state */ 1136147999Semax KBDMUX_LOCK(state); 1137147999Semax 1138162461Sru if (*(int *)arg & ~LOCK_MASK) { 1139147999Semax KBDMUX_UNLOCK(state); 1140147999Semax 1141147999Semax return (EINVAL); 1142147999Semax } 1143147999Semax 1144147999Semax state->ks_state &= ~LOCK_MASK; 1145162461Sru state->ks_state |= *(int *)arg; 1146147999Semax 1147147999Semax /* KDSKBSTATE on all slave keyboards */ 1148147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 1149213770Srpaulo (void)kbdd_ioctl(k->kbd, KDSKBSTATE, arg); 1150147999Semax 1151147999Semax KBDMUX_UNLOCK(state); 1152147999Semax 1153147999Semax return (kbdmux_ioctl(kbd, KDSETLED, arg)); 1154147999Semax /* NOT REACHED */ 1155147999Semax 1156162711Sru#ifdef COMPAT_FREEBSD6 1157162711Sru case _IO('K', 67): 1158162711Sru cmd = KDSETRAD; 1159162711Sru ival = IOCPARM_IVAL(arg); 1160162711Sru arg = (caddr_t)&ival; 1161162711Sru /* FALLTHROUGH */ 1162162711Sru#endif 1163147999Semax case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 1164147999Semax case KDSETRAD: /* set keyboard repeat rate (old interface) */ 1165147999Semax KBDMUX_LOCK(state); 1166147999Semax 1167147999Semax if (cmd == KDSETREPEAT) { 1168147999Semax int i; 1169147999Semax 1170147999Semax /* lookup delay */ 1171147999Semax for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --) 1172162441Sru if (((int *)arg)[0] >= delays[i]) 1173147999Semax break; 1174147999Semax mode = i << 5; 1175147999Semax 1176147999Semax /* lookup rate */ 1177147999Semax for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --) 1178162441Sru if (((int *)arg)[1] >= rates[i]) 1179147999Semax break; 1180147999Semax mode |= i; 1181147999Semax } else 1182162461Sru mode = *(int *)arg; 1183147999Semax 1184147999Semax if (mode & ~0x7f) { 1185147999Semax KBDMUX_UNLOCK(state); 1186147999Semax 1187147999Semax return (EINVAL); 1188147999Semax } 1189147999Semax 1190147999Semax kbd->kb_delay1 = delays[(mode >> 5) & 3]; 1191147999Semax kbd->kb_delay2 = rates[mode & 0x1f]; 1192147999Semax 1193147999Semax /* perform command on all slave keyboards */ 1194147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 1195213770Srpaulo (void)kbdd_ioctl(k->kbd, cmd, arg); 1196147999Semax 1197147999Semax KBDMUX_UNLOCK(state); 1198147999Semax break; 1199147999Semax 1200147999Semax case PIO_KEYMAP: /* set keyboard translation table */ 1201224126Sed case OPIO_KEYMAP: /* set keyboard translation table (compat) */ 1202156013Semax case PIO_KEYMAPENT: /* set keyboard translation table entry */ 1203156013Semax case PIO_DEADKEYMAP: /* set accent key translation table */ 1204147999Semax KBDMUX_LOCK(state); 1205147999Semax state->ks_accents = 0; 1206147999Semax 1207147999Semax /* perform command on all slave keyboards */ 1208147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 1209213770Srpaulo (void)kbdd_ioctl(k->kbd, cmd, arg); 1210147999Semax 1211147999Semax KBDMUX_UNLOCK(state); 1212147999Semax /* FALLTHROUGH */ 1213147999Semax 1214147999Semax default: 1215147999Semax error = genkbd_commonioctl(kbd, cmd, arg); 1216147999Semax break; 1217147999Semax } 1218147999Semax 1219147999Semax return (error); 1220147999Semax} 1221147999Semax 1222147999Semax/* 1223147999Semax * Lock the access to the keyboard 1224147999Semax */ 1225147999Semaxstatic int 1226147999Semaxkbdmux_lock(keyboard_t *kbd, int lock) 1227147999Semax{ 1228147999Semax return (1); /* XXX */ 1229147999Semax} 1230147999Semax 1231147999Semax/* 1232147999Semax * Clear the internal state of the keyboard 1233147999Semax */ 1234147999Semaxstatic void 1235147999Semaxkbdmux_clear_state_locked(kbdmux_state_t *state) 1236147999Semax{ 1237147999Semax KBDMUX_LOCK_ASSERT(state, MA_OWNED); 1238147999Semax 1239147999Semax state->ks_flags &= ~(COMPOSE|POLLING); 1240147999Semax state->ks_state &= LOCK_MASK; /* preserve locking key state */ 1241147999Semax state->ks_accents = 0; 1242147999Semax state->ks_composed_char = 0; 1243147999Semax/* state->ks_prefix = 0; XXX */ 1244193512Sed state->ks_inq_length = 0; 1245147999Semax} 1246147999Semax 1247147999Semaxstatic void 1248147999Semaxkbdmux_clear_state(keyboard_t *kbd) 1249147999Semax{ 1250147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 1251147999Semax 1252147999Semax KBDMUX_LOCK(state); 1253147999Semax kbdmux_clear_state_locked(state); 1254147999Semax KBDMUX_UNLOCK(state); 1255147999Semax} 1256147999Semax 1257147999Semax/* 1258147999Semax * Save the internal state 1259147999Semax */ 1260147999Semaxstatic int 1261147999Semaxkbdmux_get_state(keyboard_t *kbd, void *buf, size_t len) 1262147999Semax{ 1263147999Semax if (len == 0) 1264147999Semax return (sizeof(kbdmux_state_t)); 1265147999Semax if (len < sizeof(kbdmux_state_t)) 1266147999Semax return (-1); 1267147999Semax 1268147999Semax bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */ 1269147999Semax 1270147999Semax return (0); 1271147999Semax} 1272147999Semax 1273147999Semax/* 1274147999Semax * Set the internal state 1275147999Semax */ 1276147999Semaxstatic int 1277147999Semaxkbdmux_set_state(keyboard_t *kbd, void *buf, size_t len) 1278147999Semax{ 1279147999Semax if (len < sizeof(kbdmux_state_t)) 1280147999Semax return (ENOMEM); 1281147999Semax 1282147999Semax bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */ 1283147999Semax 1284147999Semax return (0); 1285147999Semax} 1286147999Semax 1287147999Semax/* 1288147999Semax * Set polling 1289147999Semax */ 1290147999Semaxstatic int 1291147999Semaxkbdmux_poll(keyboard_t *kbd, int on) 1292147999Semax{ 1293147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 1294147999Semax kbdmux_kbd_t *k; 1295147999Semax 1296147999Semax KBDMUX_LOCK(state); 1297147999Semax 1298147999Semax if (on) 1299147999Semax state->ks_flags |= POLLING; 1300147999Semax else 1301147999Semax state->ks_flags &= ~POLLING; 1302147999Semax 1303147999Semax /* set poll on slave keyboards */ 1304147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 1305174984Swkoszek kbdd_poll(k->kbd, on); 1306147999Semax 1307147999Semax KBDMUX_UNLOCK(state); 1308147999Semax 1309147999Semax return (0); 1310147999Semax} 1311147999Semax 1312147999Semax/***************************************************************************** 1313147999Semax ***************************************************************************** 1314147999Semax ** Module 1315147999Semax ***************************************************************************** 1316147999Semax *****************************************************************************/ 1317147999Semax 1318147999SemaxKEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure); 1319147999Semax 1320147999Semaxstatic int 1321147999Semaxkbdmux_modevent(module_t mod, int type, void *data) 1322147999Semax{ 1323147999Semax keyboard_switch_t *sw; 1324147999Semax keyboard_t *kbd; 1325147999Semax int error; 1326147999Semax 1327147999Semax switch (type) { 1328147999Semax case MOD_LOAD: 1329147999Semax if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0) 1330147999Semax break; 1331147999Semax 1332147999Semax if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) { 1333147999Semax kbd_delete_driver(&kbdmux_kbd_driver); 1334147999Semax error = ENXIO; 1335147999Semax break; 1336147999Semax } 1337147999Semax 1338147999Semax kbd = NULL; 1339147999Semax 1340147999Semax if ((error = (*sw->probe)(0, NULL, 0)) != 0 || 1341147999Semax (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) { 1342147999Semax kbd_delete_driver(&kbdmux_kbd_driver); 1343147999Semax break; 1344147999Semax } 1345147999Semax 1346147999Semax#ifdef KBD_INSTALL_CDEV 1347147999Semax if ((error = kbd_attach(kbd)) != 0) { 1348147999Semax (*sw->term)(kbd); 1349147999Semax kbd_delete_driver(&kbdmux_kbd_driver); 1350147999Semax break; 1351147999Semax } 1352147999Semax#endif 1353147999Semax 1354147999Semax if ((error = (*sw->enable)(kbd)) != 0) { 1355147999Semax (*sw->disable)(kbd); 1356151440Syar#ifdef KBD_INSTALL_CDEV 1357147999Semax kbd_detach(kbd); 1358151440Syar#endif 1359147999Semax (*sw->term)(kbd); 1360147999Semax kbd_delete_driver(&kbdmux_kbd_driver); 1361147999Semax break; 1362147999Semax } 1363147999Semax break; 1364147999Semax 1365147999Semax case MOD_UNLOAD: 1366147999Semax if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) 1367147999Semax panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL"); 1368147999Semax 1369147999Semax kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0)); 1370188603Sthompsa if (kbd != NULL) { 1371188603Sthompsa (*sw->disable)(kbd); 1372147999Semax#ifdef KBD_INSTALL_CDEV 1373188603Sthompsa kbd_detach(kbd); 1374147999Semax#endif 1375188603Sthompsa (*sw->term)(kbd); 1376188603Sthompsa kbd_delete_driver(&kbdmux_kbd_driver); 1377188603Sthompsa } 1378147999Semax error = 0; 1379147999Semax break; 1380147999Semax 1381147999Semax default: 1382147999Semax error = EOPNOTSUPP; 1383147999Semax break; 1384147999Semax } 1385147999Semax 1386188030Semax return (error); 1387147999Semax} 1388147999Semax 1389147999SemaxDEV_MODULE(kbdmux, kbdmux_modevent, NULL); 1390147999Semax 1391