vkbd.c revision 226500
1156057Semax/* 2156057Semax * vkbd.c 3156057Semax */ 4156057Semax 5139749Simp/*- 6137776Semax * Copyright (c) 2004 Maksim Yevmenkin <m_evmenkin@yahoo.com> 7137776Semax * All rights reserved. 8137776Semax * 9137776Semax * Redistribution and use in source and binary forms, with or without 10137776Semax * modification, are permitted provided that the following conditions 11137776Semax * are met: 12137776Semax * 1. Redistributions of source code must retain the above copyright 13137776Semax * notice, this list of conditions and the following disclaimer. 14137776Semax * 2. Redistributions in binary form must reproduce the above copyright 15137776Semax * notice, this list of conditions and the following disclaimer in the 16137776Semax * documentation and/or other materials provided with the distribution. 17137776Semax * 18137776Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19137776Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20137776Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21137776Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22137776Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23137776Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24137776Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25137776Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26137776Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27137776Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28137776Semax * SUCH DAMAGE. 29137776Semax * 30137776Semax * $Id: vkbd.c,v 1.20 2004/11/15 23:53:30 max Exp $ 31137776Semax * $FreeBSD: head/sys/dev/vkbd/vkbd.c 226500 2011-10-18 08:09:44Z ed $ 32137776Semax */ 33137776Semax 34162711Sru#include "opt_compat.h" 35137776Semax#include "opt_kbd.h" 36137776Semax 37137776Semax#include <sys/param.h> 38137776Semax#include <sys/conf.h> 39139204Sphk#include <sys/fcntl.h> 40137776Semax#include <sys/kbio.h> 41137776Semax#include <sys/kernel.h> 42137776Semax#include <sys/limits.h> 43137776Semax#include <sys/lock.h> 44137776Semax#include <sys/malloc.h> 45137776Semax#include <sys/module.h> 46137776Semax#include <sys/mutex.h> 47137776Semax#include <sys/poll.h> 48137776Semax#include <sys/proc.h> 49137776Semax#include <sys/queue.h> 50139204Sphk#include <sys/selinfo.h> 51137776Semax#include <sys/systm.h> 52137776Semax#include <sys/taskqueue.h> 53137776Semax#include <sys/uio.h> 54137776Semax#include <dev/kbd/kbdreg.h> 55137776Semax#include <dev/kbd/kbdtables.h> 56137776Semax#include <dev/vkbd/vkbd_var.h> 57137776Semax 58137776Semax#define DEVICE_NAME "vkbdctl" 59137776Semax#define KEYBOARD_NAME "vkbd" 60137776Semax 61137776SemaxMALLOC_DECLARE(M_VKBD); 62137776SemaxMALLOC_DEFINE(M_VKBD, KEYBOARD_NAME, "Virtual AT keyboard"); 63137776Semax 64137776Semax/***************************************************************************** 65137776Semax ***************************************************************************** 66137776Semax ** Keyboard state 67137776Semax ***************************************************************************** 68137776Semax *****************************************************************************/ 69137776Semax 70156057Semax/* 71156057Semax * XXX 72156057Semax * For now rely on Giant mutex to protect our data structures. 73156057Semax * Just like the rest of keyboard drivers and syscons(4) do. 74156057Semax */ 75156057Semax 76156057Semax#if 0 /* not yet */ 77137776Semax#define VKBD_LOCK_DECL struct mtx ks_lock 78148246Semax#define VKBD_LOCK_INIT(s) mtx_init(&(s)->ks_lock, "vkbd_lock", NULL, MTX_DEF|MTX_RECURSE) 79137776Semax#define VKBD_LOCK_DESTROY(s) mtx_destroy(&(s)->ks_lock) 80137776Semax#define VKBD_LOCK(s) mtx_lock(&(s)->ks_lock) 81137776Semax#define VKBD_UNLOCK(s) mtx_unlock(&(s)->ks_lock) 82137776Semax#define VKBD_LOCK_ASSERT(s, w) mtx_assert(&(s)->ks_lock, w) 83137776Semax#define VKBD_SLEEP(s, f, d, t) \ 84137776Semax msleep(&(s)->f, &(s)->ks_lock, PCATCH | (PZERO + 1), d, t) 85156057Semax#else 86156057Semax#define VKBD_LOCK_DECL 87156057Semax#define VKBD_LOCK_INIT(s) 88156057Semax#define VKBD_LOCK_DESTROY(s) 89156057Semax#define VKBD_LOCK(s) 90156057Semax#define VKBD_UNLOCK(s) 91156057Semax#define VKBD_LOCK_ASSERT(s, w) 92156057Semax#define VKBD_SLEEP(s, f, d, t) tsleep(&(s)->f, PCATCH | (PZERO + 1), d, t) 93156057Semax#endif 94137776Semax 95137776Semax#define VKBD_KEYBOARD(d) \ 96137776Semax kbd_get_keyboard(kbd_find_keyboard(KEYBOARD_NAME, dev2unit(d))) 97137776Semax 98137776Semax/* vkbd queue */ 99137776Semaxstruct vkbd_queue 100137776Semax{ 101137776Semax int q[VKBD_Q_SIZE]; /* queue */ 102137776Semax int head; /* index of the first code */ 103137776Semax int tail; /* index of the last code */ 104137776Semax int cc; /* number of codes in queue */ 105137776Semax}; 106137776Semax 107137776Semaxtypedef struct vkbd_queue vkbd_queue_t; 108137776Semax 109137776Semax/* vkbd state */ 110137776Semaxstruct vkbd_state 111137776Semax{ 112137776Semax struct cdev *ks_dev; /* control device */ 113137776Semax 114137776Semax struct selinfo ks_rsel; /* select(2) */ 115137776Semax struct selinfo ks_wsel; 116137776Semax 117137776Semax vkbd_queue_t ks_inq; /* input key codes queue */ 118137776Semax struct task ks_task; /* interrupt task */ 119137776Semax 120137776Semax int ks_flags; /* flags */ 121137776Semax#define OPEN (1 << 0) /* control device is open */ 122137776Semax#define COMPOSE (1 << 1) /* compose flag */ 123137776Semax#define STATUS (1 << 2) /* status has changed */ 124137776Semax#define TASK (1 << 3) /* interrupt task queued */ 125137776Semax#define READ (1 << 4) /* read pending */ 126137776Semax#define WRITE (1 << 5) /* write pending */ 127137776Semax 128137776Semax int ks_mode; /* K_XLATE, K_RAW, K_CODE */ 129137776Semax int ks_polling; /* polling flag */ 130137776Semax int ks_state; /* shift/lock key state */ 131137776Semax int ks_accents; /* accent key index (> 0) */ 132137776Semax u_int ks_composed_char; /* composed char code */ 133137776Semax u_char ks_prefix; /* AT scan code prefix */ 134137776Semax 135137776Semax VKBD_LOCK_DECL; 136137776Semax}; 137137776Semax 138137776Semaxtypedef struct vkbd_state vkbd_state_t; 139137776Semax 140137776Semax/***************************************************************************** 141137776Semax ***************************************************************************** 142137776Semax ** Character device 143137776Semax ***************************************************************************** 144137776Semax *****************************************************************************/ 145137776Semax 146148868Srwatsonstatic void vkbd_dev_clone(void *, struct ucred *, char *, int, 147148868Srwatson struct cdev **); 148137776Semaxstatic d_open_t vkbd_dev_open; 149137776Semaxstatic d_close_t vkbd_dev_close; 150137776Semaxstatic d_read_t vkbd_dev_read; 151137776Semaxstatic d_write_t vkbd_dev_write; 152137776Semaxstatic d_ioctl_t vkbd_dev_ioctl; 153137776Semaxstatic d_poll_t vkbd_dev_poll; 154137776Semaxstatic void vkbd_dev_intr(void *, int); 155137776Semaxstatic void vkbd_status_changed(vkbd_state_t *); 156137776Semaxstatic int vkbd_data_ready(vkbd_state_t *); 157137776Semaxstatic int vkbd_data_read(vkbd_state_t *, int); 158137776Semax 159137776Semaxstatic struct cdevsw vkbd_dev_cdevsw = { 160137776Semax .d_version = D_VERSION, 161226500Sed .d_flags = D_NEEDGIANT | D_NEEDMINOR, 162137776Semax .d_open = vkbd_dev_open, 163137776Semax .d_close = vkbd_dev_close, 164137776Semax .d_read = vkbd_dev_read, 165137776Semax .d_write = vkbd_dev_write, 166137776Semax .d_ioctl = vkbd_dev_ioctl, 167137776Semax .d_poll = vkbd_dev_poll, 168137776Semax .d_name = DEVICE_NAME, 169137776Semax}; 170137776Semax 171137776Semaxstatic struct clonedevs *vkbd_dev_clones = NULL; 172137776Semax 173137776Semax/* Clone device */ 174137776Semaxstatic void 175148868Srwatsonvkbd_dev_clone(void *arg, struct ucred *cred, char *name, int namelen, 176148868Srwatson struct cdev **dev) 177137776Semax{ 178137776Semax int unit; 179137776Semax 180137776Semax if (*dev != NULL) 181137776Semax return; 182137776Semax 183137776Semax if (strcmp(name, DEVICE_NAME) == 0) 184137776Semax unit = -1; 185137776Semax else if (dev_stdclone(name, NULL, DEVICE_NAME, &unit) != 1) 186137776Semax return; /* don't recognize the name */ 187137776Semax 188137776Semax /* find any existing device, or allocate new unit number */ 189137776Semax if (clone_create(&vkbd_dev_clones, &vkbd_dev_cdevsw, &unit, dev, 0)) { 190183381Sed *dev = make_dev(&vkbd_dev_cdevsw, unit, 191137776Semax UID_ROOT, GID_WHEEL, 0600, DEVICE_NAME "%d", unit); 192144389Sphk if (*dev != NULL) { 193144389Sphk dev_ref(*dev); 194137776Semax (*dev)->si_flags |= SI_CHEAPCLONE; 195144389Sphk } 196137776Semax } 197137776Semax} 198137776Semax 199137776Semax/* Open device */ 200137776Semaxstatic int 201137776Semaxvkbd_dev_open(struct cdev *dev, int flag, int mode, struct thread *td) 202137776Semax{ 203137776Semax int unit = dev2unit(dev), error; 204137776Semax keyboard_switch_t *sw = NULL; 205137776Semax keyboard_t *kbd = NULL; 206137776Semax vkbd_state_t *state = (vkbd_state_t *) dev->si_drv1; 207137776Semax 208137776Semax /* XXX FIXME: dev->si_drv1 locking */ 209137776Semax if (state == NULL) { 210137776Semax if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) 211137776Semax return (ENXIO); 212137776Semax 213137776Semax if ((error = (*sw->probe)(unit, NULL, 0)) != 0 || 214137776Semax (error = (*sw->init)(unit, &kbd, NULL, 0)) != 0) 215137776Semax return (error); 216137776Semax 217137776Semax state = (vkbd_state_t *) kbd->kb_data; 218137776Semax 219137776Semax if ((error = (*sw->enable)(kbd)) != 0) { 220137776Semax (*sw->term)(kbd); 221137776Semax return (error); 222137776Semax } 223137776Semax 224137776Semax#ifdef KBD_INSTALL_CDEV 225137776Semax if ((error = kbd_attach(kbd)) != 0) { 226137776Semax (*sw->disable)(kbd); 227137776Semax (*sw->term)(kbd); 228137776Semax return (error); 229137776Semax } 230137776Semax#endif /* def KBD_INSTALL_CDEV */ 231137776Semax 232137776Semax dev->si_drv1 = kbd->kb_data; 233137776Semax } 234137776Semax 235137776Semax VKBD_LOCK(state); 236137776Semax 237137776Semax if (state->ks_flags & OPEN) { 238137776Semax VKBD_UNLOCK(state); 239137776Semax return (EBUSY); 240137776Semax } 241137776Semax 242137776Semax state->ks_flags |= OPEN; 243137776Semax state->ks_dev = dev; 244137776Semax 245137776Semax VKBD_UNLOCK(state); 246137776Semax 247137776Semax return (0); 248137776Semax} 249137776Semax 250137776Semax/* Close device */ 251137776Semaxstatic int 252137776Semaxvkbd_dev_close(struct cdev *dev, int foo, int bar, struct thread *td) 253137776Semax{ 254137776Semax keyboard_t *kbd = VKBD_KEYBOARD(dev); 255137776Semax vkbd_state_t *state = NULL; 256137776Semax 257137776Semax if (kbd == NULL) 258137776Semax return (ENXIO); 259137776Semax 260137776Semax if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1) 261137776Semax panic("%s: kbd->kb_data != dev->si_drv1\n", __func__); 262137776Semax 263137776Semax state = (vkbd_state_t *) kbd->kb_data; 264137776Semax 265137776Semax VKBD_LOCK(state); 266137776Semax 267137776Semax /* wait for interrupt task */ 268137776Semax while (state->ks_flags & TASK) 269137776Semax VKBD_SLEEP(state, ks_task, "vkbdc", 0); 270137776Semax 271137776Semax /* wakeup poll()ers */ 272137776Semax selwakeuppri(&state->ks_rsel, PZERO + 1); 273137776Semax selwakeuppri(&state->ks_wsel, PZERO + 1); 274137776Semax 275137776Semax state->ks_flags &= ~OPEN; 276137776Semax state->ks_dev = NULL; 277137776Semax state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0; 278137776Semax 279137776Semax VKBD_UNLOCK(state); 280137776Semax 281174984Swkoszek kbdd_disable(kbd); 282137776Semax#ifdef KBD_INSTALL_CDEV 283137776Semax kbd_detach(kbd); 284137776Semax#endif /* def KBD_INSTALL_CDEV */ 285174984Swkoszek kbdd_term(kbd); 286137776Semax 287137776Semax /* XXX FIXME: dev->si_drv1 locking */ 288137776Semax dev->si_drv1 = NULL; 289137776Semax 290137776Semax return (0); 291137776Semax} 292137776Semax 293137776Semax/* Read status */ 294137776Semaxstatic int 295137776Semaxvkbd_dev_read(struct cdev *dev, struct uio *uio, int flag) 296137776Semax{ 297137776Semax keyboard_t *kbd = VKBD_KEYBOARD(dev); 298137776Semax vkbd_state_t *state = NULL; 299137776Semax vkbd_status_t status; 300137776Semax int error; 301137776Semax 302137776Semax if (kbd == NULL) 303137776Semax return (ENXIO); 304137776Semax 305137776Semax if (uio->uio_resid != sizeof(status)) 306137776Semax return (EINVAL); 307137776Semax 308137776Semax if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1) 309137776Semax panic("%s: kbd->kb_data != dev->si_drv1\n", __func__); 310137776Semax 311137776Semax state = (vkbd_state_t *) kbd->kb_data; 312137776Semax 313137776Semax VKBD_LOCK(state); 314137776Semax 315137776Semax if (state->ks_flags & READ) { 316137776Semax VKBD_UNLOCK(state); 317137776Semax return (EALREADY); 318137776Semax } 319137776Semax 320137776Semax state->ks_flags |= READ; 321137776Semaxagain: 322137776Semax if (state->ks_flags & STATUS) { 323137776Semax state->ks_flags &= ~STATUS; 324137776Semax 325137776Semax status.mode = state->ks_mode; 326137776Semax status.leds = KBD_LED_VAL(kbd); 327137776Semax status.lock = state->ks_state & LOCK_MASK; 328137776Semax status.delay = kbd->kb_delay1; 329137776Semax status.rate = kbd->kb_delay2; 330137776Semax bzero(status.reserved, sizeof(status.reserved)); 331137776Semax 332137776Semax error = uiomove(&status, sizeof(status), uio); 333137776Semax } else { 334139204Sphk if (flag & O_NONBLOCK) { 335137776Semax error = EWOULDBLOCK; 336137776Semax goto done; 337137776Semax } 338137776Semax 339137776Semax error = VKBD_SLEEP(state, ks_flags, "vkbdr", 0); 340137776Semax if (error != 0) 341137776Semax goto done; 342137776Semax 343137776Semax goto again; 344137776Semax } 345137776Semaxdone: 346137776Semax state->ks_flags &= ~READ; 347137776Semax 348137776Semax VKBD_UNLOCK(state); 349137776Semax 350137776Semax return (error); 351137776Semax} 352137776Semax 353137776Semax/* Write scancodes */ 354137776Semaxstatic int 355137776Semaxvkbd_dev_write(struct cdev *dev, struct uio *uio, int flag) 356137776Semax{ 357137776Semax keyboard_t *kbd = VKBD_KEYBOARD(dev); 358137776Semax vkbd_state_t *state = NULL; 359137776Semax vkbd_queue_t *q = NULL; 360137776Semax int error, avail, bytes; 361137776Semax 362137776Semax if (kbd == NULL) 363137776Semax return (ENXIO); 364137776Semax 365137776Semax if (uio->uio_resid <= 0) 366137776Semax return (EINVAL); 367137776Semax 368137776Semax if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1) 369137776Semax panic("%s: kbd->kb_data != dev->si_drv1\n", __func__); 370137776Semax 371137776Semax state = (vkbd_state_t *) kbd->kb_data; 372137776Semax 373137776Semax VKBD_LOCK(state); 374137776Semax 375137776Semax if (state->ks_flags & WRITE) { 376137776Semax VKBD_UNLOCK(state); 377137776Semax return (EALREADY); 378137776Semax } 379137776Semax 380137776Semax state->ks_flags |= WRITE; 381137776Semax error = 0; 382137776Semax q = &state->ks_inq; 383137776Semax 384137776Semax while (uio->uio_resid >= sizeof(q->q[0])) { 385137776Semax if (q->head == q->tail) { 386137776Semax if (q->cc == 0) 387137776Semax avail = sizeof(q->q)/sizeof(q->q[0]) - q->head; 388137776Semax else 389137776Semax avail = 0; /* queue must be full */ 390137776Semax } else if (q->head < q->tail) 391137776Semax avail = sizeof(q->q)/sizeof(q->q[0]) - q->tail; 392137776Semax else 393137776Semax avail = q->head - q->tail; 394137776Semax 395137776Semax if (avail == 0) { 396139204Sphk if (flag & O_NONBLOCK) { 397137776Semax error = EWOULDBLOCK; 398137776Semax break; 399137776Semax } 400137776Semax 401137776Semax error = VKBD_SLEEP(state, ks_inq, "vkbdw", 0); 402137776Semax if (error != 0) 403137776Semax break; 404137776Semax } else { 405137776Semax bytes = avail * sizeof(q->q[0]); 406137776Semax if (bytes > uio->uio_resid) { 407137776Semax avail = uio->uio_resid / sizeof(q->q[0]); 408137776Semax bytes = avail * sizeof(q->q[0]); 409137776Semax } 410137776Semax 411137776Semax error = uiomove((void *) &q->q[q->tail], bytes, uio); 412137776Semax if (error != 0) 413137776Semax break; 414137776Semax 415137776Semax q->cc += avail; 416137776Semax q->tail += avail; 417137776Semax if (q->tail == sizeof(q->q)/sizeof(q->q[0])) 418137776Semax q->tail = 0; 419137776Semax 420137776Semax /* queue interrupt task if needed */ 421137776Semax if (!(state->ks_flags & TASK) && 422137776Semax taskqueue_enqueue(taskqueue_swi_giant, &state->ks_task) == 0) 423137776Semax state->ks_flags |= TASK; 424137776Semax } 425137776Semax } 426137776Semax 427137776Semax state->ks_flags &= ~WRITE; 428137776Semax 429137776Semax VKBD_UNLOCK(state); 430137776Semax 431137776Semax return (error); 432137776Semax} 433137776Semax 434137776Semax/* Process ioctl */ 435137776Semaxstatic int 436137776Semaxvkbd_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 437137776Semax{ 438137776Semax keyboard_t *kbd = VKBD_KEYBOARD(dev); 439137776Semax 440174984Swkoszek return ((kbd == NULL)? ENXIO : kbdd_ioctl(kbd, cmd, data)); 441137776Semax} 442137776Semax 443137776Semax/* Poll device */ 444137776Semaxstatic int 445137776Semaxvkbd_dev_poll(struct cdev *dev, int events, struct thread *td) 446137776Semax{ 447137776Semax vkbd_state_t *state = (vkbd_state_t *) dev->si_drv1; 448137776Semax vkbd_queue_t *q = NULL; 449137776Semax int revents = 0; 450137776Semax 451137776Semax if (state == NULL) 452137776Semax return (ENXIO); 453137776Semax 454137776Semax VKBD_LOCK(state); 455137776Semax 456137776Semax q = &state->ks_inq; 457137776Semax 458137776Semax if (events & (POLLIN | POLLRDNORM)) { 459137776Semax if (state->ks_flags & STATUS) 460137776Semax revents |= events & (POLLIN | POLLRDNORM); 461137776Semax else 462137776Semax selrecord(td, &state->ks_rsel); 463137776Semax } 464137776Semax 465137776Semax if (events & (POLLOUT | POLLWRNORM)) { 466137776Semax if (q->cc < sizeof(q->q)/sizeof(q->q[0])) 467137776Semax revents |= events & (POLLOUT | POLLWRNORM); 468137776Semax else 469137776Semax selrecord(td, &state->ks_wsel); 470137776Semax } 471137776Semax 472137776Semax VKBD_UNLOCK(state); 473137776Semax 474137776Semax return (revents); 475137776Semax} 476137776Semax 477137776Semax/* Interrupt handler */ 478137776Semaxvoid 479137776Semaxvkbd_dev_intr(void *xkbd, int pending) 480137776Semax{ 481137776Semax keyboard_t *kbd = (keyboard_t *) xkbd; 482137776Semax vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data; 483137776Semax 484174984Swkoszek kbdd_intr(kbd, NULL); 485137776Semax 486137776Semax VKBD_LOCK(state); 487137776Semax 488137776Semax state->ks_flags &= ~TASK; 489137776Semax wakeup(&state->ks_task); 490137776Semax 491137776Semax VKBD_UNLOCK(state); 492137776Semax} 493137776Semax 494137776Semax/* Set status change flags */ 495137776Semaxstatic void 496137776Semaxvkbd_status_changed(vkbd_state_t *state) 497137776Semax{ 498137776Semax VKBD_LOCK_ASSERT(state, MA_OWNED); 499137776Semax 500137776Semax if (!(state->ks_flags & STATUS)) { 501137776Semax state->ks_flags |= STATUS; 502137776Semax selwakeuppri(&state->ks_rsel, PZERO + 1); 503137776Semax wakeup(&state->ks_flags); 504137776Semax } 505137776Semax} 506137776Semax 507137776Semax/* Check if we have data in the input queue */ 508137776Semaxstatic int 509137776Semaxvkbd_data_ready(vkbd_state_t *state) 510137776Semax{ 511137776Semax VKBD_LOCK_ASSERT(state, MA_OWNED); 512137776Semax 513137776Semax return (state->ks_inq.cc > 0); 514137776Semax} 515137776Semax 516137776Semax/* Read one code from the input queue */ 517137776Semaxstatic int 518137776Semaxvkbd_data_read(vkbd_state_t *state, int wait) 519137776Semax{ 520137776Semax vkbd_queue_t *q = &state->ks_inq; 521137776Semax int c; 522137776Semax 523137776Semax VKBD_LOCK_ASSERT(state, MA_OWNED); 524137776Semax 525137776Semax if (q->cc == 0) 526137776Semax return (-1); 527137776Semax 528137776Semax /* get first code from the queue */ 529137776Semax q->cc --; 530137776Semax c = q->q[q->head ++]; 531137776Semax if (q->head == sizeof(q->q)/sizeof(q->q[0])) 532137776Semax q->head = 0; 533137776Semax 534137776Semax /* wakeup ks_inq writers/poll()ers */ 535137776Semax selwakeuppri(&state->ks_wsel, PZERO + 1); 536137776Semax wakeup(q); 537137776Semax 538137776Semax return (c); 539137776Semax} 540137776Semax 541137776Semax/**************************************************************************** 542137776Semax **************************************************************************** 543137776Semax ** Keyboard driver 544137776Semax **************************************************************************** 545137776Semax ****************************************************************************/ 546137776Semax 547137776Semaxstatic int vkbd_configure(int flags); 548137776Semaxstatic kbd_probe_t vkbd_probe; 549137776Semaxstatic kbd_init_t vkbd_init; 550137776Semaxstatic kbd_term_t vkbd_term; 551137776Semaxstatic kbd_intr_t vkbd_intr; 552137776Semaxstatic kbd_test_if_t vkbd_test_if; 553137776Semaxstatic kbd_enable_t vkbd_enable; 554137776Semaxstatic kbd_disable_t vkbd_disable; 555137776Semaxstatic kbd_read_t vkbd_read; 556137776Semaxstatic kbd_check_t vkbd_check; 557137776Semaxstatic kbd_read_char_t vkbd_read_char; 558137776Semaxstatic kbd_check_char_t vkbd_check_char; 559137776Semaxstatic kbd_ioctl_t vkbd_ioctl; 560137776Semaxstatic kbd_lock_t vkbd_lock; 561137776Semaxstatic void vkbd_clear_state_locked(vkbd_state_t *state); 562137776Semaxstatic kbd_clear_state_t vkbd_clear_state; 563137776Semaxstatic kbd_get_state_t vkbd_get_state; 564137776Semaxstatic kbd_set_state_t vkbd_set_state; 565137776Semaxstatic kbd_poll_mode_t vkbd_poll; 566137776Semax 567137776Semaxstatic keyboard_switch_t vkbdsw = { 568137776Semax .probe = vkbd_probe, 569137776Semax .init = vkbd_init, 570137776Semax .term = vkbd_term, 571137776Semax .intr = vkbd_intr, 572137776Semax .test_if = vkbd_test_if, 573137776Semax .enable = vkbd_enable, 574137776Semax .disable = vkbd_disable, 575137776Semax .read = vkbd_read, 576137776Semax .check = vkbd_check, 577137776Semax .read_char = vkbd_read_char, 578137776Semax .check_char = vkbd_check_char, 579137776Semax .ioctl = vkbd_ioctl, 580137776Semax .lock = vkbd_lock, 581137776Semax .clear_state = vkbd_clear_state, 582137776Semax .get_state = vkbd_get_state, 583137776Semax .set_state = vkbd_set_state, 584137776Semax .get_fkeystr = genkbd_get_fkeystr, 585137776Semax .poll = vkbd_poll, 586137776Semax .diag = genkbd_diag, 587137776Semax}; 588137776Semax 589137776Semaxstatic int typematic(int delay, int rate); 590137776Semaxstatic int typematic_delay(int delay); 591137776Semaxstatic int typematic_rate(int rate); 592137776Semax 593137776Semax/* Return the number of found keyboards */ 594137776Semaxstatic int 595137776Semaxvkbd_configure(int flags) 596137776Semax{ 597137776Semax return (1); 598137776Semax} 599137776Semax 600137776Semax/* Detect a keyboard */ 601137776Semaxstatic int 602137776Semaxvkbd_probe(int unit, void *arg, int flags) 603137776Semax{ 604137776Semax return (0); 605137776Semax} 606137776Semax 607137776Semax/* Reset and initialize the keyboard (stolen from atkbd.c) */ 608137776Semaxstatic int 609137776Semaxvkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 610137776Semax{ 611137776Semax keyboard_t *kbd = NULL; 612137776Semax vkbd_state_t *state = NULL; 613137776Semax keymap_t *keymap = NULL; 614137776Semax accentmap_t *accmap = NULL; 615137776Semax fkeytab_t *fkeymap = NULL; 616137776Semax int fkeymap_size, delay[2]; 617142417Ssam int error, needfree; 618137776Semax 619137776Semax if (*kbdp == NULL) { 620137776Semax *kbdp = kbd = malloc(sizeof(*kbd), M_VKBD, M_NOWAIT | M_ZERO); 621137776Semax state = malloc(sizeof(*state), M_VKBD, M_NOWAIT | M_ZERO); 622137776Semax keymap = malloc(sizeof(key_map), M_VKBD, M_NOWAIT); 623137776Semax accmap = malloc(sizeof(accent_map), M_VKBD, M_NOWAIT); 624137776Semax fkeymap = malloc(sizeof(fkey_tab), M_VKBD, M_NOWAIT); 625137776Semax fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); 626142417Ssam needfree = 1; 627137776Semax if ((kbd == NULL) || (state == NULL) || (keymap == NULL) || 628137776Semax (accmap == NULL) || (fkeymap == NULL)) { 629142417Ssam error = ENOMEM; 630142417Ssam goto bad; 631137776Semax } 632137776Semax 633137776Semax VKBD_LOCK_INIT(state); 634137776Semax state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0; 635137776Semax TASK_INIT(&state->ks_task, 0, vkbd_dev_intr, (void *) kbd); 636137776Semax } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { 637137776Semax return (0); 638137776Semax } else { 639137776Semax kbd = *kbdp; 640137776Semax state = (vkbd_state_t *) kbd->kb_data; 641137776Semax keymap = kbd->kb_keymap; 642137776Semax accmap = kbd->kb_accentmap; 643137776Semax fkeymap = kbd->kb_fkeytab; 644137776Semax fkeymap_size = kbd->kb_fkeytab_size; 645142417Ssam needfree = 0; 646137776Semax } 647137776Semax 648137776Semax if (!KBD_IS_PROBED(kbd)) { 649137776Semax kbd_init_struct(kbd, KEYBOARD_NAME, KB_OTHER, unit, flags, 0, 0); 650137776Semax bcopy(&key_map, keymap, sizeof(key_map)); 651137776Semax bcopy(&accent_map, accmap, sizeof(accent_map)); 652137776Semax bcopy(fkey_tab, fkeymap, 653137776Semax imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 654137776Semax kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 655137776Semax kbd->kb_data = (void *)state; 656137776Semax 657137776Semax KBD_FOUND_DEVICE(kbd); 658137776Semax KBD_PROBE_DONE(kbd); 659137776Semax 660137776Semax VKBD_LOCK(state); 661137776Semax vkbd_clear_state_locked(state); 662137776Semax state->ks_mode = K_XLATE; 663137776Semax /* FIXME: set the initial value for lock keys in ks_state */ 664137776Semax VKBD_UNLOCK(state); 665137776Semax } 666137776Semax if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 667137776Semax kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; 668137776Semax 669137776Semax vkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 670137776Semax delay[0] = kbd->kb_delay1; 671137776Semax delay[1] = kbd->kb_delay2; 672137776Semax vkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); 673137776Semax 674137776Semax KBD_INIT_DONE(kbd); 675137776Semax } 676137776Semax if (!KBD_IS_CONFIGURED(kbd)) { 677142417Ssam if (kbd_register(kbd) < 0) { 678142417Ssam error = ENXIO; 679142417Ssam goto bad; 680142417Ssam } 681137776Semax KBD_CONFIG_DONE(kbd); 682137776Semax } 683137776Semax 684137776Semax return (0); 685142417Ssambad: 686142417Ssam if (needfree) { 687142417Ssam if (state != NULL) 688142417Ssam free(state, M_VKBD); 689142417Ssam if (keymap != NULL) 690142417Ssam free(keymap, M_VKBD); 691142417Ssam if (accmap != NULL) 692142417Ssam free(accmap, M_VKBD); 693142417Ssam if (fkeymap != NULL) 694142417Ssam free(fkeymap, M_VKBD); 695142417Ssam if (kbd != NULL) { 696146460Semax free(kbd, M_VKBD); 697142417Ssam *kbdp = NULL; /* insure ref doesn't leak to caller */ 698142417Ssam } 699142417Ssam } 700142417Ssam return (error); 701137776Semax} 702137776Semax 703137776Semax/* Finish using this keyboard */ 704137776Semaxstatic int 705137776Semaxvkbd_term(keyboard_t *kbd) 706137776Semax{ 707137776Semax vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data; 708137776Semax 709137776Semax kbd_unregister(kbd); 710137776Semax 711137776Semax VKBD_LOCK_DESTROY(state); 712137776Semax bzero(state, sizeof(*state)); 713137776Semax free(state, M_VKBD); 714137776Semax 715137776Semax free(kbd->kb_keymap, M_VKBD); 716137776Semax free(kbd->kb_accentmap, M_VKBD); 717137776Semax free(kbd->kb_fkeytab, M_VKBD); 718137776Semax free(kbd, M_VKBD); 719137776Semax 720137776Semax return (0); 721137776Semax} 722137776Semax 723137776Semax/* Keyboard interrupt routine */ 724137776Semaxstatic int 725137776Semaxvkbd_intr(keyboard_t *kbd, void *arg) 726137776Semax{ 727137776Semax int c; 728137776Semax 729137776Semax if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 730137776Semax /* let the callback function to process the input */ 731137776Semax (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 732137776Semax kbd->kb_callback.kc_arg); 733137776Semax } else { 734137776Semax /* read and discard the input; no one is waiting for input */ 735137776Semax do { 736137776Semax c = vkbd_read_char(kbd, FALSE); 737137776Semax } while (c != NOKEY); 738137776Semax } 739137776Semax 740137776Semax return (0); 741137776Semax} 742137776Semax 743137776Semax/* Test the interface to the device */ 744137776Semaxstatic int 745137776Semaxvkbd_test_if(keyboard_t *kbd) 746137776Semax{ 747137776Semax return (0); 748137776Semax} 749137776Semax 750137776Semax/* 751137776Semax * Enable the access to the device; until this function is called, 752137776Semax * the client cannot read from the keyboard. 753137776Semax */ 754137776Semax 755137776Semaxstatic int 756137776Semaxvkbd_enable(keyboard_t *kbd) 757137776Semax{ 758137776Semax KBD_ACTIVATE(kbd); 759137776Semax return (0); 760137776Semax} 761137776Semax 762137776Semax/* Disallow the access to the device */ 763137776Semaxstatic int 764137776Semaxvkbd_disable(keyboard_t *kbd) 765137776Semax{ 766137776Semax KBD_DEACTIVATE(kbd); 767137776Semax return (0); 768137776Semax} 769137776Semax 770137776Semax/* Read one byte from the keyboard if it's allowed */ 771137776Semaxstatic int 772137776Semaxvkbd_read(keyboard_t *kbd, int wait) 773137776Semax{ 774137776Semax vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data; 775137776Semax int c; 776137776Semax 777137776Semax VKBD_LOCK(state); 778137776Semax c = vkbd_data_read(state, wait); 779137776Semax VKBD_UNLOCK(state); 780137776Semax 781137776Semax if (c != -1) 782137776Semax kbd->kb_count ++; 783137776Semax 784137776Semax return (KBD_IS_ACTIVE(kbd)? c : -1); 785137776Semax} 786137776Semax 787137776Semax/* Check if data is waiting */ 788137776Semaxstatic int 789137776Semaxvkbd_check(keyboard_t *kbd) 790137776Semax{ 791137776Semax vkbd_state_t *state = NULL; 792137776Semax int ready; 793137776Semax 794137776Semax if (!KBD_IS_ACTIVE(kbd)) 795137776Semax return (FALSE); 796137776Semax 797137776Semax state = (vkbd_state_t *) kbd->kb_data; 798137776Semax 799137776Semax VKBD_LOCK(state); 800137776Semax ready = vkbd_data_ready(state); 801137776Semax VKBD_UNLOCK(state); 802137776Semax 803137776Semax return (ready); 804137776Semax} 805137776Semax 806137776Semax/* Read char from the keyboard (stolen from atkbd.c) */ 807137776Semaxstatic u_int 808137776Semaxvkbd_read_char(keyboard_t *kbd, int wait) 809137776Semax{ 810137776Semax vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data; 811137776Semax u_int action; 812137776Semax int scancode, keycode; 813137776Semax 814137776Semax VKBD_LOCK(state); 815137776Semax 816137776Semaxnext_code: 817137776Semax 818137776Semax /* do we have a composed char to return? */ 819137776Semax if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 820137776Semax action = state->ks_composed_char; 821137776Semax state->ks_composed_char = 0; 822137776Semax if (action > UCHAR_MAX) { 823137776Semax VKBD_UNLOCK(state); 824137776Semax return (ERRKEY); 825137776Semax } 826137776Semax 827137776Semax VKBD_UNLOCK(state); 828137776Semax return (action); 829137776Semax } 830137776Semax 831137776Semax /* see if there is something in the keyboard port */ 832137776Semax scancode = vkbd_data_read(state, wait); 833137776Semax if (scancode == -1) { 834137776Semax VKBD_UNLOCK(state); 835137776Semax return (NOKEY); 836137776Semax } 837137776Semax /* XXX FIXME: check for -1 if wait == 1! */ 838137776Semax 839137776Semax kbd->kb_count ++; 840137776Semax 841137776Semax /* return the byte as is for the K_RAW mode */ 842137776Semax if (state->ks_mode == K_RAW) { 843137776Semax VKBD_UNLOCK(state); 844137776Semax return (scancode); 845137776Semax } 846137776Semax 847137776Semax /* translate the scan code into a keycode */ 848137776Semax keycode = scancode & 0x7F; 849137776Semax switch (state->ks_prefix) { 850137776Semax case 0x00: /* normal scancode */ 851137776Semax switch(scancode) { 852137776Semax case 0xB8: /* left alt (compose key) released */ 853137776Semax if (state->ks_flags & COMPOSE) { 854137776Semax state->ks_flags &= ~COMPOSE; 855137776Semax if (state->ks_composed_char > UCHAR_MAX) 856137776Semax state->ks_composed_char = 0; 857137776Semax } 858137776Semax break; 859137776Semax case 0x38: /* left alt (compose key) pressed */ 860137776Semax if (!(state->ks_flags & COMPOSE)) { 861137776Semax state->ks_flags |= COMPOSE; 862137776Semax state->ks_composed_char = 0; 863137776Semax } 864137776Semax break; 865137776Semax case 0xE0: 866137776Semax case 0xE1: 867137776Semax state->ks_prefix = scancode; 868137776Semax goto next_code; 869137776Semax } 870137776Semax break; 871137776Semax case 0xE0: /* 0xE0 prefix */ 872137776Semax state->ks_prefix = 0; 873137776Semax switch (keycode) { 874137776Semax case 0x1C: /* right enter key */ 875137776Semax keycode = 0x59; 876137776Semax break; 877137776Semax case 0x1D: /* right ctrl key */ 878137776Semax keycode = 0x5A; 879137776Semax break; 880137776Semax case 0x35: /* keypad divide key */ 881137776Semax keycode = 0x5B; 882137776Semax break; 883137776Semax case 0x37: /* print scrn key */ 884137776Semax keycode = 0x5C; 885137776Semax break; 886137776Semax case 0x38: /* right alt key (alt gr) */ 887137776Semax keycode = 0x5D; 888137776Semax break; 889137776Semax case 0x46: /* ctrl-pause/break on AT 101 (see below) */ 890137776Semax keycode = 0x68; 891137776Semax break; 892137776Semax case 0x47: /* grey home key */ 893137776Semax keycode = 0x5E; 894137776Semax break; 895137776Semax case 0x48: /* grey up arrow key */ 896137776Semax keycode = 0x5F; 897137776Semax break; 898137776Semax case 0x49: /* grey page up key */ 899137776Semax keycode = 0x60; 900137776Semax break; 901137776Semax case 0x4B: /* grey left arrow key */ 902137776Semax keycode = 0x61; 903137776Semax break; 904137776Semax case 0x4D: /* grey right arrow key */ 905137776Semax keycode = 0x62; 906137776Semax break; 907137776Semax case 0x4F: /* grey end key */ 908137776Semax keycode = 0x63; 909137776Semax break; 910137776Semax case 0x50: /* grey down arrow key */ 911137776Semax keycode = 0x64; 912137776Semax break; 913137776Semax case 0x51: /* grey page down key */ 914137776Semax keycode = 0x65; 915137776Semax break; 916137776Semax case 0x52: /* grey insert key */ 917137776Semax keycode = 0x66; 918137776Semax break; 919137776Semax case 0x53: /* grey delete key */ 920137776Semax keycode = 0x67; 921137776Semax break; 922137776Semax /* the following 3 are only used on the MS "Natural" keyboard */ 923137776Semax case 0x5b: /* left Window key */ 924137776Semax keycode = 0x69; 925137776Semax break; 926137776Semax case 0x5c: /* right Window key */ 927137776Semax keycode = 0x6a; 928137776Semax break; 929137776Semax case 0x5d: /* menu key */ 930137776Semax keycode = 0x6b; 931137776Semax break; 932137776Semax case 0x5e: /* power key */ 933137776Semax keycode = 0x6d; 934137776Semax break; 935137776Semax case 0x5f: /* sleep key */ 936137776Semax keycode = 0x6e; 937137776Semax break; 938137776Semax case 0x63: /* wake key */ 939137776Semax keycode = 0x6f; 940137776Semax break; 941137776Semax default: /* ignore everything else */ 942137776Semax goto next_code; 943137776Semax } 944137776Semax break; 945137776Semax case 0xE1: /* 0xE1 prefix */ 946137776Semax /* 947137776Semax * The pause/break key on the 101 keyboard produces: 948137776Semax * E1-1D-45 E1-9D-C5 949137776Semax * Ctrl-pause/break produces: 950137776Semax * E0-46 E0-C6 (See above.) 951137776Semax */ 952137776Semax state->ks_prefix = 0; 953137776Semax if (keycode == 0x1D) 954137776Semax state->ks_prefix = 0x1D; 955137776Semax goto next_code; 956137776Semax /* NOT REACHED */ 957137776Semax case 0x1D: /* pause / break */ 958137776Semax state->ks_prefix = 0; 959137776Semax if (keycode != 0x45) 960137776Semax goto next_code; 961137776Semax keycode = 0x68; 962137776Semax break; 963137776Semax } 964137776Semax 965137776Semax if (kbd->kb_type == KB_84) { 966137776Semax switch (keycode) { 967137776Semax case 0x37: /* *(numpad)/print screen */ 968137776Semax if (state->ks_flags & SHIFTS) 969137776Semax keycode = 0x5c; /* print screen */ 970137776Semax break; 971137776Semax case 0x45: /* num lock/pause */ 972137776Semax if (state->ks_flags & CTLS) 973137776Semax keycode = 0x68; /* pause */ 974137776Semax break; 975137776Semax case 0x46: /* scroll lock/break */ 976137776Semax if (state->ks_flags & CTLS) 977137776Semax keycode = 0x6c; /* break */ 978137776Semax break; 979137776Semax } 980137776Semax } else if (kbd->kb_type == KB_101) { 981137776Semax switch (keycode) { 982137776Semax case 0x5c: /* print screen */ 983137776Semax if (state->ks_flags & ALTS) 984137776Semax keycode = 0x54; /* sysrq */ 985137776Semax break; 986137776Semax case 0x68: /* pause/break */ 987137776Semax if (state->ks_flags & CTLS) 988137776Semax keycode = 0x6c; /* break */ 989137776Semax break; 990137776Semax } 991137776Semax } 992137776Semax 993137776Semax /* return the key code in the K_CODE mode */ 994137776Semax if (state->ks_mode == K_CODE) { 995137776Semax VKBD_UNLOCK(state); 996137776Semax return (keycode | (scancode & 0x80)); 997137776Semax } 998137776Semax 999137776Semax /* compose a character code */ 1000137776Semax if (state->ks_flags & COMPOSE) { 1001137776Semax switch (keycode | (scancode & 0x80)) { 1002137776Semax /* key pressed, process it */ 1003137776Semax case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 1004137776Semax state->ks_composed_char *= 10; 1005137776Semax state->ks_composed_char += keycode - 0x40; 1006137776Semax if (state->ks_composed_char > UCHAR_MAX) { 1007137776Semax VKBD_UNLOCK(state); 1008137776Semax return (ERRKEY); 1009137776Semax } 1010137776Semax goto next_code; 1011137776Semax case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 1012137776Semax state->ks_composed_char *= 10; 1013137776Semax state->ks_composed_char += keycode - 0x47; 1014137776Semax if (state->ks_composed_char > UCHAR_MAX) { 1015137776Semax VKBD_UNLOCK(state); 1016137776Semax return (ERRKEY); 1017137776Semax } 1018137776Semax goto next_code; 1019137776Semax case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 1020137776Semax state->ks_composed_char *= 10; 1021137776Semax state->ks_composed_char += keycode - 0x4E; 1022137776Semax if (state->ks_composed_char > UCHAR_MAX) { 1023137776Semax VKBD_UNLOCK(state); 1024137776Semax return (ERRKEY); 1025137776Semax } 1026137776Semax goto next_code; 1027137776Semax case 0x52: /* keypad 0 */ 1028137776Semax state->ks_composed_char *= 10; 1029137776Semax if (state->ks_composed_char > UCHAR_MAX) { 1030137776Semax VKBD_UNLOCK(state); 1031137776Semax return (ERRKEY); 1032137776Semax } 1033137776Semax goto next_code; 1034137776Semax 1035137776Semax /* key released, no interest here */ 1036137776Semax case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 1037137776Semax case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 1038137776Semax case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 1039137776Semax case 0xD2: /* keypad 0 */ 1040137776Semax goto next_code; 1041137776Semax 1042137776Semax case 0x38: /* left alt key */ 1043137776Semax break; 1044137776Semax 1045137776Semax default: 1046137776Semax if (state->ks_composed_char > 0) { 1047137776Semax state->ks_flags &= ~COMPOSE; 1048137776Semax state->ks_composed_char = 0; 1049137776Semax VKBD_UNLOCK(state); 1050137776Semax return (ERRKEY); 1051137776Semax } 1052137776Semax break; 1053137776Semax } 1054137776Semax } 1055137776Semax 1056137776Semax /* keycode to key action */ 1057137776Semax action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 1058137776Semax &state->ks_state, &state->ks_accents); 1059137776Semax if (action == NOKEY) 1060137776Semax goto next_code; 1061137776Semax 1062137776Semax VKBD_UNLOCK(state); 1063137776Semax 1064137776Semax return (action); 1065137776Semax} 1066137776Semax 1067137776Semax/* Check if char is waiting */ 1068137776Semaxstatic int 1069137776Semaxvkbd_check_char(keyboard_t *kbd) 1070137776Semax{ 1071137776Semax vkbd_state_t *state = NULL; 1072137776Semax int ready; 1073137776Semax 1074137776Semax if (!KBD_IS_ACTIVE(kbd)) 1075137776Semax return (FALSE); 1076137776Semax 1077137776Semax state = (vkbd_state_t *) kbd->kb_data; 1078137776Semax 1079137776Semax VKBD_LOCK(state); 1080137776Semax if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) 1081137776Semax ready = TRUE; 1082137776Semax else 1083137776Semax ready = vkbd_data_ready(state); 1084137776Semax VKBD_UNLOCK(state); 1085137776Semax 1086137776Semax return (ready); 1087137776Semax} 1088137776Semax 1089137776Semax/* Some useful control functions (stolen from atkbd.c) */ 1090137776Semaxstatic int 1091137776Semaxvkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 1092137776Semax{ 1093137776Semax vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data; 1094137776Semax int i; 1095162711Sru#ifdef COMPAT_FREEBSD6 1096162711Sru int ival; 1097162711Sru#endif 1098137776Semax 1099137776Semax VKBD_LOCK(state); 1100137776Semax 1101137776Semax switch (cmd) { 1102137776Semax case KDGKBMODE: /* get keyboard mode */ 1103137776Semax *(int *)arg = state->ks_mode; 1104137776Semax break; 1105137776Semax 1106162711Sru#ifdef COMPAT_FREEBSD6 1107162711Sru case _IO('K', 7): 1108162711Sru ival = IOCPARM_IVAL(arg); 1109162711Sru arg = (caddr_t)&ival; 1110162711Sru /* FALLTHROUGH */ 1111162711Sru#endif 1112137776Semax case KDSKBMODE: /* set keyboard mode */ 1113137776Semax switch (*(int *)arg) { 1114137776Semax case K_XLATE: 1115137776Semax if (state->ks_mode != K_XLATE) { 1116137776Semax /* make lock key state and LED state match */ 1117137776Semax state->ks_state &= ~LOCK_MASK; 1118137776Semax state->ks_state |= KBD_LED_VAL(kbd); 1119137776Semax vkbd_status_changed(state); 1120137776Semax } 1121137776Semax /* FALLTHROUGH */ 1122137776Semax 1123137776Semax case K_RAW: 1124137776Semax case K_CODE: 1125137776Semax if (state->ks_mode != *(int *)arg) { 1126137776Semax vkbd_clear_state_locked(state); 1127137776Semax state->ks_mode = *(int *)arg; 1128137776Semax vkbd_status_changed(state); 1129137776Semax } 1130137776Semax break; 1131137776Semax 1132137776Semax default: 1133137776Semax VKBD_UNLOCK(state); 1134137776Semax return (EINVAL); 1135137776Semax } 1136137776Semax break; 1137137776Semax 1138137776Semax case KDGETLED: /* get keyboard LED */ 1139137776Semax *(int *)arg = KBD_LED_VAL(kbd); 1140137776Semax break; 1141137776Semax 1142162711Sru#ifdef COMPAT_FREEBSD6 1143162711Sru case _IO('K', 66): 1144162711Sru ival = IOCPARM_IVAL(arg); 1145162711Sru arg = (caddr_t)&ival; 1146162711Sru /* FALLTHROUGH */ 1147162711Sru#endif 1148137776Semax case KDSETLED: /* set keyboard LED */ 1149137776Semax /* NOTE: lock key state in ks_state won't be changed */ 1150137776Semax if (*(int *)arg & ~LOCK_MASK) { 1151137776Semax VKBD_UNLOCK(state); 1152137776Semax return (EINVAL); 1153137776Semax } 1154137776Semax 1155137776Semax i = *(int *)arg; 1156137776Semax /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 1157137776Semax if (state->ks_mode == K_XLATE && 1158137776Semax kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 1159137776Semax if (i & ALKED) 1160137776Semax i |= CLKED; 1161137776Semax else 1162137776Semax i &= ~CLKED; 1163137776Semax } 1164137776Semax 1165137776Semax KBD_LED_VAL(kbd) = *(int *)arg; 1166137776Semax vkbd_status_changed(state); 1167137776Semax break; 1168137776Semax 1169137776Semax case KDGKBSTATE: /* get lock key state */ 1170137776Semax *(int *)arg = state->ks_state & LOCK_MASK; 1171137776Semax break; 1172137776Semax 1173162711Sru#ifdef COMPAT_FREEBSD6 1174162711Sru case _IO('K', 20): 1175162711Sru ival = IOCPARM_IVAL(arg); 1176162711Sru arg = (caddr_t)&ival; 1177162711Sru /* FALLTHROUGH */ 1178162711Sru#endif 1179137776Semax case KDSKBSTATE: /* set lock key state */ 1180137776Semax if (*(int *)arg & ~LOCK_MASK) { 1181137776Semax VKBD_UNLOCK(state); 1182137776Semax return (EINVAL); 1183137776Semax } 1184137776Semax state->ks_state &= ~LOCK_MASK; 1185137776Semax state->ks_state |= *(int *)arg; 1186137776Semax vkbd_status_changed(state); 1187137776Semax VKBD_UNLOCK(state); 1188137776Semax /* set LEDs and quit */ 1189137776Semax return (vkbd_ioctl(kbd, KDSETLED, arg)); 1190137776Semax 1191137776Semax case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 1192137776Semax i = typematic(((int *)arg)[0], ((int *)arg)[1]); 1193137776Semax kbd->kb_delay1 = typematic_delay(i); 1194137776Semax kbd->kb_delay2 = typematic_rate(i); 1195137776Semax vkbd_status_changed(state); 1196137776Semax break; 1197137776Semax 1198162711Sru#ifdef COMPAT_FREEBSD6 1199162711Sru case _IO('K', 67): 1200162711Sru ival = IOCPARM_IVAL(arg); 1201162711Sru arg = (caddr_t)&ival; 1202162711Sru /* FALLTHROUGH */ 1203162711Sru#endif 1204137776Semax case KDSETRAD: /* set keyboard repeat rate (old interface) */ 1205137776Semax kbd->kb_delay1 = typematic_delay(*(int *)arg); 1206137776Semax kbd->kb_delay2 = typematic_rate(*(int *)arg); 1207137776Semax vkbd_status_changed(state); 1208137776Semax break; 1209137776Semax 1210137776Semax case PIO_KEYMAP: /* set keyboard translation table */ 1211224126Sed case OPIO_KEYMAP: /* set keyboard translation table (compat) */ 1212137776Semax case PIO_KEYMAPENT: /* set keyboard translation table entry */ 1213137776Semax case PIO_DEADKEYMAP: /* set accent key translation table */ 1214137776Semax state->ks_accents = 0; 1215137776Semax /* FALLTHROUGH */ 1216137776Semax 1217137776Semax default: 1218137776Semax VKBD_UNLOCK(state); 1219137776Semax return (genkbd_commonioctl(kbd, cmd, arg)); 1220137776Semax } 1221137776Semax 1222137776Semax VKBD_UNLOCK(state); 1223137776Semax 1224137776Semax return (0); 1225137776Semax} 1226137776Semax 1227137776Semax/* Lock the access to the keyboard */ 1228137776Semaxstatic int 1229137776Semaxvkbd_lock(keyboard_t *kbd, int lock) 1230137776Semax{ 1231137776Semax return (1); /* XXX */ 1232137776Semax} 1233137776Semax 1234137776Semax/* Clear the internal state of the keyboard */ 1235137776Semaxstatic void 1236137776Semaxvkbd_clear_state_locked(vkbd_state_t *state) 1237137776Semax{ 1238137776Semax VKBD_LOCK_ASSERT(state, MA_OWNED); 1239137776Semax 1240146289Semax state->ks_flags &= ~COMPOSE; 1241137776Semax state->ks_polling = 0; 1242137776Semax state->ks_state &= LOCK_MASK; /* preserve locking key state */ 1243137776Semax state->ks_accents = 0; 1244137776Semax state->ks_composed_char = 0; 1245137776Semax/* state->ks_prefix = 0; XXX */ 1246137776Semax 1247137776Semax /* flush ks_inq and wakeup writers/poll()ers */ 1248137776Semax state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0; 1249137776Semax selwakeuppri(&state->ks_wsel, PZERO + 1); 1250137776Semax wakeup(&state->ks_inq); 1251137776Semax} 1252137776Semax 1253137776Semaxstatic void 1254137776Semaxvkbd_clear_state(keyboard_t *kbd) 1255137776Semax{ 1256137776Semax vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data; 1257137776Semax 1258137776Semax VKBD_LOCK(state); 1259137776Semax vkbd_clear_state_locked(state); 1260137776Semax VKBD_UNLOCK(state); 1261137776Semax} 1262137776Semax 1263137776Semax/* Save the internal state */ 1264137776Semaxstatic int 1265137776Semaxvkbd_get_state(keyboard_t *kbd, void *buf, size_t len) 1266137776Semax{ 1267137776Semax if (len == 0) 1268137776Semax return (sizeof(vkbd_state_t)); 1269137776Semax if (len < sizeof(vkbd_state_t)) 1270137776Semax return (-1); 1271137776Semax bcopy(kbd->kb_data, buf, sizeof(vkbd_state_t)); /* XXX locking? */ 1272137776Semax return (0); 1273137776Semax} 1274137776Semax 1275137776Semax/* Set the internal state */ 1276137776Semaxstatic int 1277137776Semaxvkbd_set_state(keyboard_t *kbd, void *buf, size_t len) 1278137776Semax{ 1279137776Semax if (len < sizeof(vkbd_state_t)) 1280137776Semax return (ENOMEM); 1281137776Semax bcopy(buf, kbd->kb_data, sizeof(vkbd_state_t)); /* XXX locking? */ 1282137776Semax return (0); 1283137776Semax} 1284137776Semax 1285137776Semax/* Set polling */ 1286137776Semaxstatic int 1287137776Semaxvkbd_poll(keyboard_t *kbd, int on) 1288137776Semax{ 1289137776Semax vkbd_state_t *state = NULL; 1290137776Semax 1291137776Semax state = (vkbd_state_t *) kbd->kb_data; 1292137776Semax 1293137776Semax VKBD_LOCK(state); 1294137776Semax 1295137776Semax if (on) 1296137776Semax state->ks_polling ++; 1297137776Semax else 1298137776Semax state->ks_polling --; 1299137776Semax 1300137776Semax VKBD_UNLOCK(state); 1301137776Semax 1302137776Semax return (0); 1303137776Semax} 1304137776Semax 1305137776Semax/* 1306137776Semax * Local functions 1307137776Semax */ 1308137776Semax 1309137776Semaxstatic int delays[] = { 250, 500, 750, 1000 }; 1310137776Semaxstatic int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63, 1311137776Semax 68, 76, 84, 92, 100, 110, 118, 126, 1312137776Semax 136, 152, 168, 184, 200, 220, 236, 252, 1313137776Semax 272, 304, 336, 368, 400, 440, 472, 504 }; 1314137776Semax 1315137776Semaxstatic int 1316137776Semaxtypematic_delay(int i) 1317137776Semax{ 1318137776Semax return (delays[(i >> 5) & 3]); 1319137776Semax} 1320137776Semax 1321137776Semaxstatic int 1322137776Semaxtypematic_rate(int i) 1323137776Semax{ 1324137776Semax return (rates[i & 0x1f]); 1325137776Semax} 1326137776Semax 1327137776Semaxstatic int 1328137776Semaxtypematic(int delay, int rate) 1329137776Semax{ 1330137776Semax int value; 1331137776Semax int i; 1332137776Semax 1333137776Semax for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; i --) { 1334137776Semax if (delay >= delays[i]) 1335137776Semax break; 1336137776Semax } 1337137776Semax value = i << 5; 1338137776Semax for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; i --) { 1339137776Semax if (rate >= rates[i]) 1340137776Semax break; 1341137776Semax } 1342137776Semax value |= i; 1343137776Semax return (value); 1344137776Semax} 1345137776Semax 1346137776Semax/***************************************************************************** 1347137776Semax ***************************************************************************** 1348137776Semax ** Module 1349137776Semax ***************************************************************************** 1350137776Semax *****************************************************************************/ 1351137776Semax 1352137776SemaxKEYBOARD_DRIVER(vkbd, vkbdsw, vkbd_configure); 1353137776Semax 1354137776Semaxstatic int 1355137776Semaxvkbd_modevent(module_t mod, int type, void *data) 1356137776Semax{ 1357137776Semax static eventhandler_tag tag; 1358137776Semax 1359137776Semax switch (type) { 1360137776Semax case MOD_LOAD: 1361137776Semax clone_setup(&vkbd_dev_clones); 1362137776Semax tag = EVENTHANDLER_REGISTER(dev_clone, vkbd_dev_clone, 0, 1000); 1363137776Semax if (tag == NULL) { 1364137776Semax clone_cleanup(&vkbd_dev_clones); 1365137776Semax return (ENOMEM); 1366137776Semax } 1367137776Semax kbd_add_driver(&vkbd_kbd_driver); 1368137776Semax break; 1369137776Semax 1370137776Semax case MOD_UNLOAD: 1371137776Semax kbd_delete_driver(&vkbd_kbd_driver); 1372137776Semax EVENTHANDLER_DEREGISTER(dev_clone, tag); 1373137776Semax clone_cleanup(&vkbd_dev_clones); 1374137776Semax break; 1375137776Semax 1376137776Semax default: 1377137776Semax return (EOPNOTSUPP); 1378137776Semax } 1379137776Semax 1380137776Semax return (0); 1381137776Semax} 1382137776Semax 1383137776SemaxDEV_MODULE(vkbd, vkbd_modevent, NULL); 1384137776Semax 1385