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$ 32147999Semax */ 33147999Semax 34162711Sru#include "opt_compat.h" 35147999Semax#include "opt_kbd.h" 36298430Semaste#include "opt_kbdmux.h" 37147999Semax 38147999Semax#include <sys/param.h> 39156167Semax#include <sys/bus.h> 40147999Semax#include <sys/conf.h> 41147999Semax#include <sys/consio.h> 42147999Semax#include <sys/fcntl.h> 43147999Semax#include <sys/kbio.h> 44147999Semax#include <sys/kernel.h> 45147999Semax#include <sys/limits.h> 46147999Semax#include <sys/lock.h> 47147999Semax#include <sys/malloc.h> 48147999Semax#include <sys/module.h> 49147999Semax#include <sys/mutex.h> 50147999Semax#include <sys/poll.h> 51147999Semax#include <sys/proc.h> 52147999Semax#include <sys/queue.h> 53147999Semax#include <sys/selinfo.h> 54147999Semax#include <sys/systm.h> 55147999Semax#include <sys/taskqueue.h> 56147999Semax#include <sys/uio.h> 57147999Semax#include <dev/kbd/kbdreg.h> 58298430Semaste 59298430Semaste/* the initial key map, accent map and fkey strings */ 60298430Semaste#ifdef KBDMUX_DFLT_KEYMAP 61298430Semaste#define KBD_DFLT_KEYMAP 62298430Semaste#include "kbdmuxmap.h" 63298430Semaste#endif 64298430Semaste 65147999Semax#include <dev/kbd/kbdtables.h> 66147999Semax 67147999Semax#define KEYBOARD_NAME "kbdmux" 68147999Semax 69147999SemaxMALLOC_DECLARE(M_KBDMUX); 70147999SemaxMALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor"); 71147999Semax 72147999Semax/***************************************************************************** 73147999Semax ***************************************************************************** 74147999Semax ** Keyboard state 75147999Semax ***************************************************************************** 76147999Semax *****************************************************************************/ 77147999Semax 78147999Semax#define KBDMUX_Q_SIZE 512 /* input queue size */ 79147999Semax 80147999Semax/* 81147999Semax * XXX 82147999Semax * For now rely on Giant mutex to protect our data structures. 83147999Semax * Just like the rest of keyboard drivers and syscons(4) do. 84147999Semax * Note that callout is initialized as not MP-safe to make sure 85147999Semax * Giant is held. 86147999Semax */ 87147999Semax 88147999Semax#if 0 /* not yet */ 89147999Semax#define KBDMUX_LOCK_DECL_GLOBAL \ 90147999Semax struct mtx ks_lock 91147999Semax#define KBDMUX_LOCK_INIT(s) \ 92147999Semax mtx_init(&(s)->ks_lock, "kbdmux", NULL, MTX_DEF|MTX_RECURSE) 93147999Semax#define KBDMUX_LOCK_DESTROY(s) \ 94147999Semax mtx_destroy(&(s)->ks_lock) 95147999Semax#define KBDMUX_LOCK(s) \ 96147999Semax mtx_lock(&(s)->ks_lock) 97147999Semax#define KBDMUX_UNLOCK(s) \ 98147999Semax mtx_unlock(&(s)->ks_lock) 99147999Semax#define KBDMUX_LOCK_ASSERT(s, w) \ 100147999Semax mtx_assert(&(s)->ks_lock, (w)) 101147999Semax#define KBDMUX_SLEEP(s, f, d, t) \ 102147999Semax msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), (d), (t)) 103147999Semax#define KBDMUX_CALLOUT_INIT(s) \ 104147999Semax callout_init_mtx(&(s)->ks_timo, &(s)->ks_lock, 0) 105147999Semax#define KBDMUX_QUEUE_INTR(s) \ 106147999Semax taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task) 107147999Semax#else 108147999Semax#define KBDMUX_LOCK_DECL_GLOBAL 109147999Semax 110147999Semax#define KBDMUX_LOCK_INIT(s) 111147999Semax 112147999Semax#define KBDMUX_LOCK_DESTROY(s) 113147999Semax 114190857Semax#define KBDMUX_LOCK(s) 115190857Semax 116190857Semax#define KBDMUX_UNLOCK(s) 117190857Semax 118147999Semax#define KBDMUX_LOCK_ASSERT(s, w) 119147999Semax 120147999Semax#define KBDMUX_SLEEP(s, f, d, t) \ 121147999Semax tsleep(&(s)->f, PCATCH | (PZERO + 1), (d), (t)) 122147999Semax#define KBDMUX_CALLOUT_INIT(s) \ 123147999Semax callout_init(&(s)->ks_timo, 0) 124147999Semax#define KBDMUX_QUEUE_INTR(s) \ 125147999Semax taskqueue_enqueue(taskqueue_swi_giant, &(s)->ks_task) 126147999Semax#endif /* not yet */ 127147999Semax 128147999Semax/* 129147999Semax * kbdmux keyboard 130147999Semax */ 131147999Semaxstruct kbdmux_kbd 132147999Semax{ 133147999Semax keyboard_t *kbd; /* keyboard */ 134147999Semax SLIST_ENTRY(kbdmux_kbd) next; /* link to next */ 135147999Semax}; 136147999Semax 137147999Semaxtypedef struct kbdmux_kbd kbdmux_kbd_t; 138147999Semax 139147999Semax/* 140147999Semax * kbdmux state 141147999Semax */ 142147999Semaxstruct kbdmux_state 143147999Semax{ 144193512Sed char ks_inq[KBDMUX_Q_SIZE]; /* input chars queue */ 145193512Sed unsigned int ks_inq_start; 146193512Sed unsigned int ks_inq_length; 147147999Semax struct task ks_task; /* interrupt task */ 148147999Semax struct callout ks_timo; /* timeout handler */ 149147999Semax#define TICKS (hz) /* rate */ 150147999Semax 151147999Semax int ks_flags; /* flags */ 152147999Semax#define COMPOSE (1 << 0) /* compose char flag */ 153147999Semax#define POLLING (1 << 1) /* polling */ 154147999Semax#define TASK (1 << 2) /* interrupt task queued */ 155147999Semax 156147999Semax int ks_mode; /* K_XLATE, K_RAW, K_CODE */ 157147999Semax int ks_state; /* state */ 158147999Semax int ks_accents; /* accent key index (> 0) */ 159147999Semax u_int ks_composed_char; /* composed char code */ 160147999Semax u_char ks_prefix; /* AT scan code prefix */ 161147999Semax 162147999Semax SLIST_HEAD(, kbdmux_kbd) ks_kbds; /* keyboards */ 163147999Semax 164147999Semax KBDMUX_LOCK_DECL_GLOBAL; 165147999Semax}; 166147999Semax 167147999Semaxtypedef struct kbdmux_state kbdmux_state_t; 168147999Semax 169147999Semax/***************************************************************************** 170147999Semax ***************************************************************************** 171147999Semax ** Helper functions 172147999Semax ***************************************************************************** 173147999Semax *****************************************************************************/ 174147999Semax 175147999Semaxstatic task_fn_t kbdmux_kbd_intr; 176147999Semaxstatic timeout_t kbdmux_kbd_intr_timo; 177147999Semaxstatic kbd_callback_func_t kbdmux_kbd_event; 178147999Semax 179193512Sedstatic void 180193512Sedkbdmux_kbd_putc(kbdmux_state_t *state, char c) 181193512Sed{ 182193512Sed unsigned int p; 183193512Sed 184193512Sed if (state->ks_inq_length == KBDMUX_Q_SIZE) 185193512Sed return; 186193512Sed 187193512Sed p = (state->ks_inq_start + state->ks_inq_length) % KBDMUX_Q_SIZE; 188193512Sed state->ks_inq[p] = c; 189193512Sed state->ks_inq_length++; 190193512Sed} 191193512Sed 192193752Sedstatic int 193193512Sedkbdmux_kbd_getc(kbdmux_state_t *state) 194193512Sed{ 195193752Sed unsigned char c; 196193512Sed 197193512Sed if (state->ks_inq_length == 0) 198193512Sed return (-1); 199193512Sed 200193512Sed c = state->ks_inq[state->ks_inq_start]; 201193512Sed state->ks_inq_start = (state->ks_inq_start + 1) % KBDMUX_Q_SIZE; 202193512Sed state->ks_inq_length--; 203193512Sed 204193512Sed return (c); 205193512Sed} 206193512Sed 207147999Semax/* 208147999Semax * Interrupt handler task 209147999Semax */ 210147999Semaxvoid 211147999Semaxkbdmux_kbd_intr(void *xkbd, int pending) 212147999Semax{ 213147999Semax keyboard_t *kbd = (keyboard_t *) xkbd; 214147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 215147999Semax 216174984Swkoszek kbdd_intr(kbd, NULL); 217147999Semax 218147999Semax KBDMUX_LOCK(state); 219147999Semax 220147999Semax state->ks_flags &= ~TASK; 221147999Semax wakeup(&state->ks_task); 222147999Semax 223147999Semax KBDMUX_UNLOCK(state); 224147999Semax} 225147999Semax 226147999Semax/* 227147999Semax * Schedule interrupt handler on timeout. Called with locked state. 228147999Semax */ 229147999Semaxvoid 230147999Semaxkbdmux_kbd_intr_timo(void *xstate) 231147999Semax{ 232147999Semax kbdmux_state_t *state = (kbdmux_state_t *) xstate; 233147999Semax 234147999Semax KBDMUX_LOCK_ASSERT(state, MA_OWNED); 235147999Semax 236147999Semax if (callout_pending(&state->ks_timo)) 237147999Semax return; /* callout was reset */ 238147999Semax 239147999Semax if (!callout_active(&state->ks_timo)) 240147999Semax return; /* callout was stopped */ 241147999Semax 242147999Semax callout_deactivate(&state->ks_timo); 243147999Semax 244147999Semax /* queue interrupt task if needed */ 245193512Sed if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) && 246147999Semax KBDMUX_QUEUE_INTR(state) == 0) 247147999Semax state->ks_flags |= TASK; 248147999Semax 249147999Semax /* re-schedule timeout */ 250147999Semax callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state); 251147999Semax} 252147999Semax 253147999Semax/* 254147999Semax * Process event from one of our keyboards 255147999Semax */ 256147999Semaxstatic int 257147999Semaxkbdmux_kbd_event(keyboard_t *kbd, int event, void *arg) 258147999Semax{ 259147999Semax kbdmux_state_t *state = (kbdmux_state_t *) arg; 260147999Semax 261147999Semax switch (event) { 262147999Semax case KBDIO_KEYINPUT: { 263147999Semax int c; 264147999Semax 265147999Semax KBDMUX_LOCK(state); 266147999Semax 267156013Semax /* 268156013Semax * Read all chars from the keyboard 269156013Semax * 270156013Semax * Turns out that atkbd(4) check_char() method may return 271156013Semax * "true" while read_char() method returns NOKEY. If this 272156013Semax * happens we could stuck in the loop below. Avoid this 273156013Semax * by breaking out of the loop if read_char() method returns 274156013Semax * NOKEY. 275156013Semax */ 276156013Semax 277174984Swkoszek while (kbdd_check_char(kbd)) { 278174984Swkoszek c = kbdd_read_char(kbd, 0); 279147999Semax if (c == NOKEY) 280156010Semax break; 281147999Semax if (c == ERRKEY) 282147999Semax continue; /* XXX ring bell */ 283147999Semax if (!KBD_IS_BUSY(kbd)) 284147999Semax continue; /* not open - discard the input */ 285147999Semax 286193512Sed kbdmux_kbd_putc(state, c); 287147999Semax } 288147999Semax 289147999Semax /* queue interrupt task if needed */ 290193512Sed if (state->ks_inq_length > 0 && !(state->ks_flags & TASK) && 291147999Semax KBDMUX_QUEUE_INTR(state) == 0) 292147999Semax state->ks_flags |= TASK; 293147999Semax 294147999Semax KBDMUX_UNLOCK(state); 295147999Semax } break; 296147999Semax 297147999Semax case KBDIO_UNLOADING: { 298147999Semax kbdmux_kbd_t *k; 299147999Semax 300147999Semax KBDMUX_LOCK(state); 301147999Semax 302147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 303147999Semax if (k->kbd == kbd) 304147999Semax break; 305147999Semax 306147999Semax if (k != NULL) { 307147999Semax kbd_release(k->kbd, &k->kbd); 308147999Semax SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next); 309147999Semax 310147999Semax k->kbd = NULL; 311147999Semax 312147999Semax free(k, M_KBDMUX); 313147999Semax } 314147999Semax 315147999Semax KBDMUX_UNLOCK(state); 316147999Semax } break; 317147999Semax 318147999Semax default: 319147999Semax return (EINVAL); 320147999Semax /* NOT REACHED */ 321147999Semax } 322147999Semax 323147999Semax return (0); 324147999Semax} 325147999Semax 326147999Semax/**************************************************************************** 327147999Semax **************************************************************************** 328147999Semax ** Keyboard driver 329147999Semax **************************************************************************** 330147999Semax ****************************************************************************/ 331147999Semax 332147999Semaxstatic int kbdmux_configure(int flags); 333147999Semaxstatic kbd_probe_t kbdmux_probe; 334147999Semaxstatic kbd_init_t kbdmux_init; 335147999Semaxstatic kbd_term_t kbdmux_term; 336147999Semaxstatic kbd_intr_t kbdmux_intr; 337147999Semaxstatic kbd_test_if_t kbdmux_test_if; 338147999Semaxstatic kbd_enable_t kbdmux_enable; 339147999Semaxstatic kbd_disable_t kbdmux_disable; 340147999Semaxstatic kbd_read_t kbdmux_read; 341147999Semaxstatic kbd_check_t kbdmux_check; 342147999Semaxstatic kbd_read_char_t kbdmux_read_char; 343147999Semaxstatic kbd_check_char_t kbdmux_check_char; 344147999Semaxstatic kbd_ioctl_t kbdmux_ioctl; 345147999Semaxstatic kbd_lock_t kbdmux_lock; 346147999Semaxstatic void kbdmux_clear_state_locked(kbdmux_state_t *state); 347147999Semaxstatic kbd_clear_state_t kbdmux_clear_state; 348147999Semaxstatic kbd_get_state_t kbdmux_get_state; 349147999Semaxstatic kbd_set_state_t kbdmux_set_state; 350147999Semaxstatic kbd_poll_mode_t kbdmux_poll; 351147999Semax 352147999Semaxstatic keyboard_switch_t kbdmuxsw = { 353147999Semax .probe = kbdmux_probe, 354147999Semax .init = kbdmux_init, 355147999Semax .term = kbdmux_term, 356147999Semax .intr = kbdmux_intr, 357147999Semax .test_if = kbdmux_test_if, 358147999Semax .enable = kbdmux_enable, 359147999Semax .disable = kbdmux_disable, 360147999Semax .read = kbdmux_read, 361147999Semax .check = kbdmux_check, 362147999Semax .read_char = kbdmux_read_char, 363147999Semax .check_char = kbdmux_check_char, 364147999Semax .ioctl = kbdmux_ioctl, 365147999Semax .lock = kbdmux_lock, 366147999Semax .clear_state = kbdmux_clear_state, 367147999Semax .get_state = kbdmux_get_state, 368147999Semax .set_state = kbdmux_set_state, 369147999Semax .get_fkeystr = genkbd_get_fkeystr, 370147999Semax .poll = kbdmux_poll, 371147999Semax .diag = genkbd_diag, 372147999Semax}; 373147999Semax 374147999Semax/* 375147999Semax * Return the number of found keyboards 376147999Semax */ 377147999Semaxstatic int 378147999Semaxkbdmux_configure(int flags) 379147999Semax{ 380147999Semax return (1); 381147999Semax} 382147999Semax 383147999Semax/* 384147999Semax * Detect a keyboard 385147999Semax */ 386147999Semaxstatic int 387147999Semaxkbdmux_probe(int unit, void *arg, int flags) 388147999Semax{ 389241885Seadler if (resource_disabled(KEYBOARD_NAME, unit)) 390241885Seadler return (ENXIO); 391156167Semax 392147999Semax return (0); 393147999Semax} 394147999Semax 395147999Semax/* 396147999Semax * Reset and initialize the keyboard (stolen from atkbd.c) 397147999Semax */ 398147999Semaxstatic int 399147999Semaxkbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags) 400147999Semax{ 401147999Semax keyboard_t *kbd = NULL; 402147999Semax kbdmux_state_t *state = NULL; 403147999Semax keymap_t *keymap = NULL; 404147999Semax accentmap_t *accmap = NULL; 405147999Semax fkeytab_t *fkeymap = NULL; 406147999Semax int error, needfree, fkeymap_size, delay[2]; 407147999Semax 408147999Semax if (*kbdp == NULL) { 409147999Semax *kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO); 410147999Semax state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO); 411147999Semax keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT); 412147999Semax accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT); 413147999Semax fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT); 414147999Semax fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); 415147999Semax needfree = 1; 416147999Semax 417147999Semax if ((kbd == NULL) || (state == NULL) || (keymap == NULL) || 418147999Semax (accmap == NULL) || (fkeymap == NULL)) { 419147999Semax error = ENOMEM; 420147999Semax goto bad; 421147999Semax } 422147999Semax 423147999Semax KBDMUX_LOCK_INIT(state); 424147999Semax TASK_INIT(&state->ks_task, 0, kbdmux_kbd_intr, (void *) kbd); 425147999Semax KBDMUX_CALLOUT_INIT(state); 426147999Semax SLIST_INIT(&state->ks_kbds); 427147999Semax } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { 428147999Semax return (0); 429147999Semax } else { 430147999Semax kbd = *kbdp; 431147999Semax state = (kbdmux_state_t *) kbd->kb_data; 432147999Semax keymap = kbd->kb_keymap; 433147999Semax accmap = kbd->kb_accentmap; 434147999Semax fkeymap = kbd->kb_fkeytab; 435147999Semax fkeymap_size = kbd->kb_fkeytab_size; 436147999Semax needfree = 0; 437147999Semax } 438147999Semax 439147999Semax if (!KBD_IS_PROBED(kbd)) { 440147999Semax /* XXX assume 101/102 keys keyboard */ 441147999Semax kbd_init_struct(kbd, KEYBOARD_NAME, KB_101, unit, flags, 0, 0); 442147999Semax bcopy(&key_map, keymap, sizeof(key_map)); 443147999Semax bcopy(&accent_map, accmap, sizeof(accent_map)); 444147999Semax bcopy(fkey_tab, fkeymap, 445147999Semax imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 446147999Semax kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 447147999Semax kbd->kb_data = (void *)state; 448147999Semax 449147999Semax KBD_FOUND_DEVICE(kbd); 450147999Semax KBD_PROBE_DONE(kbd); 451147999Semax 452147999Semax KBDMUX_LOCK(state); 453147999Semax kbdmux_clear_state_locked(state); 454147999Semax state->ks_mode = K_XLATE; 455147999Semax KBDMUX_UNLOCK(state); 456147999Semax } 457147999Semax 458147999Semax if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 459147999Semax kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; 460147999Semax 461147999Semax kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 462147999Semax 463147999Semax delay[0] = kbd->kb_delay1; 464147999Semax delay[1] = kbd->kb_delay2; 465147999Semax kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); 466147999Semax 467147999Semax KBD_INIT_DONE(kbd); 468147999Semax } 469147999Semax 470147999Semax if (!KBD_IS_CONFIGURED(kbd)) { 471147999Semax if (kbd_register(kbd) < 0) { 472147999Semax error = ENXIO; 473147999Semax goto bad; 474147999Semax } 475147999Semax 476147999Semax KBD_CONFIG_DONE(kbd); 477147999Semax 478147999Semax KBDMUX_LOCK(state); 479147999Semax callout_reset(&state->ks_timo, TICKS, kbdmux_kbd_intr_timo, state); 480147999Semax KBDMUX_UNLOCK(state); 481147999Semax } 482147999Semax 483147999Semax return (0); 484147999Semaxbad: 485147999Semax if (needfree) { 486193512Sed if (state != NULL) 487147999Semax free(state, M_KBDMUX); 488147999Semax if (keymap != NULL) 489147999Semax free(keymap, M_KBDMUX); 490147999Semax if (accmap != NULL) 491147999Semax free(accmap, M_KBDMUX); 492147999Semax if (fkeymap != NULL) 493147999Semax free(fkeymap, M_KBDMUX); 494147999Semax if (kbd != NULL) { 495147999Semax free(kbd, M_KBDMUX); 496147999Semax *kbdp = NULL; /* insure ref doesn't leak to caller */ 497147999Semax } 498147999Semax } 499147999Semax 500147999Semax return (error); 501147999Semax} 502147999Semax 503147999Semax/* 504147999Semax * Finish using this keyboard 505147999Semax */ 506147999Semaxstatic int 507147999Semaxkbdmux_term(keyboard_t *kbd) 508147999Semax{ 509147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 510147999Semax kbdmux_kbd_t *k; 511147999Semax 512147999Semax KBDMUX_LOCK(state); 513147999Semax 514147999Semax /* kill callout */ 515147999Semax callout_stop(&state->ks_timo); 516147999Semax 517147999Semax /* wait for interrupt task */ 518147999Semax while (state->ks_flags & TASK) 519147999Semax KBDMUX_SLEEP(state, ks_task, "kbdmuxc", 0); 520147999Semax 521147999Semax /* release all keyboards from the mux */ 522147999Semax while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) { 523147999Semax kbd_release(k->kbd, &k->kbd); 524147999Semax SLIST_REMOVE_HEAD(&state->ks_kbds, next); 525147999Semax 526147999Semax k->kbd = NULL; 527147999Semax 528147999Semax free(k, M_KBDMUX); 529147999Semax } 530147999Semax 531147999Semax KBDMUX_UNLOCK(state); 532147999Semax 533147999Semax kbd_unregister(kbd); 534147999Semax 535147999Semax KBDMUX_LOCK_DESTROY(state); 536147999Semax bzero(state, sizeof(*state)); 537147999Semax free(state, M_KBDMUX); 538156086Semax 539156086Semax free(kbd->kb_keymap, M_KBDMUX); 540156086Semax free(kbd->kb_accentmap, M_KBDMUX); 541156086Semax free(kbd->kb_fkeytab, M_KBDMUX); 542147999Semax free(kbd, M_KBDMUX); 543147999Semax 544147999Semax return (0); 545147999Semax} 546147999Semax 547147999Semax/* 548147999Semax * Keyboard interrupt routine 549147999Semax */ 550147999Semaxstatic int 551147999Semaxkbdmux_intr(keyboard_t *kbd, void *arg) 552147999Semax{ 553147999Semax int c; 554147999Semax 555147999Semax if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 556147999Semax /* let the callback function to process the input */ 557147999Semax (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 558147999Semax kbd->kb_callback.kc_arg); 559147999Semax } else { 560147999Semax /* read and discard the input; no one is waiting for input */ 561147999Semax do { 562147999Semax c = kbdmux_read_char(kbd, FALSE); 563147999Semax } while (c != NOKEY); 564147999Semax } 565147999Semax 566147999Semax return (0); 567147999Semax} 568147999Semax 569147999Semax/* 570147999Semax * Test the interface to the device 571147999Semax */ 572147999Semaxstatic int 573147999Semaxkbdmux_test_if(keyboard_t *kbd) 574147999Semax{ 575147999Semax return (0); 576147999Semax} 577147999Semax 578147999Semax/* 579147999Semax * Enable the access to the device; until this function is called, 580147999Semax * the client cannot read from the keyboard. 581147999Semax */ 582147999Semaxstatic int 583147999Semaxkbdmux_enable(keyboard_t *kbd) 584147999Semax{ 585147999Semax KBD_ACTIVATE(kbd); 586147999Semax return (0); 587147999Semax} 588147999Semax 589147999Semax/* 590147999Semax * Disallow the access to the device 591147999Semax */ 592147999Semaxstatic int 593147999Semaxkbdmux_disable(keyboard_t *kbd) 594147999Semax{ 595147999Semax KBD_DEACTIVATE(kbd); 596147999Semax return (0); 597147999Semax} 598147999Semax 599147999Semax/* 600147999Semax * Read one byte from the keyboard if it's allowed 601147999Semax */ 602147999Semaxstatic int 603147999Semaxkbdmux_read(keyboard_t *kbd, int wait) 604147999Semax{ 605147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 606147999Semax int c; 607147999Semax 608147999Semax KBDMUX_LOCK(state); 609193512Sed c = kbdmux_kbd_getc(state); 610147999Semax KBDMUX_UNLOCK(state); 611147999Semax 612147999Semax if (c != -1) 613147999Semax kbd->kb_count ++; 614147999Semax 615147999Semax return (KBD_IS_ACTIVE(kbd)? c : -1); 616147999Semax} 617147999Semax 618147999Semax/* 619147999Semax * Check if data is waiting 620147999Semax */ 621147999Semaxstatic int 622147999Semaxkbdmux_check(keyboard_t *kbd) 623147999Semax{ 624147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 625147999Semax int ready; 626147999Semax 627147999Semax if (!KBD_IS_ACTIVE(kbd)) 628147999Semax return (FALSE); 629147999Semax 630147999Semax KBDMUX_LOCK(state); 631193512Sed ready = (state->ks_inq_length > 0) ? TRUE : FALSE; 632147999Semax KBDMUX_UNLOCK(state); 633147999Semax 634147999Semax return (ready); 635147999Semax} 636147999Semax 637147999Semax/* 638147999Semax * Read char from the keyboard (stolen from atkbd.c) 639147999Semax */ 640147999Semaxstatic u_int 641147999Semaxkbdmux_read_char(keyboard_t *kbd, int wait) 642147999Semax{ 643147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 644147999Semax u_int action; 645147999Semax int scancode, keycode; 646147999Semax 647147999Semax KBDMUX_LOCK(state); 648147999Semax 649147999Semaxnext_code: 650147999Semax 651147999Semax /* do we have a composed char to return? */ 652147999Semax if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 653147999Semax action = state->ks_composed_char; 654147999Semax state->ks_composed_char = 0; 655147999Semax if (action > UCHAR_MAX) { 656147999Semax KBDMUX_UNLOCK(state); 657147999Semax 658147999Semax return (ERRKEY); 659147999Semax } 660147999Semax 661147999Semax KBDMUX_UNLOCK(state); 662147999Semax 663147999Semax return (action); 664147999Semax } 665147999Semax 666147999Semax /* see if there is something in the keyboard queue */ 667193512Sed scancode = kbdmux_kbd_getc(state); 668147999Semax if (scancode == -1) { 669160768Semax if (state->ks_flags & POLLING) { 670160768Semax kbdmux_kbd_t *k; 671160768Semax 672160768Semax SLIST_FOREACH(k, &state->ks_kbds, next) { 673174984Swkoszek while (kbdd_check_char(k->kbd)) { 674174984Swkoszek scancode = kbdd_read_char(k->kbd, 0); 675160768Semax if (scancode == NOKEY) 676160768Semax break; 677160768Semax if (scancode == ERRKEY) 678160768Semax continue; 679160768Semax if (!KBD_IS_BUSY(k->kbd)) 680160768Semax continue; 681160768Semax 682193512Sed kbdmux_kbd_putc(state, scancode); 683160768Semax } 684160768Semax } 685160768Semax 686193512Sed if (state->ks_inq_length > 0) 687160768Semax goto next_code; 688160768Semax } 689160768Semax 690147999Semax KBDMUX_UNLOCK(state); 691147999Semax return (NOKEY); 692147999Semax } 693147999Semax /* XXX FIXME: check for -1 if wait == 1! */ 694147999Semax 695147999Semax kbd->kb_count ++; 696147999Semax 697147999Semax /* return the byte as is for the K_RAW mode */ 698147999Semax if (state->ks_mode == K_RAW) { 699147999Semax KBDMUX_UNLOCK(state); 700147999Semax return (scancode); 701147999Semax } 702147999Semax 703147999Semax /* translate the scan code into a keycode */ 704147999Semax keycode = scancode & 0x7F; 705147999Semax switch (state->ks_prefix) { 706147999Semax case 0x00: /* normal scancode */ 707147999Semax switch(scancode) { 708147999Semax case 0xB8: /* left alt (compose key) released */ 709147999Semax if (state->ks_flags & COMPOSE) { 710147999Semax state->ks_flags &= ~COMPOSE; 711147999Semax if (state->ks_composed_char > UCHAR_MAX) 712147999Semax state->ks_composed_char = 0; 713147999Semax } 714147999Semax break; 715147999Semax case 0x38: /* left alt (compose key) pressed */ 716147999Semax if (!(state->ks_flags & COMPOSE)) { 717147999Semax state->ks_flags |= COMPOSE; 718147999Semax state->ks_composed_char = 0; 719147999Semax } 720147999Semax break; 721147999Semax case 0xE0: 722147999Semax case 0xE1: 723147999Semax state->ks_prefix = scancode; 724147999Semax goto next_code; 725147999Semax } 726147999Semax break; 727147999Semax case 0xE0: /* 0xE0 prefix */ 728147999Semax state->ks_prefix = 0; 729147999Semax switch (keycode) { 730147999Semax case 0x1C: /* right enter key */ 731147999Semax keycode = 0x59; 732147999Semax break; 733147999Semax case 0x1D: /* right ctrl key */ 734147999Semax keycode = 0x5A; 735147999Semax break; 736147999Semax case 0x35: /* keypad divide key */ 737147999Semax keycode = 0x5B; 738147999Semax break; 739147999Semax case 0x37: /* print scrn key */ 740147999Semax keycode = 0x5C; 741147999Semax break; 742147999Semax case 0x38: /* right alt key (alt gr) */ 743147999Semax keycode = 0x5D; 744147999Semax break; 745147999Semax case 0x46: /* ctrl-pause/break on AT 101 (see below) */ 746147999Semax keycode = 0x68; 747147999Semax break; 748147999Semax case 0x47: /* grey home key */ 749147999Semax keycode = 0x5E; 750147999Semax break; 751147999Semax case 0x48: /* grey up arrow key */ 752147999Semax keycode = 0x5F; 753147999Semax break; 754147999Semax case 0x49: /* grey page up key */ 755147999Semax keycode = 0x60; 756147999Semax break; 757147999Semax case 0x4B: /* grey left arrow key */ 758147999Semax keycode = 0x61; 759147999Semax break; 760147999Semax case 0x4D: /* grey right arrow key */ 761147999Semax keycode = 0x62; 762147999Semax break; 763147999Semax case 0x4F: /* grey end key */ 764147999Semax keycode = 0x63; 765147999Semax break; 766147999Semax case 0x50: /* grey down arrow key */ 767147999Semax keycode = 0x64; 768147999Semax break; 769147999Semax case 0x51: /* grey page down key */ 770147999Semax keycode = 0x65; 771147999Semax break; 772147999Semax case 0x52: /* grey insert key */ 773147999Semax keycode = 0x66; 774147999Semax break; 775147999Semax case 0x53: /* grey delete key */ 776147999Semax keycode = 0x67; 777147999Semax break; 778147999Semax /* the following 3 are only used on the MS "Natural" keyboard */ 779147999Semax case 0x5b: /* left Window key */ 780147999Semax keycode = 0x69; 781147999Semax break; 782147999Semax case 0x5c: /* right Window key */ 783147999Semax keycode = 0x6a; 784147999Semax break; 785147999Semax case 0x5d: /* menu key */ 786147999Semax keycode = 0x6b; 787147999Semax break; 788147999Semax case 0x5e: /* power key */ 789147999Semax keycode = 0x6d; 790147999Semax break; 791147999Semax case 0x5f: /* sleep key */ 792147999Semax keycode = 0x6e; 793147999Semax break; 794147999Semax case 0x63: /* wake key */ 795147999Semax keycode = 0x6f; 796147999Semax break; 797171373Semax case 0x64: /* [JP106USB] backslash, underscore */ 798171373Semax keycode = 0x73; 799171373Semax break; 800147999Semax default: /* ignore everything else */ 801147999Semax goto next_code; 802147999Semax } 803147999Semax break; 804147999Semax case 0xE1: /* 0xE1 prefix */ 805147999Semax /* 806147999Semax * The pause/break key on the 101 keyboard produces: 807147999Semax * E1-1D-45 E1-9D-C5 808147999Semax * Ctrl-pause/break produces: 809147999Semax * E0-46 E0-C6 (See above.) 810147999Semax */ 811147999Semax state->ks_prefix = 0; 812147999Semax if (keycode == 0x1D) 813147999Semax state->ks_prefix = 0x1D; 814147999Semax goto next_code; 815147999Semax /* NOT REACHED */ 816147999Semax case 0x1D: /* pause / break */ 817147999Semax state->ks_prefix = 0; 818147999Semax if (keycode != 0x45) 819147999Semax goto next_code; 820147999Semax keycode = 0x68; 821147999Semax break; 822147999Semax } 823147999Semax 824147999Semax /* XXX assume 101/102 keys AT keyboard */ 825147999Semax switch (keycode) { 826147999Semax case 0x5c: /* print screen */ 827147999Semax if (state->ks_flags & ALTS) 828147999Semax keycode = 0x54; /* sysrq */ 829147999Semax break; 830147999Semax case 0x68: /* pause/break */ 831147999Semax if (state->ks_flags & CTLS) 832147999Semax keycode = 0x6c; /* break */ 833147999Semax break; 834147999Semax } 835147999Semax 836147999Semax /* return the key code in the K_CODE mode */ 837147999Semax if (state->ks_mode == K_CODE) { 838147999Semax KBDMUX_UNLOCK(state); 839147999Semax return (keycode | (scancode & 0x80)); 840147999Semax } 841147999Semax 842147999Semax /* compose a character code */ 843147999Semax if (state->ks_flags & COMPOSE) { 844147999Semax switch (keycode | (scancode & 0x80)) { 845147999Semax /* key pressed, process it */ 846147999Semax case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 847147999Semax state->ks_composed_char *= 10; 848147999Semax state->ks_composed_char += keycode - 0x40; 849147999Semax if (state->ks_composed_char > UCHAR_MAX) { 850147999Semax KBDMUX_UNLOCK(state); 851147999Semax return (ERRKEY); 852147999Semax } 853147999Semax goto next_code; 854147999Semax case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 855147999Semax state->ks_composed_char *= 10; 856147999Semax state->ks_composed_char += keycode - 0x47; 857147999Semax if (state->ks_composed_char > UCHAR_MAX) { 858147999Semax KBDMUX_UNLOCK(state); 859147999Semax return (ERRKEY); 860147999Semax } 861147999Semax goto next_code; 862147999Semax case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 863147999Semax state->ks_composed_char *= 10; 864147999Semax state->ks_composed_char += keycode - 0x4E; 865147999Semax if (state->ks_composed_char > UCHAR_MAX) { 866147999Semax KBDMUX_UNLOCK(state); 867147999Semax return (ERRKEY); 868147999Semax } 869147999Semax goto next_code; 870147999Semax case 0x52: /* keypad 0 */ 871147999Semax state->ks_composed_char *= 10; 872147999Semax if (state->ks_composed_char > UCHAR_MAX) { 873147999Semax KBDMUX_UNLOCK(state); 874147999Semax return (ERRKEY); 875147999Semax } 876147999Semax goto next_code; 877147999Semax 878147999Semax /* key released, no interest here */ 879147999Semax case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 880147999Semax case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 881147999Semax case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 882147999Semax case 0xD2: /* keypad 0 */ 883147999Semax goto next_code; 884147999Semax 885147999Semax case 0x38: /* left alt key */ 886147999Semax break; 887147999Semax 888147999Semax default: 889147999Semax if (state->ks_composed_char > 0) { 890147999Semax state->ks_flags &= ~COMPOSE; 891147999Semax state->ks_composed_char = 0; 892147999Semax KBDMUX_UNLOCK(state); 893147999Semax return (ERRKEY); 894147999Semax } 895147999Semax break; 896147999Semax } 897147999Semax } 898147999Semax 899147999Semax /* keycode to key action */ 900147999Semax action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 901147999Semax &state->ks_state, &state->ks_accents); 902147999Semax if (action == NOKEY) 903147999Semax goto next_code; 904147999Semax 905147999Semax KBDMUX_UNLOCK(state); 906147999Semax 907147999Semax return (action); 908147999Semax} 909147999Semax 910147999Semax/* 911147999Semax * Check if char is waiting 912147999Semax */ 913147999Semaxstatic int 914147999Semaxkbdmux_check_char(keyboard_t *kbd) 915147999Semax{ 916147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 917147999Semax int ready; 918147999Semax 919147999Semax if (!KBD_IS_ACTIVE(kbd)) 920147999Semax return (FALSE); 921147999Semax 922147999Semax KBDMUX_LOCK(state); 923147999Semax 924147999Semax if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char != 0)) 925147999Semax ready = TRUE; 926147999Semax else 927193512Sed ready = (state->ks_inq_length > 0) ? TRUE : FALSE; 928147999Semax 929147999Semax KBDMUX_UNLOCK(state); 930147999Semax 931147999Semax return (ready); 932147999Semax} 933147999Semax 934147999Semax/* 935147999Semax * Keyboard ioctl's 936147999Semax */ 937147999Semaxstatic int 938147999Semaxkbdmux_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 939147999Semax{ 940147999Semax static int delays[] = { 941147999Semax 250, 500, 750, 1000 942147999Semax }; 943147999Semax 944147999Semax static int rates[] = { 945147999Semax 34, 38, 42, 46, 50, 55, 59, 63, 946147999Semax 68, 76, 84, 92, 100, 110, 118, 126, 947147999Semax 136, 152, 168, 184, 200, 220, 236, 252, 948147999Semax 272, 304, 336, 368, 400, 440, 472, 504 949147999Semax }; 950147999Semax 951147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 952147999Semax kbdmux_kbd_t *k; 953148017Semax keyboard_info_t *ki; 954147999Semax int error = 0, mode; 955162711Sru#ifdef COMPAT_FREEBSD6 956162711Sru int ival; 957162711Sru#endif 958147999Semax 959147999Semax if (state == NULL) 960147999Semax return (ENXIO); 961147999Semax 962147999Semax switch (cmd) { 963147999Semax case KBADDKBD: /* add keyboard to the mux */ 964148017Semax ki = (keyboard_info_t *) arg; 965148017Semax 966148017Semax if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' || 967148017Semax strcmp(ki->kb_name, "*") == 0) 968148017Semax return (EINVAL); /* bad input */ 969148017Semax 970147999Semax KBDMUX_LOCK(state); 971147999Semax 972147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 973148017Semax if (k->kbd->kb_unit == ki->kb_unit && 974148017Semax strcmp(k->kbd->kb_name, ki->kb_name) == 0) 975147999Semax break; 976147999Semax 977147999Semax if (k != NULL) { 978147999Semax KBDMUX_UNLOCK(state); 979147999Semax 980147999Semax return (0); /* keyboard already in the mux */ 981147999Semax } 982147999Semax 983147999Semax k = malloc(sizeof(*k), M_KBDMUX, M_NOWAIT | M_ZERO); 984147999Semax if (k == NULL) { 985147999Semax KBDMUX_UNLOCK(state); 986147999Semax 987147999Semax return (ENOMEM); /* out of memory */ 988147999Semax } 989147999Semax 990148017Semax k->kbd = kbd_get_keyboard( 991148017Semax kbd_allocate( 992148017Semax ki->kb_name, 993148017Semax ki->kb_unit, 994148017Semax (void *) &k->kbd, 995148017Semax kbdmux_kbd_event, (void *) state)); 996147999Semax if (k->kbd == NULL) { 997147999Semax KBDMUX_UNLOCK(state); 998147999Semax free(k, M_KBDMUX); 999147999Semax 1000148017Semax return (EINVAL); /* bad keyboard */ 1001147999Semax } 1002147999Semax 1003174984Swkoszek kbdd_enable(k->kbd); 1004174984Swkoszek kbdd_clear_state(k->kbd); 1005147999Semax 1006147999Semax /* set K_RAW mode on slave keyboard */ 1007147999Semax mode = K_RAW; 1008174984Swkoszek error = kbdd_ioctl(k->kbd, KDSKBMODE, (caddr_t)&mode); 1009147999Semax if (error == 0) { 1010147999Semax /* set lock keys state on slave keyboard */ 1011147999Semax mode = state->ks_state & LOCK_MASK; 1012174984Swkoszek error = kbdd_ioctl(k->kbd, KDSKBSTATE, (caddr_t)&mode); 1013147999Semax } 1014147999Semax 1015147999Semax if (error != 0) { 1016147999Semax KBDMUX_UNLOCK(state); 1017147999Semax 1018147999Semax kbd_release(k->kbd, &k->kbd); 1019147999Semax k->kbd = NULL; 1020147999Semax 1021147999Semax free(k, M_KBDMUX); 1022147999Semax 1023147999Semax return (error); /* could not set mode */ 1024147999Semax } 1025147999Semax 1026147999Semax SLIST_INSERT_HEAD(&state->ks_kbds, k, next); 1027147999Semax 1028147999Semax KBDMUX_UNLOCK(state); 1029147999Semax break; 1030147999Semax 1031147999Semax case KBRELKBD: /* release keyboard from the mux */ 1032148017Semax ki = (keyboard_info_t *) arg; 1033148017Semax 1034148017Semax if (ki == NULL || ki->kb_unit < 0 || ki->kb_name[0] == '\0' || 1035148017Semax strcmp(ki->kb_name, "*") == 0) 1036148017Semax return (EINVAL); /* bad input */ 1037148017Semax 1038147999Semax KBDMUX_LOCK(state); 1039147999Semax 1040147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 1041148017Semax if (k->kbd->kb_unit == ki->kb_unit && 1042148017Semax strcmp(k->kbd->kb_name, ki->kb_name) == 0) 1043147999Semax break; 1044147999Semax 1045147999Semax if (k != NULL) { 1046147999Semax error = kbd_release(k->kbd, &k->kbd); 1047147999Semax if (error == 0) { 1048147999Semax SLIST_REMOVE(&state->ks_kbds, k, kbdmux_kbd, next); 1049147999Semax 1050147999Semax k->kbd = NULL; 1051147999Semax 1052147999Semax free(k, M_KBDMUX); 1053147999Semax } 1054147999Semax } else 1055147999Semax error = ENXIO; /* keyboard is not in the mux */ 1056147999Semax 1057147999Semax KBDMUX_UNLOCK(state); 1058147999Semax break; 1059147999Semax 1060147999Semax case KDGKBMODE: /* get kyboard mode */ 1061147999Semax KBDMUX_LOCK(state); 1062162441Sru *(int *)arg = state->ks_mode; 1063147999Semax KBDMUX_UNLOCK(state); 1064147999Semax break; 1065147999Semax 1066162711Sru#ifdef COMPAT_FREEBSD6 1067162711Sru case _IO('K', 7): 1068162711Sru ival = IOCPARM_IVAL(arg); 1069162711Sru arg = (caddr_t)&ival; 1070162711Sru /* FALLTHROUGH */ 1071162711Sru#endif 1072147999Semax case KDSKBMODE: /* set keyboard mode */ 1073147999Semax KBDMUX_LOCK(state); 1074147999Semax 1075162461Sru switch (*(int *)arg) { 1076147999Semax case K_XLATE: 1077147999Semax if (state->ks_mode != K_XLATE) { 1078147999Semax /* make lock key state and LED state match */ 1079147999Semax state->ks_state &= ~LOCK_MASK; 1080147999Semax state->ks_state |= KBD_LED_VAL(kbd); 1081147999Semax } 1082147999Semax /* FALLTHROUGH */ 1083147999Semax 1084147999Semax case K_RAW: 1085147999Semax case K_CODE: 1086162461Sru if (state->ks_mode != *(int *)arg) { 1087147999Semax kbdmux_clear_state_locked(state); 1088162461Sru state->ks_mode = *(int *)arg; 1089147999Semax } 1090147999Semax break; 1091147999Semax 1092147999Semax default: 1093147999Semax error = EINVAL; 1094147999Semax break; 1095147999Semax } 1096147999Semax 1097147999Semax KBDMUX_UNLOCK(state); 1098147999Semax break; 1099147999Semax 1100147999Semax case KDGETLED: /* get keyboard LED */ 1101147999Semax KBDMUX_LOCK(state); 1102162441Sru *(int *)arg = KBD_LED_VAL(kbd); 1103147999Semax KBDMUX_UNLOCK(state); 1104147999Semax break; 1105147999Semax 1106162711Sru#ifdef COMPAT_FREEBSD6 1107162711Sru case _IO('K', 66): 1108162711Sru ival = IOCPARM_IVAL(arg); 1109162711Sru arg = (caddr_t)&ival; 1110162711Sru /* FALLTHROUGH */ 1111162711Sru#endif 1112147999Semax case KDSETLED: /* set keyboard LED */ 1113147999Semax KBDMUX_LOCK(state); 1114147999Semax 1115147999Semax /* NOTE: lock key state in ks_state won't be changed */ 1116162461Sru if (*(int *)arg & ~LOCK_MASK) { 1117147999Semax KBDMUX_UNLOCK(state); 1118147999Semax 1119147999Semax return (EINVAL); 1120147999Semax } 1121147999Semax 1122162461Sru KBD_LED_VAL(kbd) = *(int *)arg; 1123147999Semax 1124147999Semax /* KDSETLED on all slave keyboards */ 1125147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 1126213770Srpaulo (void)kbdd_ioctl(k->kbd, KDSETLED, arg); 1127147999Semax 1128147999Semax KBDMUX_UNLOCK(state); 1129147999Semax break; 1130147999Semax 1131147999Semax case KDGKBSTATE: /* get lock key state */ 1132147999Semax KBDMUX_LOCK(state); 1133162441Sru *(int *)arg = state->ks_state & LOCK_MASK; 1134147999Semax KBDMUX_UNLOCK(state); 1135147999Semax break; 1136147999Semax 1137162711Sru#ifdef COMPAT_FREEBSD6 1138162711Sru case _IO('K', 20): 1139162711Sru ival = IOCPARM_IVAL(arg); 1140162711Sru arg = (caddr_t)&ival; 1141162711Sru /* FALLTHROUGH */ 1142162711Sru#endif 1143147999Semax case KDSKBSTATE: /* set lock key state */ 1144147999Semax KBDMUX_LOCK(state); 1145147999Semax 1146162461Sru if (*(int *)arg & ~LOCK_MASK) { 1147147999Semax KBDMUX_UNLOCK(state); 1148147999Semax 1149147999Semax return (EINVAL); 1150147999Semax } 1151147999Semax 1152147999Semax state->ks_state &= ~LOCK_MASK; 1153162461Sru state->ks_state |= *(int *)arg; 1154147999Semax 1155147999Semax /* KDSKBSTATE on all slave keyboards */ 1156147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 1157213770Srpaulo (void)kbdd_ioctl(k->kbd, KDSKBSTATE, arg); 1158147999Semax 1159147999Semax KBDMUX_UNLOCK(state); 1160147999Semax 1161147999Semax return (kbdmux_ioctl(kbd, KDSETLED, arg)); 1162147999Semax /* NOT REACHED */ 1163147999Semax 1164162711Sru#ifdef COMPAT_FREEBSD6 1165162711Sru case _IO('K', 67): 1166162711Sru cmd = KDSETRAD; 1167162711Sru ival = IOCPARM_IVAL(arg); 1168162711Sru arg = (caddr_t)&ival; 1169162711Sru /* FALLTHROUGH */ 1170162711Sru#endif 1171147999Semax case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 1172147999Semax case KDSETRAD: /* set keyboard repeat rate (old interface) */ 1173147999Semax KBDMUX_LOCK(state); 1174147999Semax 1175147999Semax if (cmd == KDSETREPEAT) { 1176147999Semax int i; 1177147999Semax 1178147999Semax /* lookup delay */ 1179147999Semax for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --) 1180162441Sru if (((int *)arg)[0] >= delays[i]) 1181147999Semax break; 1182147999Semax mode = i << 5; 1183147999Semax 1184147999Semax /* lookup rate */ 1185147999Semax for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --) 1186162441Sru if (((int *)arg)[1] >= rates[i]) 1187147999Semax break; 1188147999Semax mode |= i; 1189147999Semax } else 1190162461Sru mode = *(int *)arg; 1191147999Semax 1192147999Semax if (mode & ~0x7f) { 1193147999Semax KBDMUX_UNLOCK(state); 1194147999Semax 1195147999Semax return (EINVAL); 1196147999Semax } 1197147999Semax 1198147999Semax kbd->kb_delay1 = delays[(mode >> 5) & 3]; 1199147999Semax kbd->kb_delay2 = rates[mode & 0x1f]; 1200147999Semax 1201147999Semax /* perform command on all slave keyboards */ 1202147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 1203213770Srpaulo (void)kbdd_ioctl(k->kbd, cmd, arg); 1204147999Semax 1205147999Semax KBDMUX_UNLOCK(state); 1206147999Semax break; 1207147999Semax 1208147999Semax case PIO_KEYMAP: /* set keyboard translation table */ 1209224126Sed case OPIO_KEYMAP: /* set keyboard translation table (compat) */ 1210156013Semax case PIO_KEYMAPENT: /* set keyboard translation table entry */ 1211156013Semax case PIO_DEADKEYMAP: /* set accent key translation table */ 1212147999Semax KBDMUX_LOCK(state); 1213147999Semax state->ks_accents = 0; 1214147999Semax 1215147999Semax /* perform command on all slave keyboards */ 1216147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 1217213770Srpaulo (void)kbdd_ioctl(k->kbd, cmd, arg); 1218147999Semax 1219147999Semax KBDMUX_UNLOCK(state); 1220147999Semax /* FALLTHROUGH */ 1221147999Semax 1222147999Semax default: 1223147999Semax error = genkbd_commonioctl(kbd, cmd, arg); 1224147999Semax break; 1225147999Semax } 1226147999Semax 1227147999Semax return (error); 1228147999Semax} 1229147999Semax 1230147999Semax/* 1231147999Semax * Lock the access to the keyboard 1232147999Semax */ 1233147999Semaxstatic int 1234147999Semaxkbdmux_lock(keyboard_t *kbd, int lock) 1235147999Semax{ 1236147999Semax return (1); /* XXX */ 1237147999Semax} 1238147999Semax 1239147999Semax/* 1240147999Semax * Clear the internal state of the keyboard 1241147999Semax */ 1242147999Semaxstatic void 1243147999Semaxkbdmux_clear_state_locked(kbdmux_state_t *state) 1244147999Semax{ 1245147999Semax KBDMUX_LOCK_ASSERT(state, MA_OWNED); 1246147999Semax 1247147999Semax state->ks_flags &= ~(COMPOSE|POLLING); 1248147999Semax state->ks_state &= LOCK_MASK; /* preserve locking key state */ 1249147999Semax state->ks_accents = 0; 1250147999Semax state->ks_composed_char = 0; 1251147999Semax/* state->ks_prefix = 0; XXX */ 1252193512Sed state->ks_inq_length = 0; 1253147999Semax} 1254147999Semax 1255147999Semaxstatic void 1256147999Semaxkbdmux_clear_state(keyboard_t *kbd) 1257147999Semax{ 1258147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 1259147999Semax 1260147999Semax KBDMUX_LOCK(state); 1261147999Semax kbdmux_clear_state_locked(state); 1262147999Semax KBDMUX_UNLOCK(state); 1263147999Semax} 1264147999Semax 1265147999Semax/* 1266147999Semax * Save the internal state 1267147999Semax */ 1268147999Semaxstatic int 1269147999Semaxkbdmux_get_state(keyboard_t *kbd, void *buf, size_t len) 1270147999Semax{ 1271147999Semax if (len == 0) 1272147999Semax return (sizeof(kbdmux_state_t)); 1273147999Semax if (len < sizeof(kbdmux_state_t)) 1274147999Semax return (-1); 1275147999Semax 1276147999Semax bcopy(kbd->kb_data, buf, sizeof(kbdmux_state_t)); /* XXX locking? */ 1277147999Semax 1278147999Semax return (0); 1279147999Semax} 1280147999Semax 1281147999Semax/* 1282147999Semax * Set the internal state 1283147999Semax */ 1284147999Semaxstatic int 1285147999Semaxkbdmux_set_state(keyboard_t *kbd, void *buf, size_t len) 1286147999Semax{ 1287147999Semax if (len < sizeof(kbdmux_state_t)) 1288147999Semax return (ENOMEM); 1289147999Semax 1290147999Semax bcopy(buf, kbd->kb_data, sizeof(kbdmux_state_t)); /* XXX locking? */ 1291147999Semax 1292147999Semax return (0); 1293147999Semax} 1294147999Semax 1295147999Semax/* 1296147999Semax * Set polling 1297147999Semax */ 1298147999Semaxstatic int 1299147999Semaxkbdmux_poll(keyboard_t *kbd, int on) 1300147999Semax{ 1301147999Semax kbdmux_state_t *state = (kbdmux_state_t *) kbd->kb_data; 1302147999Semax kbdmux_kbd_t *k; 1303147999Semax 1304147999Semax KBDMUX_LOCK(state); 1305147999Semax 1306147999Semax if (on) 1307147999Semax state->ks_flags |= POLLING; 1308147999Semax else 1309147999Semax state->ks_flags &= ~POLLING; 1310147999Semax 1311147999Semax /* set poll on slave keyboards */ 1312147999Semax SLIST_FOREACH(k, &state->ks_kbds, next) 1313174984Swkoszek kbdd_poll(k->kbd, on); 1314147999Semax 1315147999Semax KBDMUX_UNLOCK(state); 1316147999Semax 1317147999Semax return (0); 1318147999Semax} 1319147999Semax 1320147999Semax/***************************************************************************** 1321147999Semax ***************************************************************************** 1322147999Semax ** Module 1323147999Semax ***************************************************************************** 1324147999Semax *****************************************************************************/ 1325147999Semax 1326147999SemaxKEYBOARD_DRIVER(kbdmux, kbdmuxsw, kbdmux_configure); 1327147999Semax 1328147999Semaxstatic int 1329147999Semaxkbdmux_modevent(module_t mod, int type, void *data) 1330147999Semax{ 1331147999Semax keyboard_switch_t *sw; 1332147999Semax keyboard_t *kbd; 1333147999Semax int error; 1334147999Semax 1335147999Semax switch (type) { 1336147999Semax case MOD_LOAD: 1337147999Semax if ((error = kbd_add_driver(&kbdmux_kbd_driver)) != 0) 1338147999Semax break; 1339147999Semax 1340147999Semax if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) { 1341147999Semax kbd_delete_driver(&kbdmux_kbd_driver); 1342147999Semax error = ENXIO; 1343147999Semax break; 1344147999Semax } 1345147999Semax 1346147999Semax kbd = NULL; 1347147999Semax 1348147999Semax if ((error = (*sw->probe)(0, NULL, 0)) != 0 || 1349147999Semax (error = (*sw->init)(0, &kbd, NULL, 0)) != 0) { 1350147999Semax kbd_delete_driver(&kbdmux_kbd_driver); 1351147999Semax break; 1352147999Semax } 1353147999Semax 1354147999Semax#ifdef KBD_INSTALL_CDEV 1355147999Semax if ((error = kbd_attach(kbd)) != 0) { 1356147999Semax (*sw->term)(kbd); 1357147999Semax kbd_delete_driver(&kbdmux_kbd_driver); 1358147999Semax break; 1359147999Semax } 1360147999Semax#endif 1361147999Semax 1362147999Semax if ((error = (*sw->enable)(kbd)) != 0) { 1363147999Semax (*sw->disable)(kbd); 1364151440Syar#ifdef KBD_INSTALL_CDEV 1365147999Semax kbd_detach(kbd); 1366151440Syar#endif 1367147999Semax (*sw->term)(kbd); 1368147999Semax kbd_delete_driver(&kbdmux_kbd_driver); 1369147999Semax break; 1370147999Semax } 1371147999Semax break; 1372147999Semax 1373147999Semax case MOD_UNLOAD: 1374147999Semax if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) 1375147999Semax panic("kbd_get_switch(" KEYBOARD_NAME ") == NULL"); 1376147999Semax 1377147999Semax kbd = kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, 0)); 1378188603Sthompsa if (kbd != NULL) { 1379188603Sthompsa (*sw->disable)(kbd); 1380147999Semax#ifdef KBD_INSTALL_CDEV 1381188603Sthompsa kbd_detach(kbd); 1382147999Semax#endif 1383188603Sthompsa (*sw->term)(kbd); 1384188603Sthompsa kbd_delete_driver(&kbdmux_kbd_driver); 1385188603Sthompsa } 1386147999Semax error = 0; 1387147999Semax break; 1388147999Semax 1389147999Semax default: 1390147999Semax error = EOPNOTSUPP; 1391147999Semax break; 1392147999Semax } 1393147999Semax 1394188030Semax return (error); 1395147999Semax} 1396147999Semax 1397147999SemaxDEV_MODULE(kbdmux, kbdmux_modevent, NULL); 1398147999Semax 1399