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: releng/11.0/sys/dev/vkbd/vkbd.c 298307 2016-04-19 23:37:24Z pfg $ 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 */ 189255359Sdavide if (clone_create(&vkbd_dev_clones, &vkbd_dev_cdevsw, &unit, dev, 0)) 190255359Sdavide *dev = make_dev_credf(MAKEDEV_REF, &vkbd_dev_cdevsw, unit, 191255359Sdavide cred, UID_ROOT, GID_WHEEL, 0600, DEVICE_NAME "%d", 192255359Sdavide unit); 193137776Semax} 194137776Semax 195137776Semax/* Open device */ 196137776Semaxstatic int 197137776Semaxvkbd_dev_open(struct cdev *dev, int flag, int mode, struct thread *td) 198137776Semax{ 199137776Semax int unit = dev2unit(dev), error; 200137776Semax keyboard_switch_t *sw = NULL; 201137776Semax keyboard_t *kbd = NULL; 202137776Semax vkbd_state_t *state = (vkbd_state_t *) dev->si_drv1; 203137776Semax 204137776Semax /* XXX FIXME: dev->si_drv1 locking */ 205137776Semax if (state == NULL) { 206137776Semax if ((sw = kbd_get_switch(KEYBOARD_NAME)) == NULL) 207137776Semax return (ENXIO); 208137776Semax 209137776Semax if ((error = (*sw->probe)(unit, NULL, 0)) != 0 || 210137776Semax (error = (*sw->init)(unit, &kbd, NULL, 0)) != 0) 211137776Semax return (error); 212137776Semax 213137776Semax state = (vkbd_state_t *) kbd->kb_data; 214137776Semax 215137776Semax if ((error = (*sw->enable)(kbd)) != 0) { 216137776Semax (*sw->term)(kbd); 217137776Semax return (error); 218137776Semax } 219137776Semax 220137776Semax#ifdef KBD_INSTALL_CDEV 221137776Semax if ((error = kbd_attach(kbd)) != 0) { 222137776Semax (*sw->disable)(kbd); 223137776Semax (*sw->term)(kbd); 224137776Semax return (error); 225137776Semax } 226137776Semax#endif /* def KBD_INSTALL_CDEV */ 227137776Semax 228137776Semax dev->si_drv1 = kbd->kb_data; 229137776Semax } 230137776Semax 231137776Semax VKBD_LOCK(state); 232137776Semax 233137776Semax if (state->ks_flags & OPEN) { 234137776Semax VKBD_UNLOCK(state); 235137776Semax return (EBUSY); 236137776Semax } 237137776Semax 238137776Semax state->ks_flags |= OPEN; 239137776Semax state->ks_dev = dev; 240137776Semax 241137776Semax VKBD_UNLOCK(state); 242137776Semax 243137776Semax return (0); 244137776Semax} 245137776Semax 246137776Semax/* Close device */ 247137776Semaxstatic int 248137776Semaxvkbd_dev_close(struct cdev *dev, int foo, int bar, struct thread *td) 249137776Semax{ 250137776Semax keyboard_t *kbd = VKBD_KEYBOARD(dev); 251137776Semax vkbd_state_t *state = NULL; 252137776Semax 253137776Semax if (kbd == NULL) 254137776Semax return (ENXIO); 255137776Semax 256137776Semax if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1) 257137776Semax panic("%s: kbd->kb_data != dev->si_drv1\n", __func__); 258137776Semax 259137776Semax state = (vkbd_state_t *) kbd->kb_data; 260137776Semax 261137776Semax VKBD_LOCK(state); 262137776Semax 263137776Semax /* wait for interrupt task */ 264137776Semax while (state->ks_flags & TASK) 265137776Semax VKBD_SLEEP(state, ks_task, "vkbdc", 0); 266137776Semax 267137776Semax /* wakeup poll()ers */ 268137776Semax selwakeuppri(&state->ks_rsel, PZERO + 1); 269137776Semax selwakeuppri(&state->ks_wsel, PZERO + 1); 270137776Semax 271137776Semax state->ks_flags &= ~OPEN; 272137776Semax state->ks_dev = NULL; 273137776Semax state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0; 274137776Semax 275137776Semax VKBD_UNLOCK(state); 276137776Semax 277174984Swkoszek kbdd_disable(kbd); 278137776Semax#ifdef KBD_INSTALL_CDEV 279137776Semax kbd_detach(kbd); 280137776Semax#endif /* def KBD_INSTALL_CDEV */ 281174984Swkoszek kbdd_term(kbd); 282137776Semax 283137776Semax /* XXX FIXME: dev->si_drv1 locking */ 284137776Semax dev->si_drv1 = NULL; 285137776Semax 286137776Semax return (0); 287137776Semax} 288137776Semax 289137776Semax/* Read status */ 290137776Semaxstatic int 291137776Semaxvkbd_dev_read(struct cdev *dev, struct uio *uio, int flag) 292137776Semax{ 293137776Semax keyboard_t *kbd = VKBD_KEYBOARD(dev); 294137776Semax vkbd_state_t *state = NULL; 295137776Semax vkbd_status_t status; 296137776Semax int error; 297137776Semax 298137776Semax if (kbd == NULL) 299137776Semax return (ENXIO); 300137776Semax 301137776Semax if (uio->uio_resid != sizeof(status)) 302137776Semax return (EINVAL); 303137776Semax 304137776Semax if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1) 305137776Semax panic("%s: kbd->kb_data != dev->si_drv1\n", __func__); 306137776Semax 307137776Semax state = (vkbd_state_t *) kbd->kb_data; 308137776Semax 309137776Semax VKBD_LOCK(state); 310137776Semax 311137776Semax if (state->ks_flags & READ) { 312137776Semax VKBD_UNLOCK(state); 313137776Semax return (EALREADY); 314137776Semax } 315137776Semax 316137776Semax state->ks_flags |= READ; 317137776Semaxagain: 318137776Semax if (state->ks_flags & STATUS) { 319137776Semax state->ks_flags &= ~STATUS; 320137776Semax 321137776Semax status.mode = state->ks_mode; 322137776Semax status.leds = KBD_LED_VAL(kbd); 323137776Semax status.lock = state->ks_state & LOCK_MASK; 324137776Semax status.delay = kbd->kb_delay1; 325137776Semax status.rate = kbd->kb_delay2; 326137776Semax bzero(status.reserved, sizeof(status.reserved)); 327137776Semax 328137776Semax error = uiomove(&status, sizeof(status), uio); 329137776Semax } else { 330139204Sphk if (flag & O_NONBLOCK) { 331137776Semax error = EWOULDBLOCK; 332137776Semax goto done; 333137776Semax } 334137776Semax 335137776Semax error = VKBD_SLEEP(state, ks_flags, "vkbdr", 0); 336137776Semax if (error != 0) 337137776Semax goto done; 338137776Semax 339137776Semax goto again; 340137776Semax } 341137776Semaxdone: 342137776Semax state->ks_flags &= ~READ; 343137776Semax 344137776Semax VKBD_UNLOCK(state); 345137776Semax 346137776Semax return (error); 347137776Semax} 348137776Semax 349137776Semax/* Write scancodes */ 350137776Semaxstatic int 351137776Semaxvkbd_dev_write(struct cdev *dev, struct uio *uio, int flag) 352137776Semax{ 353137776Semax keyboard_t *kbd = VKBD_KEYBOARD(dev); 354137776Semax vkbd_state_t *state = NULL; 355137776Semax vkbd_queue_t *q = NULL; 356137776Semax int error, avail, bytes; 357137776Semax 358137776Semax if (kbd == NULL) 359137776Semax return (ENXIO); 360137776Semax 361137776Semax if (uio->uio_resid <= 0) 362137776Semax return (EINVAL); 363137776Semax 364137776Semax if (kbd->kb_data == NULL || kbd->kb_data != dev->si_drv1) 365137776Semax panic("%s: kbd->kb_data != dev->si_drv1\n", __func__); 366137776Semax 367137776Semax state = (vkbd_state_t *) kbd->kb_data; 368137776Semax 369137776Semax VKBD_LOCK(state); 370137776Semax 371137776Semax if (state->ks_flags & WRITE) { 372137776Semax VKBD_UNLOCK(state); 373137776Semax return (EALREADY); 374137776Semax } 375137776Semax 376137776Semax state->ks_flags |= WRITE; 377137776Semax error = 0; 378137776Semax q = &state->ks_inq; 379137776Semax 380137776Semax while (uio->uio_resid >= sizeof(q->q[0])) { 381137776Semax if (q->head == q->tail) { 382137776Semax if (q->cc == 0) 383298307Spfg avail = nitems(q->q) - q->head; 384137776Semax else 385137776Semax avail = 0; /* queue must be full */ 386137776Semax } else if (q->head < q->tail) 387298307Spfg avail = nitems(q->q) - q->tail; 388137776Semax else 389137776Semax avail = q->head - q->tail; 390137776Semax 391137776Semax if (avail == 0) { 392139204Sphk if (flag & O_NONBLOCK) { 393137776Semax error = EWOULDBLOCK; 394137776Semax break; 395137776Semax } 396137776Semax 397137776Semax error = VKBD_SLEEP(state, ks_inq, "vkbdw", 0); 398137776Semax if (error != 0) 399137776Semax break; 400137776Semax } else { 401137776Semax bytes = avail * sizeof(q->q[0]); 402137776Semax if (bytes > uio->uio_resid) { 403137776Semax avail = uio->uio_resid / sizeof(q->q[0]); 404137776Semax bytes = avail * sizeof(q->q[0]); 405137776Semax } 406137776Semax 407137776Semax error = uiomove((void *) &q->q[q->tail], bytes, uio); 408137776Semax if (error != 0) 409137776Semax break; 410137776Semax 411137776Semax q->cc += avail; 412137776Semax q->tail += avail; 413298307Spfg if (q->tail == nitems(q->q)) 414137776Semax q->tail = 0; 415137776Semax 416137776Semax /* queue interrupt task if needed */ 417137776Semax if (!(state->ks_flags & TASK) && 418137776Semax taskqueue_enqueue(taskqueue_swi_giant, &state->ks_task) == 0) 419137776Semax state->ks_flags |= TASK; 420137776Semax } 421137776Semax } 422137776Semax 423137776Semax state->ks_flags &= ~WRITE; 424137776Semax 425137776Semax VKBD_UNLOCK(state); 426137776Semax 427137776Semax return (error); 428137776Semax} 429137776Semax 430137776Semax/* Process ioctl */ 431137776Semaxstatic int 432137776Semaxvkbd_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td) 433137776Semax{ 434137776Semax keyboard_t *kbd = VKBD_KEYBOARD(dev); 435137776Semax 436174984Swkoszek return ((kbd == NULL)? ENXIO : kbdd_ioctl(kbd, cmd, data)); 437137776Semax} 438137776Semax 439137776Semax/* Poll device */ 440137776Semaxstatic int 441137776Semaxvkbd_dev_poll(struct cdev *dev, int events, struct thread *td) 442137776Semax{ 443137776Semax vkbd_state_t *state = (vkbd_state_t *) dev->si_drv1; 444137776Semax vkbd_queue_t *q = NULL; 445137776Semax int revents = 0; 446137776Semax 447137776Semax if (state == NULL) 448137776Semax return (ENXIO); 449137776Semax 450137776Semax VKBD_LOCK(state); 451137776Semax 452137776Semax q = &state->ks_inq; 453137776Semax 454137776Semax if (events & (POLLIN | POLLRDNORM)) { 455137776Semax if (state->ks_flags & STATUS) 456137776Semax revents |= events & (POLLIN | POLLRDNORM); 457137776Semax else 458137776Semax selrecord(td, &state->ks_rsel); 459137776Semax } 460137776Semax 461137776Semax if (events & (POLLOUT | POLLWRNORM)) { 462298307Spfg if (q->cc < nitems(q->q)) 463137776Semax revents |= events & (POLLOUT | POLLWRNORM); 464137776Semax else 465137776Semax selrecord(td, &state->ks_wsel); 466137776Semax } 467137776Semax 468137776Semax VKBD_UNLOCK(state); 469137776Semax 470137776Semax return (revents); 471137776Semax} 472137776Semax 473137776Semax/* Interrupt handler */ 474137776Semaxvoid 475137776Semaxvkbd_dev_intr(void *xkbd, int pending) 476137776Semax{ 477137776Semax keyboard_t *kbd = (keyboard_t *) xkbd; 478137776Semax vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data; 479137776Semax 480174984Swkoszek kbdd_intr(kbd, NULL); 481137776Semax 482137776Semax VKBD_LOCK(state); 483137776Semax 484137776Semax state->ks_flags &= ~TASK; 485137776Semax wakeup(&state->ks_task); 486137776Semax 487137776Semax VKBD_UNLOCK(state); 488137776Semax} 489137776Semax 490137776Semax/* Set status change flags */ 491137776Semaxstatic void 492137776Semaxvkbd_status_changed(vkbd_state_t *state) 493137776Semax{ 494137776Semax VKBD_LOCK_ASSERT(state, MA_OWNED); 495137776Semax 496137776Semax if (!(state->ks_flags & STATUS)) { 497137776Semax state->ks_flags |= STATUS; 498137776Semax selwakeuppri(&state->ks_rsel, PZERO + 1); 499137776Semax wakeup(&state->ks_flags); 500137776Semax } 501137776Semax} 502137776Semax 503137776Semax/* Check if we have data in the input queue */ 504137776Semaxstatic int 505137776Semaxvkbd_data_ready(vkbd_state_t *state) 506137776Semax{ 507137776Semax VKBD_LOCK_ASSERT(state, MA_OWNED); 508137776Semax 509137776Semax return (state->ks_inq.cc > 0); 510137776Semax} 511137776Semax 512137776Semax/* Read one code from the input queue */ 513137776Semaxstatic int 514137776Semaxvkbd_data_read(vkbd_state_t *state, int wait) 515137776Semax{ 516137776Semax vkbd_queue_t *q = &state->ks_inq; 517137776Semax int c; 518137776Semax 519137776Semax VKBD_LOCK_ASSERT(state, MA_OWNED); 520137776Semax 521137776Semax if (q->cc == 0) 522137776Semax return (-1); 523137776Semax 524137776Semax /* get first code from the queue */ 525137776Semax q->cc --; 526137776Semax c = q->q[q->head ++]; 527298307Spfg if (q->head == nitems(q->q)) 528137776Semax q->head = 0; 529137776Semax 530137776Semax /* wakeup ks_inq writers/poll()ers */ 531137776Semax selwakeuppri(&state->ks_wsel, PZERO + 1); 532137776Semax wakeup(q); 533137776Semax 534137776Semax return (c); 535137776Semax} 536137776Semax 537137776Semax/**************************************************************************** 538137776Semax **************************************************************************** 539137776Semax ** Keyboard driver 540137776Semax **************************************************************************** 541137776Semax ****************************************************************************/ 542137776Semax 543137776Semaxstatic int vkbd_configure(int flags); 544137776Semaxstatic kbd_probe_t vkbd_probe; 545137776Semaxstatic kbd_init_t vkbd_init; 546137776Semaxstatic kbd_term_t vkbd_term; 547137776Semaxstatic kbd_intr_t vkbd_intr; 548137776Semaxstatic kbd_test_if_t vkbd_test_if; 549137776Semaxstatic kbd_enable_t vkbd_enable; 550137776Semaxstatic kbd_disable_t vkbd_disable; 551137776Semaxstatic kbd_read_t vkbd_read; 552137776Semaxstatic kbd_check_t vkbd_check; 553137776Semaxstatic kbd_read_char_t vkbd_read_char; 554137776Semaxstatic kbd_check_char_t vkbd_check_char; 555137776Semaxstatic kbd_ioctl_t vkbd_ioctl; 556137776Semaxstatic kbd_lock_t vkbd_lock; 557137776Semaxstatic void vkbd_clear_state_locked(vkbd_state_t *state); 558137776Semaxstatic kbd_clear_state_t vkbd_clear_state; 559137776Semaxstatic kbd_get_state_t vkbd_get_state; 560137776Semaxstatic kbd_set_state_t vkbd_set_state; 561137776Semaxstatic kbd_poll_mode_t vkbd_poll; 562137776Semax 563137776Semaxstatic keyboard_switch_t vkbdsw = { 564137776Semax .probe = vkbd_probe, 565137776Semax .init = vkbd_init, 566137776Semax .term = vkbd_term, 567137776Semax .intr = vkbd_intr, 568137776Semax .test_if = vkbd_test_if, 569137776Semax .enable = vkbd_enable, 570137776Semax .disable = vkbd_disable, 571137776Semax .read = vkbd_read, 572137776Semax .check = vkbd_check, 573137776Semax .read_char = vkbd_read_char, 574137776Semax .check_char = vkbd_check_char, 575137776Semax .ioctl = vkbd_ioctl, 576137776Semax .lock = vkbd_lock, 577137776Semax .clear_state = vkbd_clear_state, 578137776Semax .get_state = vkbd_get_state, 579137776Semax .set_state = vkbd_set_state, 580137776Semax .get_fkeystr = genkbd_get_fkeystr, 581137776Semax .poll = vkbd_poll, 582137776Semax .diag = genkbd_diag, 583137776Semax}; 584137776Semax 585137776Semaxstatic int typematic(int delay, int rate); 586137776Semaxstatic int typematic_delay(int delay); 587137776Semaxstatic int typematic_rate(int rate); 588137776Semax 589137776Semax/* Return the number of found keyboards */ 590137776Semaxstatic int 591137776Semaxvkbd_configure(int flags) 592137776Semax{ 593137776Semax return (1); 594137776Semax} 595137776Semax 596137776Semax/* Detect a keyboard */ 597137776Semaxstatic int 598137776Semaxvkbd_probe(int unit, void *arg, int flags) 599137776Semax{ 600137776Semax return (0); 601137776Semax} 602137776Semax 603137776Semax/* Reset and initialize the keyboard (stolen from atkbd.c) */ 604137776Semaxstatic int 605137776Semaxvkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) 606137776Semax{ 607137776Semax keyboard_t *kbd = NULL; 608137776Semax vkbd_state_t *state = NULL; 609137776Semax keymap_t *keymap = NULL; 610137776Semax accentmap_t *accmap = NULL; 611137776Semax fkeytab_t *fkeymap = NULL; 612137776Semax int fkeymap_size, delay[2]; 613142417Ssam int error, needfree; 614137776Semax 615137776Semax if (*kbdp == NULL) { 616137776Semax *kbdp = kbd = malloc(sizeof(*kbd), M_VKBD, M_NOWAIT | M_ZERO); 617137776Semax state = malloc(sizeof(*state), M_VKBD, M_NOWAIT | M_ZERO); 618137776Semax keymap = malloc(sizeof(key_map), M_VKBD, M_NOWAIT); 619137776Semax accmap = malloc(sizeof(accent_map), M_VKBD, M_NOWAIT); 620137776Semax fkeymap = malloc(sizeof(fkey_tab), M_VKBD, M_NOWAIT); 621137776Semax fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); 622142417Ssam needfree = 1; 623137776Semax if ((kbd == NULL) || (state == NULL) || (keymap == NULL) || 624137776Semax (accmap == NULL) || (fkeymap == NULL)) { 625142417Ssam error = ENOMEM; 626142417Ssam goto bad; 627137776Semax } 628137776Semax 629137776Semax VKBD_LOCK_INIT(state); 630137776Semax state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0; 631137776Semax TASK_INIT(&state->ks_task, 0, vkbd_dev_intr, (void *) kbd); 632137776Semax } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { 633137776Semax return (0); 634137776Semax } else { 635137776Semax kbd = *kbdp; 636137776Semax state = (vkbd_state_t *) kbd->kb_data; 637137776Semax keymap = kbd->kb_keymap; 638137776Semax accmap = kbd->kb_accentmap; 639137776Semax fkeymap = kbd->kb_fkeytab; 640137776Semax fkeymap_size = kbd->kb_fkeytab_size; 641142417Ssam needfree = 0; 642137776Semax } 643137776Semax 644137776Semax if (!KBD_IS_PROBED(kbd)) { 645137776Semax kbd_init_struct(kbd, KEYBOARD_NAME, KB_OTHER, unit, flags, 0, 0); 646137776Semax bcopy(&key_map, keymap, sizeof(key_map)); 647137776Semax bcopy(&accent_map, accmap, sizeof(accent_map)); 648137776Semax bcopy(fkey_tab, fkeymap, 649137776Semax imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); 650137776Semax kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); 651137776Semax kbd->kb_data = (void *)state; 652137776Semax 653137776Semax KBD_FOUND_DEVICE(kbd); 654137776Semax KBD_PROBE_DONE(kbd); 655137776Semax 656137776Semax VKBD_LOCK(state); 657137776Semax vkbd_clear_state_locked(state); 658137776Semax state->ks_mode = K_XLATE; 659137776Semax /* FIXME: set the initial value for lock keys in ks_state */ 660137776Semax VKBD_UNLOCK(state); 661137776Semax } 662137776Semax if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { 663137776Semax kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; 664137776Semax 665137776Semax vkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); 666137776Semax delay[0] = kbd->kb_delay1; 667137776Semax delay[1] = kbd->kb_delay2; 668137776Semax vkbd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); 669137776Semax 670137776Semax KBD_INIT_DONE(kbd); 671137776Semax } 672137776Semax if (!KBD_IS_CONFIGURED(kbd)) { 673142417Ssam if (kbd_register(kbd) < 0) { 674142417Ssam error = ENXIO; 675142417Ssam goto bad; 676142417Ssam } 677137776Semax KBD_CONFIG_DONE(kbd); 678137776Semax } 679137776Semax 680137776Semax return (0); 681142417Ssambad: 682142417Ssam if (needfree) { 683142417Ssam if (state != NULL) 684142417Ssam free(state, M_VKBD); 685142417Ssam if (keymap != NULL) 686142417Ssam free(keymap, M_VKBD); 687142417Ssam if (accmap != NULL) 688142417Ssam free(accmap, M_VKBD); 689142417Ssam if (fkeymap != NULL) 690142417Ssam free(fkeymap, M_VKBD); 691142417Ssam if (kbd != NULL) { 692146460Semax free(kbd, M_VKBD); 693142417Ssam *kbdp = NULL; /* insure ref doesn't leak to caller */ 694142417Ssam } 695142417Ssam } 696142417Ssam return (error); 697137776Semax} 698137776Semax 699137776Semax/* Finish using this keyboard */ 700137776Semaxstatic int 701137776Semaxvkbd_term(keyboard_t *kbd) 702137776Semax{ 703137776Semax vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data; 704137776Semax 705137776Semax kbd_unregister(kbd); 706137776Semax 707137776Semax VKBD_LOCK_DESTROY(state); 708137776Semax bzero(state, sizeof(*state)); 709137776Semax free(state, M_VKBD); 710137776Semax 711137776Semax free(kbd->kb_keymap, M_VKBD); 712137776Semax free(kbd->kb_accentmap, M_VKBD); 713137776Semax free(kbd->kb_fkeytab, M_VKBD); 714137776Semax free(kbd, M_VKBD); 715137776Semax 716137776Semax return (0); 717137776Semax} 718137776Semax 719137776Semax/* Keyboard interrupt routine */ 720137776Semaxstatic int 721137776Semaxvkbd_intr(keyboard_t *kbd, void *arg) 722137776Semax{ 723137776Semax int c; 724137776Semax 725137776Semax if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { 726137776Semax /* let the callback function to process the input */ 727137776Semax (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, 728137776Semax kbd->kb_callback.kc_arg); 729137776Semax } else { 730137776Semax /* read and discard the input; no one is waiting for input */ 731137776Semax do { 732137776Semax c = vkbd_read_char(kbd, FALSE); 733137776Semax } while (c != NOKEY); 734137776Semax } 735137776Semax 736137776Semax return (0); 737137776Semax} 738137776Semax 739137776Semax/* Test the interface to the device */ 740137776Semaxstatic int 741137776Semaxvkbd_test_if(keyboard_t *kbd) 742137776Semax{ 743137776Semax return (0); 744137776Semax} 745137776Semax 746137776Semax/* 747137776Semax * Enable the access to the device; until this function is called, 748137776Semax * the client cannot read from the keyboard. 749137776Semax */ 750137776Semax 751137776Semaxstatic int 752137776Semaxvkbd_enable(keyboard_t *kbd) 753137776Semax{ 754137776Semax KBD_ACTIVATE(kbd); 755137776Semax return (0); 756137776Semax} 757137776Semax 758137776Semax/* Disallow the access to the device */ 759137776Semaxstatic int 760137776Semaxvkbd_disable(keyboard_t *kbd) 761137776Semax{ 762137776Semax KBD_DEACTIVATE(kbd); 763137776Semax return (0); 764137776Semax} 765137776Semax 766137776Semax/* Read one byte from the keyboard if it's allowed */ 767137776Semaxstatic int 768137776Semaxvkbd_read(keyboard_t *kbd, int wait) 769137776Semax{ 770137776Semax vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data; 771137776Semax int c; 772137776Semax 773137776Semax VKBD_LOCK(state); 774137776Semax c = vkbd_data_read(state, wait); 775137776Semax VKBD_UNLOCK(state); 776137776Semax 777137776Semax if (c != -1) 778137776Semax kbd->kb_count ++; 779137776Semax 780137776Semax return (KBD_IS_ACTIVE(kbd)? c : -1); 781137776Semax} 782137776Semax 783137776Semax/* Check if data is waiting */ 784137776Semaxstatic int 785137776Semaxvkbd_check(keyboard_t *kbd) 786137776Semax{ 787137776Semax vkbd_state_t *state = NULL; 788137776Semax int ready; 789137776Semax 790137776Semax if (!KBD_IS_ACTIVE(kbd)) 791137776Semax return (FALSE); 792137776Semax 793137776Semax state = (vkbd_state_t *) kbd->kb_data; 794137776Semax 795137776Semax VKBD_LOCK(state); 796137776Semax ready = vkbd_data_ready(state); 797137776Semax VKBD_UNLOCK(state); 798137776Semax 799137776Semax return (ready); 800137776Semax} 801137776Semax 802137776Semax/* Read char from the keyboard (stolen from atkbd.c) */ 803137776Semaxstatic u_int 804137776Semaxvkbd_read_char(keyboard_t *kbd, int wait) 805137776Semax{ 806137776Semax vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data; 807137776Semax u_int action; 808137776Semax int scancode, keycode; 809137776Semax 810137776Semax VKBD_LOCK(state); 811137776Semax 812137776Semaxnext_code: 813137776Semax 814137776Semax /* do we have a composed char to return? */ 815137776Semax if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { 816137776Semax action = state->ks_composed_char; 817137776Semax state->ks_composed_char = 0; 818137776Semax if (action > UCHAR_MAX) { 819137776Semax VKBD_UNLOCK(state); 820137776Semax return (ERRKEY); 821137776Semax } 822137776Semax 823137776Semax VKBD_UNLOCK(state); 824137776Semax return (action); 825137776Semax } 826137776Semax 827137776Semax /* see if there is something in the keyboard port */ 828137776Semax scancode = vkbd_data_read(state, wait); 829137776Semax if (scancode == -1) { 830137776Semax VKBD_UNLOCK(state); 831137776Semax return (NOKEY); 832137776Semax } 833137776Semax /* XXX FIXME: check for -1 if wait == 1! */ 834137776Semax 835137776Semax kbd->kb_count ++; 836137776Semax 837137776Semax /* return the byte as is for the K_RAW mode */ 838137776Semax if (state->ks_mode == K_RAW) { 839137776Semax VKBD_UNLOCK(state); 840137776Semax return (scancode); 841137776Semax } 842137776Semax 843137776Semax /* translate the scan code into a keycode */ 844137776Semax keycode = scancode & 0x7F; 845137776Semax switch (state->ks_prefix) { 846137776Semax case 0x00: /* normal scancode */ 847137776Semax switch(scancode) { 848137776Semax case 0xB8: /* left alt (compose key) released */ 849137776Semax if (state->ks_flags & COMPOSE) { 850137776Semax state->ks_flags &= ~COMPOSE; 851137776Semax if (state->ks_composed_char > UCHAR_MAX) 852137776Semax state->ks_composed_char = 0; 853137776Semax } 854137776Semax break; 855137776Semax case 0x38: /* left alt (compose key) pressed */ 856137776Semax if (!(state->ks_flags & COMPOSE)) { 857137776Semax state->ks_flags |= COMPOSE; 858137776Semax state->ks_composed_char = 0; 859137776Semax } 860137776Semax break; 861137776Semax case 0xE0: 862137776Semax case 0xE1: 863137776Semax state->ks_prefix = scancode; 864137776Semax goto next_code; 865137776Semax } 866137776Semax break; 867137776Semax case 0xE0: /* 0xE0 prefix */ 868137776Semax state->ks_prefix = 0; 869137776Semax switch (keycode) { 870137776Semax case 0x1C: /* right enter key */ 871137776Semax keycode = 0x59; 872137776Semax break; 873137776Semax case 0x1D: /* right ctrl key */ 874137776Semax keycode = 0x5A; 875137776Semax break; 876137776Semax case 0x35: /* keypad divide key */ 877137776Semax keycode = 0x5B; 878137776Semax break; 879137776Semax case 0x37: /* print scrn key */ 880137776Semax keycode = 0x5C; 881137776Semax break; 882137776Semax case 0x38: /* right alt key (alt gr) */ 883137776Semax keycode = 0x5D; 884137776Semax break; 885137776Semax case 0x46: /* ctrl-pause/break on AT 101 (see below) */ 886137776Semax keycode = 0x68; 887137776Semax break; 888137776Semax case 0x47: /* grey home key */ 889137776Semax keycode = 0x5E; 890137776Semax break; 891137776Semax case 0x48: /* grey up arrow key */ 892137776Semax keycode = 0x5F; 893137776Semax break; 894137776Semax case 0x49: /* grey page up key */ 895137776Semax keycode = 0x60; 896137776Semax break; 897137776Semax case 0x4B: /* grey left arrow key */ 898137776Semax keycode = 0x61; 899137776Semax break; 900137776Semax case 0x4D: /* grey right arrow key */ 901137776Semax keycode = 0x62; 902137776Semax break; 903137776Semax case 0x4F: /* grey end key */ 904137776Semax keycode = 0x63; 905137776Semax break; 906137776Semax case 0x50: /* grey down arrow key */ 907137776Semax keycode = 0x64; 908137776Semax break; 909137776Semax case 0x51: /* grey page down key */ 910137776Semax keycode = 0x65; 911137776Semax break; 912137776Semax case 0x52: /* grey insert key */ 913137776Semax keycode = 0x66; 914137776Semax break; 915137776Semax case 0x53: /* grey delete key */ 916137776Semax keycode = 0x67; 917137776Semax break; 918137776Semax /* the following 3 are only used on the MS "Natural" keyboard */ 919137776Semax case 0x5b: /* left Window key */ 920137776Semax keycode = 0x69; 921137776Semax break; 922137776Semax case 0x5c: /* right Window key */ 923137776Semax keycode = 0x6a; 924137776Semax break; 925137776Semax case 0x5d: /* menu key */ 926137776Semax keycode = 0x6b; 927137776Semax break; 928137776Semax case 0x5e: /* power key */ 929137776Semax keycode = 0x6d; 930137776Semax break; 931137776Semax case 0x5f: /* sleep key */ 932137776Semax keycode = 0x6e; 933137776Semax break; 934137776Semax case 0x63: /* wake key */ 935137776Semax keycode = 0x6f; 936137776Semax break; 937137776Semax default: /* ignore everything else */ 938137776Semax goto next_code; 939137776Semax } 940137776Semax break; 941137776Semax case 0xE1: /* 0xE1 prefix */ 942137776Semax /* 943137776Semax * The pause/break key on the 101 keyboard produces: 944137776Semax * E1-1D-45 E1-9D-C5 945137776Semax * Ctrl-pause/break produces: 946137776Semax * E0-46 E0-C6 (See above.) 947137776Semax */ 948137776Semax state->ks_prefix = 0; 949137776Semax if (keycode == 0x1D) 950137776Semax state->ks_prefix = 0x1D; 951137776Semax goto next_code; 952137776Semax /* NOT REACHED */ 953137776Semax case 0x1D: /* pause / break */ 954137776Semax state->ks_prefix = 0; 955137776Semax if (keycode != 0x45) 956137776Semax goto next_code; 957137776Semax keycode = 0x68; 958137776Semax break; 959137776Semax } 960137776Semax 961137776Semax if (kbd->kb_type == KB_84) { 962137776Semax switch (keycode) { 963137776Semax case 0x37: /* *(numpad)/print screen */ 964137776Semax if (state->ks_flags & SHIFTS) 965137776Semax keycode = 0x5c; /* print screen */ 966137776Semax break; 967137776Semax case 0x45: /* num lock/pause */ 968137776Semax if (state->ks_flags & CTLS) 969137776Semax keycode = 0x68; /* pause */ 970137776Semax break; 971137776Semax case 0x46: /* scroll lock/break */ 972137776Semax if (state->ks_flags & CTLS) 973137776Semax keycode = 0x6c; /* break */ 974137776Semax break; 975137776Semax } 976137776Semax } else if (kbd->kb_type == KB_101) { 977137776Semax switch (keycode) { 978137776Semax case 0x5c: /* print screen */ 979137776Semax if (state->ks_flags & ALTS) 980137776Semax keycode = 0x54; /* sysrq */ 981137776Semax break; 982137776Semax case 0x68: /* pause/break */ 983137776Semax if (state->ks_flags & CTLS) 984137776Semax keycode = 0x6c; /* break */ 985137776Semax break; 986137776Semax } 987137776Semax } 988137776Semax 989137776Semax /* return the key code in the K_CODE mode */ 990137776Semax if (state->ks_mode == K_CODE) { 991137776Semax VKBD_UNLOCK(state); 992137776Semax return (keycode | (scancode & 0x80)); 993137776Semax } 994137776Semax 995137776Semax /* compose a character code */ 996137776Semax if (state->ks_flags & COMPOSE) { 997137776Semax switch (keycode | (scancode & 0x80)) { 998137776Semax /* key pressed, process it */ 999137776Semax case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ 1000137776Semax state->ks_composed_char *= 10; 1001137776Semax state->ks_composed_char += keycode - 0x40; 1002137776Semax if (state->ks_composed_char > UCHAR_MAX) { 1003137776Semax VKBD_UNLOCK(state); 1004137776Semax return (ERRKEY); 1005137776Semax } 1006137776Semax goto next_code; 1007137776Semax case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ 1008137776Semax state->ks_composed_char *= 10; 1009137776Semax state->ks_composed_char += keycode - 0x47; 1010137776Semax if (state->ks_composed_char > UCHAR_MAX) { 1011137776Semax VKBD_UNLOCK(state); 1012137776Semax return (ERRKEY); 1013137776Semax } 1014137776Semax goto next_code; 1015137776Semax case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ 1016137776Semax state->ks_composed_char *= 10; 1017137776Semax state->ks_composed_char += keycode - 0x4E; 1018137776Semax if (state->ks_composed_char > UCHAR_MAX) { 1019137776Semax VKBD_UNLOCK(state); 1020137776Semax return (ERRKEY); 1021137776Semax } 1022137776Semax goto next_code; 1023137776Semax case 0x52: /* keypad 0 */ 1024137776Semax state->ks_composed_char *= 10; 1025137776Semax if (state->ks_composed_char > UCHAR_MAX) { 1026137776Semax VKBD_UNLOCK(state); 1027137776Semax return (ERRKEY); 1028137776Semax } 1029137776Semax goto next_code; 1030137776Semax 1031137776Semax /* key released, no interest here */ 1032137776Semax case 0xC7: case 0xC8: case 0xC9: /* keypad 7,8,9 */ 1033137776Semax case 0xCB: case 0xCC: case 0xCD: /* keypad 4,5,6 */ 1034137776Semax case 0xCF: case 0xD0: case 0xD1: /* keypad 1,2,3 */ 1035137776Semax case 0xD2: /* keypad 0 */ 1036137776Semax goto next_code; 1037137776Semax 1038137776Semax case 0x38: /* left alt key */ 1039137776Semax break; 1040137776Semax 1041137776Semax default: 1042137776Semax if (state->ks_composed_char > 0) { 1043137776Semax state->ks_flags &= ~COMPOSE; 1044137776Semax state->ks_composed_char = 0; 1045137776Semax VKBD_UNLOCK(state); 1046137776Semax return (ERRKEY); 1047137776Semax } 1048137776Semax break; 1049137776Semax } 1050137776Semax } 1051137776Semax 1052137776Semax /* keycode to key action */ 1053137776Semax action = genkbd_keyaction(kbd, keycode, scancode & 0x80, 1054137776Semax &state->ks_state, &state->ks_accents); 1055137776Semax if (action == NOKEY) 1056137776Semax goto next_code; 1057137776Semax 1058137776Semax VKBD_UNLOCK(state); 1059137776Semax 1060137776Semax return (action); 1061137776Semax} 1062137776Semax 1063137776Semax/* Check if char is waiting */ 1064137776Semaxstatic int 1065137776Semaxvkbd_check_char(keyboard_t *kbd) 1066137776Semax{ 1067137776Semax vkbd_state_t *state = NULL; 1068137776Semax int ready; 1069137776Semax 1070137776Semax if (!KBD_IS_ACTIVE(kbd)) 1071137776Semax return (FALSE); 1072137776Semax 1073137776Semax state = (vkbd_state_t *) kbd->kb_data; 1074137776Semax 1075137776Semax VKBD_LOCK(state); 1076137776Semax if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) 1077137776Semax ready = TRUE; 1078137776Semax else 1079137776Semax ready = vkbd_data_ready(state); 1080137776Semax VKBD_UNLOCK(state); 1081137776Semax 1082137776Semax return (ready); 1083137776Semax} 1084137776Semax 1085137776Semax/* Some useful control functions (stolen from atkbd.c) */ 1086137776Semaxstatic int 1087137776Semaxvkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 1088137776Semax{ 1089137776Semax vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data; 1090137776Semax int i; 1091162711Sru#ifdef COMPAT_FREEBSD6 1092162711Sru int ival; 1093162711Sru#endif 1094137776Semax 1095137776Semax VKBD_LOCK(state); 1096137776Semax 1097137776Semax switch (cmd) { 1098137776Semax case KDGKBMODE: /* get keyboard mode */ 1099137776Semax *(int *)arg = state->ks_mode; 1100137776Semax break; 1101137776Semax 1102162711Sru#ifdef COMPAT_FREEBSD6 1103162711Sru case _IO('K', 7): 1104162711Sru ival = IOCPARM_IVAL(arg); 1105162711Sru arg = (caddr_t)&ival; 1106162711Sru /* FALLTHROUGH */ 1107162711Sru#endif 1108137776Semax case KDSKBMODE: /* set keyboard mode */ 1109137776Semax switch (*(int *)arg) { 1110137776Semax case K_XLATE: 1111137776Semax if (state->ks_mode != K_XLATE) { 1112137776Semax /* make lock key state and LED state match */ 1113137776Semax state->ks_state &= ~LOCK_MASK; 1114137776Semax state->ks_state |= KBD_LED_VAL(kbd); 1115137776Semax vkbd_status_changed(state); 1116137776Semax } 1117137776Semax /* FALLTHROUGH */ 1118137776Semax 1119137776Semax case K_RAW: 1120137776Semax case K_CODE: 1121137776Semax if (state->ks_mode != *(int *)arg) { 1122137776Semax vkbd_clear_state_locked(state); 1123137776Semax state->ks_mode = *(int *)arg; 1124137776Semax vkbd_status_changed(state); 1125137776Semax } 1126137776Semax break; 1127137776Semax 1128137776Semax default: 1129137776Semax VKBD_UNLOCK(state); 1130137776Semax return (EINVAL); 1131137776Semax } 1132137776Semax break; 1133137776Semax 1134137776Semax case KDGETLED: /* get keyboard LED */ 1135137776Semax *(int *)arg = KBD_LED_VAL(kbd); 1136137776Semax break; 1137137776Semax 1138162711Sru#ifdef COMPAT_FREEBSD6 1139162711Sru case _IO('K', 66): 1140162711Sru ival = IOCPARM_IVAL(arg); 1141162711Sru arg = (caddr_t)&ival; 1142162711Sru /* FALLTHROUGH */ 1143162711Sru#endif 1144137776Semax case KDSETLED: /* set keyboard LED */ 1145137776Semax /* NOTE: lock key state in ks_state won't be changed */ 1146137776Semax if (*(int *)arg & ~LOCK_MASK) { 1147137776Semax VKBD_UNLOCK(state); 1148137776Semax return (EINVAL); 1149137776Semax } 1150137776Semax 1151137776Semax i = *(int *)arg; 1152137776Semax /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ 1153137776Semax if (state->ks_mode == K_XLATE && 1154137776Semax kbd->kb_keymap->n_keys > ALTGR_OFFSET) { 1155137776Semax if (i & ALKED) 1156137776Semax i |= CLKED; 1157137776Semax else 1158137776Semax i &= ~CLKED; 1159137776Semax } 1160137776Semax 1161137776Semax KBD_LED_VAL(kbd) = *(int *)arg; 1162137776Semax vkbd_status_changed(state); 1163137776Semax break; 1164137776Semax 1165137776Semax case KDGKBSTATE: /* get lock key state */ 1166137776Semax *(int *)arg = state->ks_state & LOCK_MASK; 1167137776Semax break; 1168137776Semax 1169162711Sru#ifdef COMPAT_FREEBSD6 1170162711Sru case _IO('K', 20): 1171162711Sru ival = IOCPARM_IVAL(arg); 1172162711Sru arg = (caddr_t)&ival; 1173162711Sru /* FALLTHROUGH */ 1174162711Sru#endif 1175137776Semax case KDSKBSTATE: /* set lock key state */ 1176137776Semax if (*(int *)arg & ~LOCK_MASK) { 1177137776Semax VKBD_UNLOCK(state); 1178137776Semax return (EINVAL); 1179137776Semax } 1180137776Semax state->ks_state &= ~LOCK_MASK; 1181137776Semax state->ks_state |= *(int *)arg; 1182137776Semax vkbd_status_changed(state); 1183137776Semax VKBD_UNLOCK(state); 1184137776Semax /* set LEDs and quit */ 1185137776Semax return (vkbd_ioctl(kbd, KDSETLED, arg)); 1186137776Semax 1187137776Semax case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ 1188137776Semax i = typematic(((int *)arg)[0], ((int *)arg)[1]); 1189137776Semax kbd->kb_delay1 = typematic_delay(i); 1190137776Semax kbd->kb_delay2 = typematic_rate(i); 1191137776Semax vkbd_status_changed(state); 1192137776Semax break; 1193137776Semax 1194162711Sru#ifdef COMPAT_FREEBSD6 1195162711Sru case _IO('K', 67): 1196162711Sru ival = IOCPARM_IVAL(arg); 1197162711Sru arg = (caddr_t)&ival; 1198162711Sru /* FALLTHROUGH */ 1199162711Sru#endif 1200137776Semax case KDSETRAD: /* set keyboard repeat rate (old interface) */ 1201137776Semax kbd->kb_delay1 = typematic_delay(*(int *)arg); 1202137776Semax kbd->kb_delay2 = typematic_rate(*(int *)arg); 1203137776Semax vkbd_status_changed(state); 1204137776Semax break; 1205137776Semax 1206137776Semax case PIO_KEYMAP: /* set keyboard translation table */ 1207224126Sed case OPIO_KEYMAP: /* set keyboard translation table (compat) */ 1208137776Semax case PIO_KEYMAPENT: /* set keyboard translation table entry */ 1209137776Semax case PIO_DEADKEYMAP: /* set accent key translation table */ 1210137776Semax state->ks_accents = 0; 1211137776Semax /* FALLTHROUGH */ 1212137776Semax 1213137776Semax default: 1214137776Semax VKBD_UNLOCK(state); 1215137776Semax return (genkbd_commonioctl(kbd, cmd, arg)); 1216137776Semax } 1217137776Semax 1218137776Semax VKBD_UNLOCK(state); 1219137776Semax 1220137776Semax return (0); 1221137776Semax} 1222137776Semax 1223137776Semax/* Lock the access to the keyboard */ 1224137776Semaxstatic int 1225137776Semaxvkbd_lock(keyboard_t *kbd, int lock) 1226137776Semax{ 1227137776Semax return (1); /* XXX */ 1228137776Semax} 1229137776Semax 1230137776Semax/* Clear the internal state of the keyboard */ 1231137776Semaxstatic void 1232137776Semaxvkbd_clear_state_locked(vkbd_state_t *state) 1233137776Semax{ 1234137776Semax VKBD_LOCK_ASSERT(state, MA_OWNED); 1235137776Semax 1236146289Semax state->ks_flags &= ~COMPOSE; 1237137776Semax state->ks_polling = 0; 1238137776Semax state->ks_state &= LOCK_MASK; /* preserve locking key state */ 1239137776Semax state->ks_accents = 0; 1240137776Semax state->ks_composed_char = 0; 1241137776Semax/* state->ks_prefix = 0; XXX */ 1242137776Semax 1243137776Semax /* flush ks_inq and wakeup writers/poll()ers */ 1244137776Semax state->ks_inq.head = state->ks_inq.tail = state->ks_inq.cc = 0; 1245137776Semax selwakeuppri(&state->ks_wsel, PZERO + 1); 1246137776Semax wakeup(&state->ks_inq); 1247137776Semax} 1248137776Semax 1249137776Semaxstatic void 1250137776Semaxvkbd_clear_state(keyboard_t *kbd) 1251137776Semax{ 1252137776Semax vkbd_state_t *state = (vkbd_state_t *) kbd->kb_data; 1253137776Semax 1254137776Semax VKBD_LOCK(state); 1255137776Semax vkbd_clear_state_locked(state); 1256137776Semax VKBD_UNLOCK(state); 1257137776Semax} 1258137776Semax 1259137776Semax/* Save the internal state */ 1260137776Semaxstatic int 1261137776Semaxvkbd_get_state(keyboard_t *kbd, void *buf, size_t len) 1262137776Semax{ 1263137776Semax if (len == 0) 1264137776Semax return (sizeof(vkbd_state_t)); 1265137776Semax if (len < sizeof(vkbd_state_t)) 1266137776Semax return (-1); 1267137776Semax bcopy(kbd->kb_data, buf, sizeof(vkbd_state_t)); /* XXX locking? */ 1268137776Semax return (0); 1269137776Semax} 1270137776Semax 1271137776Semax/* Set the internal state */ 1272137776Semaxstatic int 1273137776Semaxvkbd_set_state(keyboard_t *kbd, void *buf, size_t len) 1274137776Semax{ 1275137776Semax if (len < sizeof(vkbd_state_t)) 1276137776Semax return (ENOMEM); 1277137776Semax bcopy(buf, kbd->kb_data, sizeof(vkbd_state_t)); /* XXX locking? */ 1278137776Semax return (0); 1279137776Semax} 1280137776Semax 1281137776Semax/* Set polling */ 1282137776Semaxstatic int 1283137776Semaxvkbd_poll(keyboard_t *kbd, int on) 1284137776Semax{ 1285137776Semax vkbd_state_t *state = NULL; 1286137776Semax 1287137776Semax state = (vkbd_state_t *) kbd->kb_data; 1288137776Semax 1289137776Semax VKBD_LOCK(state); 1290137776Semax 1291137776Semax if (on) 1292137776Semax state->ks_polling ++; 1293137776Semax else 1294137776Semax state->ks_polling --; 1295137776Semax 1296137776Semax VKBD_UNLOCK(state); 1297137776Semax 1298137776Semax return (0); 1299137776Semax} 1300137776Semax 1301137776Semax/* 1302137776Semax * Local functions 1303137776Semax */ 1304137776Semax 1305137776Semaxstatic int delays[] = { 250, 500, 750, 1000 }; 1306137776Semaxstatic int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63, 1307137776Semax 68, 76, 84, 92, 100, 110, 118, 126, 1308137776Semax 136, 152, 168, 184, 200, 220, 236, 252, 1309137776Semax 272, 304, 336, 368, 400, 440, 472, 504 }; 1310137776Semax 1311137776Semaxstatic int 1312137776Semaxtypematic_delay(int i) 1313137776Semax{ 1314137776Semax return (delays[(i >> 5) & 3]); 1315137776Semax} 1316137776Semax 1317137776Semaxstatic int 1318137776Semaxtypematic_rate(int i) 1319137776Semax{ 1320137776Semax return (rates[i & 0x1f]); 1321137776Semax} 1322137776Semax 1323137776Semaxstatic int 1324137776Semaxtypematic(int delay, int rate) 1325137776Semax{ 1326137776Semax int value; 1327137776Semax int i; 1328137776Semax 1329298307Spfg for (i = nitems(delays) - 1; i > 0; i --) { 1330137776Semax if (delay >= delays[i]) 1331137776Semax break; 1332137776Semax } 1333137776Semax value = i << 5; 1334298307Spfg for (i = nitems(rates) - 1; i > 0; i --) { 1335137776Semax if (rate >= rates[i]) 1336137776Semax break; 1337137776Semax } 1338137776Semax value |= i; 1339137776Semax return (value); 1340137776Semax} 1341137776Semax 1342137776Semax/***************************************************************************** 1343137776Semax ***************************************************************************** 1344137776Semax ** Module 1345137776Semax ***************************************************************************** 1346137776Semax *****************************************************************************/ 1347137776Semax 1348137776SemaxKEYBOARD_DRIVER(vkbd, vkbdsw, vkbd_configure); 1349137776Semax 1350137776Semaxstatic int 1351137776Semaxvkbd_modevent(module_t mod, int type, void *data) 1352137776Semax{ 1353137776Semax static eventhandler_tag tag; 1354137776Semax 1355137776Semax switch (type) { 1356137776Semax case MOD_LOAD: 1357137776Semax clone_setup(&vkbd_dev_clones); 1358137776Semax tag = EVENTHANDLER_REGISTER(dev_clone, vkbd_dev_clone, 0, 1000); 1359137776Semax if (tag == NULL) { 1360137776Semax clone_cleanup(&vkbd_dev_clones); 1361137776Semax return (ENOMEM); 1362137776Semax } 1363137776Semax kbd_add_driver(&vkbd_kbd_driver); 1364137776Semax break; 1365137776Semax 1366137776Semax case MOD_UNLOAD: 1367137776Semax kbd_delete_driver(&vkbd_kbd_driver); 1368137776Semax EVENTHANDLER_DEREGISTER(dev_clone, tag); 1369137776Semax clone_cleanup(&vkbd_dev_clones); 1370137776Semax break; 1371137776Semax 1372137776Semax default: 1373137776Semax return (EOPNOTSUPP); 1374137776Semax } 1375137776Semax 1376137776Semax return (0); 1377137776Semax} 1378137776Semax 1379137776SemaxDEV_MODULE(vkbd, vkbd_modevent, NULL); 1380137776Semax 1381