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