kbd.c revision 213770
1238730Sdelphij/*- 2294286Sdelphij * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 3238730Sdelphij * All rights reserved. 4238730Sdelphij * 5238730Sdelphij * Redistribution and use in source and binary forms, with or without 6238730Sdelphij * modification, are permitted provided that the following conditions 7238730Sdelphij * are met: 8238730Sdelphij * 1. Redistributions of source code must retain the above copyright 960786Sps * notice, this list of conditions and the following disclaimer as 1060786Sps * the first lines of this file unmodified. 1160786Sps * 2. Redistributions in binary form must reproduce the above copyright 1260786Sps * notice, this list of conditions and the following disclaimer in the 1360786Sps * documentation and/or other materials provided with the distribution. 1460786Sps * 1560786Sps * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 1660786Sps * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1760786Sps * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1860786Sps * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 1960786Sps * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2060786Sps * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2160786Sps * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2260786Sps * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2360786Sps * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2460786Sps * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2560786Sps * 2660786Sps */ 2760786Sps 2860786Sps#include <sys/cdefs.h> 2960786Sps__FBSDID("$FreeBSD: head/sys/dev/kbd/kbd.c 213770 2010-10-13 11:37:12Z rpaulo $"); 3060786Sps 3160786Sps#include "opt_kbd.h" 3260786Sps 3360786Sps#include <sys/param.h> 3460786Sps#include <sys/systm.h> 3589019Sps#include <sys/kernel.h> 3689019Sps#include <sys/malloc.h> 3789019Sps#include <sys/conf.h> 3860786Sps#include <sys/fcntl.h> 3960786Sps#include <sys/poll.h> 4060786Sps#include <sys/priv.h> 4160786Sps#include <sys/proc.h> 4260786Sps#include <sys/selinfo.h> 4360786Sps#include <sys/sysctl.h> 4460786Sps#include <sys/uio.h> 4560786Sps 4660786Sps#include <sys/kbio.h> 4760786Sps 4860786Sps#include <dev/kbd/kbdreg.h> 4960786Sps 5060786Sps#define KBD_INDEX(dev) dev2unit(dev) 5160786Sps 52128345Stjr#define KB_QSIZE 512 53170256Sdelphij#define KB_BUFSIZE 64 54191930Sdelphij 5560786Spstypedef struct genkbd_softc { 5660786Sps int gkb_flags; /* flag/status bits */ 5760786Sps#define KB_ASLEEP (1 << 0) 5860786Sps struct selinfo gkb_rsel; 5960786Sps char gkb_q[KB_QSIZE]; /* input queue */ 6060786Sps unsigned int gkb_q_start; 6160786Sps unsigned int gkb_q_length; 6260786Sps} genkbd_softc_t; 6360786Sps 6460786Spsstatic SLIST_HEAD(, keyboard_driver) keyboard_drivers = 6560786Sps SLIST_HEAD_INITIALIZER(keyboard_drivers); 66128345Stjr 6760786SpsSET_DECLARE(kbddriver_set, const keyboard_driver_t); 6860786Sps 6960786Sps/* local arrays */ 7060786Sps 7160786Sps/* 72128345Stjr * We need at least one entry each in order to initialize a keyboard 73128345Stjr * for the kernel console. The arrays will be increased dynamically 74128345Stjr * when necessary. 75128345Stjr */ 76128345Stjr 77128345Stjrstatic int keyboards = 1; 78128345Stjrstatic keyboard_t *kbd_ini; 79128345Stjrstatic keyboard_t **keyboard = &kbd_ini; 80128345Stjrstatic keyboard_switch_t *kbdsw_ini; 81128345Stjr keyboard_switch_t **kbdsw = &kbdsw_ini; 82128345Stjr 83128345Stjrstatic int keymap_restrict_change; 84128345StjrSYSCTL_NODE(_hw, OID_AUTO, kbd, CTLFLAG_RD, 0, "kbd"); 85128345StjrSYSCTL_INT(_hw_kbd, OID_AUTO, keymap_restrict_change, CTLFLAG_RW, 86128345Stjr &keymap_restrict_change, 0, "restrict ability to change keymap"); 87128345Stjr 88128345Stjr#define ARRAY_DELTA 4 89294286Sdelphij 90128345Stjrstatic int 91128345Stjrkbd_realloc_array(void) 92128345Stjr{ 93128345Stjr keyboard_t **new_kbd; 94128345Stjr keyboard_switch_t **new_kbdsw; 95128345Stjr int newsize; 96128345Stjr int s; 97128345Stjr 9860786Sps s = spltty(); 9960786Sps newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA; 10060786Sps new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT|M_ZERO); 10160786Sps if (new_kbd == NULL) { 102128345Stjr splx(s); 103128345Stjr return (ENOMEM); 104128345Stjr } 105128345Stjr new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF, 106128345Stjr M_NOWAIT|M_ZERO); 107128345Stjr if (new_kbdsw == NULL) { 108128345Stjr free(new_kbd, M_DEVBUF); 109128345Stjr splx(s); 110128345Stjr return (ENOMEM); 111128345Stjr } 112128345Stjr bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards); 113128345Stjr bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards); 114128345Stjr if (keyboards > 1) { 115128345Stjr free(keyboard, M_DEVBUF); 116128345Stjr free(kbdsw, M_DEVBUF); 117128345Stjr } 118128345Stjr keyboard = new_kbd; 119128345Stjr kbdsw = new_kbdsw; 120128345Stjr keyboards = newsize; 121128345Stjr splx(s); 122128345Stjr 123128345Stjr if (bootverbose) 124128345Stjr printf("kbd: new array size %d\n", keyboards); 125128345Stjr 126128345Stjr return (0); 127128345Stjr} 128128345Stjr 129128345Stjr/* 130128345Stjr * Low-level keyboard driver functions 131128345Stjr * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard 132128345Stjr * driver, call these functions to initialize the keyboard_t structure 133128345Stjr * and register it to the virtual keyboard driver `kbd'. 134128345Stjr */ 135128345Stjr 136128345Stjr/* initialize the keyboard_t structure */ 137128345Stjrvoid 138128345Stjrkbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config, 139128345Stjr int port, int port_size) 140128345Stjr{ 141128345Stjr kbd->kb_flags = KB_NO_DEVICE; /* device has not been found */ 142128345Stjr kbd->kb_name = name; 143128345Stjr kbd->kb_type = type; 144128345Stjr kbd->kb_unit = unit; 145128345Stjr kbd->kb_config = config & ~KB_CONF_PROBE_ONLY; 146128345Stjr kbd->kb_led = 0; /* unknown */ 147128345Stjr kbd->kb_io_base = port; 148128345Stjr kbd->kb_io_size = port_size; 149128345Stjr kbd->kb_data = NULL; 150128345Stjr kbd->kb_keymap = NULL; 151128345Stjr kbd->kb_accentmap = NULL; 152128345Stjr kbd->kb_fkeytab = NULL; 153294286Sdelphij kbd->kb_fkeytab_size = 0; 154128345Stjr kbd->kb_delay1 = KB_DELAY1; /* these values are advisory only */ 155128345Stjr kbd->kb_delay2 = KB_DELAY2; 156128345Stjr kbd->kb_count = 0L; 157128345Stjr bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact)); 158128345Stjr} 159128345Stjr 160128345Stjrvoid 161128345Stjrkbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap, 162128345Stjr fkeytab_t *fkeymap, int fkeymap_size) 163128345Stjr{ 164128345Stjr kbd->kb_keymap = keymap; 165128345Stjr kbd->kb_accentmap = accmap; 166128345Stjr kbd->kb_fkeytab = fkeymap; 167128345Stjr kbd->kb_fkeytab_size = fkeymap_size; 168128345Stjr} 169128345Stjr 170128345Stjr/* declare a new keyboard driver */ 171128345Stjrint 172128345Stjrkbd_add_driver(keyboard_driver_t *driver) 173128345Stjr{ 174128345Stjr if (SLIST_NEXT(driver, link)) 175128345Stjr return (EINVAL); 176128345Stjr SLIST_INSERT_HEAD(&keyboard_drivers, driver, link); 177128345Stjr return (0); 178128345Stjr} 179128345Stjr 180128345Stjrint 181128345Stjrkbd_delete_driver(keyboard_driver_t *driver) 182128345Stjr{ 183128345Stjr SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link); 184128345Stjr SLIST_NEXT(driver, link) = NULL; 185128345Stjr return (0); 186128345Stjr} 187128345Stjr 188128345Stjr/* register a keyboard and associate it with a function table */ 189128345Stjrint 190128345Stjrkbd_register(keyboard_t *kbd) 191294286Sdelphij{ 192128345Stjr const keyboard_driver_t **list; 193128345Stjr const keyboard_driver_t *p; 194128345Stjr keyboard_t *mux; 195128345Stjr keyboard_info_t ki; 196128345Stjr int index; 197128345Stjr 198128345Stjr mux = kbd_get_keyboard(kbd_find_keyboard("kbdmux", -1)); 199161475Sdelphij 200128345Stjr for (index = 0; index < keyboards; ++index) { 201128345Stjr if (keyboard[index] == NULL) 202128345Stjr break; 203128345Stjr } 204128345Stjr if (index >= keyboards) { 205128345Stjr if (kbd_realloc_array()) 206128345Stjr return (-1); 207128345Stjr } 208128345Stjr 209128345Stjr kbd->kb_index = index; 210128345Stjr KBD_UNBUSY(kbd); 211128345Stjr KBD_VALID(kbd); 212128345Stjr kbd->kb_active = 0; /* disabled until someone calls kbd_enable() */ 213128345Stjr kbd->kb_token = NULL; 214128345Stjr kbd->kb_callback.kc_func = NULL; 215128345Stjr kbd->kb_callback.kc_arg = NULL; 216128345Stjr 217128345Stjr SLIST_FOREACH(p, &keyboard_drivers, link) { 218128345Stjr if (strcmp(p->name, kbd->kb_name) == 0) { 219128345Stjr keyboard[index] = kbd; 22060786Sps kbdsw[index] = p->kbdsw; 22160786Sps 22260786Sps if (mux != NULL) { 22360786Sps bzero(&ki, sizeof(ki)); 22460786Sps strcpy(ki.kb_name, kbd->kb_name); 22560786Sps ki.kb_unit = kbd->kb_unit; 22660786Sps 22760786Sps (void)kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki); 22860786Sps } 22960786Sps 230161475Sdelphij return (index); 23160786Sps } 23260786Sps } 23360786Sps SET_FOREACH(list, kbddriver_set) { 23460786Sps p = *list; 23560786Sps if (strcmp(p->name, kbd->kb_name) == 0) { 23660786Sps keyboard[index] = kbd; 23760786Sps kbdsw[index] = p->kbdsw; 238294286Sdelphij 239161475Sdelphij if (mux != NULL) { 24060786Sps bzero(&ki, sizeof(ki)); 24160786Sps strcpy(ki.kb_name, kbd->kb_name); 242161475Sdelphij ki.kb_unit = kbd->kb_unit; 24360786Sps 24460786Sps (void)kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki); 24560786Sps } 246128345Stjr 24760786Sps return (index); 24860786Sps } 24960786Sps } 25060786Sps 25160786Sps return (-1); 25260786Sps} 25360786Sps 25460786Spsint 25560786Spskbd_unregister(keyboard_t *kbd) 25660786Sps{ 25760786Sps int error; 25860786Sps int s; 25960786Sps 26060786Sps if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards)) 26160786Sps return (ENOENT); 26260786Sps if (keyboard[kbd->kb_index] != kbd) 26360786Sps return (ENOENT); 26460786Sps 26560786Sps s = spltty(); 26660786Sps if (KBD_IS_BUSY(kbd)) { 26760786Sps error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING, 26860786Sps kbd->kb_callback.kc_arg); 26960786Sps if (error) { 27060786Sps splx(s); 27160786Sps return (error); 27260786Sps } 27360786Sps if (KBD_IS_BUSY(kbd)) { 27460786Sps splx(s); 27560786Sps return (EBUSY); 27660786Sps } 27760786Sps } 27860786Sps KBD_INVALID(kbd); 27960786Sps keyboard[kbd->kb_index] = NULL; 28060786Sps kbdsw[kbd->kb_index] = NULL; 28160786Sps 28260786Sps splx(s); 28360786Sps return (0); 28460786Sps} 28560786Sps 28660786Sps/* find a funciton table by the driver name */ 28760786Spskeyboard_switch_t 28860786Sps*kbd_get_switch(char *driver) 28960786Sps{ 29060786Sps const keyboard_driver_t **list; 29160786Sps const keyboard_driver_t *p; 29260786Sps 29360786Sps SLIST_FOREACH(p, &keyboard_drivers, link) { 29460786Sps if (strcmp(p->name, driver) == 0) 29560786Sps return (p->kbdsw); 29660786Sps } 29760786Sps SET_FOREACH(list, kbddriver_set) { 29860786Sps p = *list; 29960786Sps if (strcmp(p->name, driver) == 0) 30060786Sps return (p->kbdsw); 30160786Sps } 30260786Sps 30360786Sps return (NULL); 30460786Sps} 30560786Sps 30660786Sps/* 30760786Sps * Keyboard client functions 30860786Sps * Keyboard clients, such as the console driver `syscons' and the keyboard 30960786Sps * cdev driver, use these functions to claim and release a keyboard for 31060786Sps * exclusive use. 31160786Sps */ 31260786Sps 31360786Sps/* 31460786Sps * find the keyboard specified by a driver name and a unit number 31560786Sps * starting at given index 31660786Sps */ 31760786Spsint 31860786Spskbd_find_keyboard2(char *driver, int unit, int index) 31960786Sps{ 32060786Sps int i; 32160786Sps 32260786Sps if ((index < 0) || (index >= keyboards)) 32360786Sps return (-1); 32460786Sps 32560786Sps for (i = index; i < keyboards; ++i) { 32660786Sps if (keyboard[i] == NULL) 32760786Sps continue; 32860786Sps if (!KBD_IS_VALID(keyboard[i])) 32960786Sps continue; 33060786Sps if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver)) 33160786Sps continue; 33260786Sps if ((unit != -1) && (keyboard[i]->kb_unit != unit)) 33360786Sps continue; 33460786Sps return (i); 33560786Sps } 33660786Sps 33760786Sps return (-1); 33860786Sps} 33960786Sps 34060786Sps/* find the keyboard specified by a driver name and a unit number */ 34160786Spsint 34260786Spskbd_find_keyboard(char *driver, int unit) 34360786Sps{ 34460786Sps return (kbd_find_keyboard2(driver, unit, 0)); 34560786Sps} 34660786Sps 34760786Sps/* allocate a keyboard */ 34860786Spsint 34960786Spskbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func, 35060786Sps void *arg) 35160786Sps{ 35260786Sps int index; 353294286Sdelphij int s; 35460786Sps 35560786Sps if (func == NULL) 35660786Sps return (-1); 35760786Sps 35860786Sps s = spltty(); 35960786Sps index = kbd_find_keyboard(driver, unit); 36060786Sps if (index >= 0) { 36160786Sps if (KBD_IS_BUSY(keyboard[index])) { 36260786Sps splx(s); 36360786Sps return (-1); 36460786Sps } 36560786Sps keyboard[index]->kb_token = id; 36660786Sps KBD_BUSY(keyboard[index]); 36760786Sps keyboard[index]->kb_callback.kc_func = func; 36860786Sps keyboard[index]->kb_callback.kc_arg = arg; 36960786Sps kbdd_clear_state(keyboard[index]); 37060786Sps } 37160786Sps splx(s); 37260786Sps return (index); 37360786Sps} 37460786Sps 37560786Spsint 37660786Spskbd_release(keyboard_t *kbd, void *id) 37760786Sps{ 37860786Sps int error; 37960786Sps int s; 38060786Sps 38160786Sps s = spltty(); 38260786Sps if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 38360786Sps error = EINVAL; 38460786Sps } else if (kbd->kb_token != id) { 38560786Sps error = EPERM; 38660786Sps } else { 38760786Sps kbd->kb_token = NULL; 38860786Sps KBD_UNBUSY(kbd); 38960786Sps kbd->kb_callback.kc_func = NULL; 39060786Sps kbd->kb_callback.kc_arg = NULL; 39160786Sps kbdd_clear_state(kbd); 39260786Sps error = 0; 39360786Sps } 39460786Sps splx(s); 39560786Sps return (error); 39660786Sps} 39760786Sps 39860786Spsint 39960786Spskbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func, 40060786Sps void *arg) 40160786Sps{ 402221715Sdelphij int error; 40360786Sps int s; 40460786Sps 40560786Sps s = spltty(); 40660786Sps if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 40760786Sps error = EINVAL; 40860786Sps } else if (kbd->kb_token != id) { 40960786Sps error = EPERM; 41060786Sps } else if (func == NULL) { 41160786Sps error = EINVAL; 41260786Sps } else { 41360786Sps kbd->kb_callback.kc_func = func; 414128345Stjr kbd->kb_callback.kc_arg = arg; 41560786Sps error = 0; 41660786Sps } 41760786Sps splx(s); 41860786Sps return (error); 41960786Sps} 42060786Sps 42160786Sps/* get a keyboard structure */ 42260786Spskeyboard_t 42360786Sps*kbd_get_keyboard(int index) 42460786Sps{ 42560786Sps if ((index < 0) || (index >= keyboards)) 42660786Sps return (NULL); 42760786Sps if (keyboard[index] == NULL) 42860786Sps return (NULL); 42960786Sps if (!KBD_IS_VALID(keyboard[index])) 43060786Sps return (NULL); 431161475Sdelphij return (keyboard[index]); 43260786Sps} 43360786Sps 43460786Sps/* 435294286Sdelphij * The back door for the console driver; configure keyboards 436161475Sdelphij * This function is for the kernel console to initialize keyboards 43760786Sps * at very early stage. 438161475Sdelphij */ 43960786Sps 440161475Sdelphijint 44160786Spskbd_configure(int flags) 44260786Sps{ 443161475Sdelphij const keyboard_driver_t **list; 444294286Sdelphij const keyboard_driver_t *p; 445161475Sdelphij 446161475Sdelphij SLIST_FOREACH(p, &keyboard_drivers, link) { 447161475Sdelphij if (p->configure != NULL) 44860786Sps (*p->configure)(flags); 449128345Stjr } 450128345Stjr SET_FOREACH(list, kbddriver_set) { 45160786Sps p = *list; 45260786Sps if (p->configure != NULL) 45360786Sps (*p->configure)(flags); 45460786Sps } 45560786Sps 456128345Stjr return (0); 457128345Stjr} 45860786Sps 459128345Stjr#ifdef KBD_INSTALL_CDEV 46060786Sps 461128345Stjr/* 46260786Sps * Virtual keyboard cdev driver functions 46360786Sps * The virtual keyboard driver dispatches driver functions to 46460786Sps * appropriate subdrivers. 46560786Sps */ 46660786Sps 46760786Sps#define KBD_UNIT(dev) dev2unit(dev) 46860786Sps 46960786Spsstatic d_open_t genkbdopen; 47060786Spsstatic d_close_t genkbdclose; 47160786Spsstatic d_read_t genkbdread; 47260786Spsstatic d_write_t genkbdwrite; 47360786Spsstatic d_ioctl_t genkbdioctl; 474170256Sdelphijstatic d_poll_t genkbdpoll; 475191930Sdelphij 476191930Sdelphij 477191930Sdelphijstatic struct cdevsw kbd_cdevsw = { 47860786Sps .d_version = D_VERSION, 47960786Sps .d_flags = D_NEEDGIANT, 48060786Sps .d_open = genkbdopen, 481173682Sdelphij .d_close = genkbdclose, 48260786Sps .d_read = genkbdread, 48360786Sps .d_write = genkbdwrite, 484294286Sdelphij .d_ioctl = genkbdioctl, 485294286Sdelphij .d_poll = genkbdpoll, 486294286Sdelphij .d_name = "kbd", 487170256Sdelphij}; 488294286Sdelphij 489294286Sdelphijint 490294286Sdelphijkbd_attach(keyboard_t *kbd) 491294286Sdelphij{ 492294286Sdelphij 493170256Sdelphij if (kbd->kb_index >= keyboards) 494294286Sdelphij return (EINVAL); 495294286Sdelphij if (keyboard[kbd->kb_index] != kbd) 496294286Sdelphij return (EINVAL); 497294286Sdelphij 498294286Sdelphij kbd->kb_dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 499294286Sdelphij 0600, "%s%r", kbd->kb_name, kbd->kb_unit); 500294286Sdelphij make_dev_alias(kbd->kb_dev, "kbd%r", kbd->kb_index); 501294286Sdelphij kbd->kb_dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF, 502294286Sdelphij M_WAITOK | M_ZERO); 503170256Sdelphij printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit); 504170256Sdelphij return (0); 505170256Sdelphij} 506170256Sdelphij 507170256Sdelphijint 508170256Sdelphijkbd_detach(keyboard_t *kbd) 50960786Sps{ 51060786Sps 51160786Sps if (kbd->kb_index >= keyboards) 51260786Sps return (EINVAL); 51360786Sps if (keyboard[kbd->kb_index] != kbd) 51460786Sps return (EINVAL); 51560786Sps 51660786Sps free(kbd->kb_dev->si_drv1, M_DEVBUF); 51760786Sps destroy_dev(kbd->kb_dev); 51860786Sps 51960786Sps return (0); 520173682Sdelphij} 52160786Sps 52260786Sps/* 52360786Sps * Generic keyboard cdev driver functions 52460786Sps * Keyboard subdrivers may call these functions to implement common 52560786Sps * driver functions. 52660786Sps */ 52760786Sps 52860786Spsstatic void 52960786Spsgenkbd_putc(genkbd_softc_t *sc, char c) 53060786Sps{ 53160786Sps unsigned int p; 53260786Sps 53360786Sps if (sc->gkb_q_length == KB_QSIZE) 53460786Sps return; 53560786Sps 53660786Sps p = (sc->gkb_q_start + sc->gkb_q_length) % KB_QSIZE; 53760786Sps sc->gkb_q[p] = c; 53860786Sps sc->gkb_q_length++; 53960786Sps} 54060786Sps 54160786Spsstatic size_t 54260786Spsgenkbd_getc(genkbd_softc_t *sc, char *buf, size_t len) 54360786Sps{ 54460786Sps 54560786Sps /* Determine copy size. */ 54660786Sps if (sc->gkb_q_length == 0) 54760786Sps return (0); 54860786Sps if (len >= sc->gkb_q_length) 54960786Sps len = sc->gkb_q_length; 55060786Sps if (len >= KB_QSIZE - sc->gkb_q_start) 55160786Sps len = KB_QSIZE - sc->gkb_q_start; 55260786Sps 55360786Sps /* Copy out data and progress offset. */ 55460786Sps memcpy(buf, sc->gkb_q + sc->gkb_q_start, len); 55560786Sps sc->gkb_q_start = (sc->gkb_q_start + len) % KB_QSIZE; 55660786Sps sc->gkb_q_length -= len; 55760786Sps 55860786Sps return (len); 55960786Sps} 56060786Sps 56160786Spsstatic kbd_callback_func_t genkbd_event; 56260786Sps 56360786Spsstatic int 56460786Spsgenkbdopen(struct cdev *dev, int mode, int flag, struct thread *td) 56560786Sps{ 56660786Sps keyboard_t *kbd; 56760786Sps genkbd_softc_t *sc; 56860786Sps int s; 56960786Sps int i; 57060786Sps 57160786Sps s = spltty(); 57260786Sps sc = dev->si_drv1; 57360786Sps kbd = kbd_get_keyboard(KBD_INDEX(dev)); 57460786Sps if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 57560786Sps splx(s); 57660786Sps return (ENXIO); 57760786Sps } 57860786Sps i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc, 57960786Sps genkbd_event, (void *)sc); 58060786Sps if (i < 0) { 58160786Sps splx(s); 58260786Sps return (EBUSY); 58360786Sps } 58460786Sps /* assert(i == kbd->kb_index) */ 58560786Sps /* assert(kbd == kbd_get_keyboard(i)) */ 58660786Sps 58760786Sps /* 58860786Sps * NOTE: even when we have successfully claimed a keyboard, 58960786Sps * the device may still be missing (!KBD_HAS_DEVICE(kbd)). 59060786Sps */ 59160786Sps 59260786Sps sc->gkb_q_length = 0; 59360786Sps splx(s); 59460786Sps 595128345Stjr return (0); 596128345Stjr} 59760786Sps 598128345Stjrstatic int 599128345Stjrgenkbdclose(struct cdev *dev, int mode, int flag, struct thread *td) 60060786Sps{ 601128345Stjr keyboard_t *kbd; 60260786Sps genkbd_softc_t *sc; 60360786Sps int s; 604294286Sdelphij 605161475Sdelphij /* 606161475Sdelphij * NOTE: the device may have already become invalid. 60760786Sps * kbd == NULL || !KBD_IS_VALID(kbd) 608128345Stjr */ 609128345Stjr s = spltty(); 61060786Sps sc = dev->si_drv1; 61160786Sps kbd = kbd_get_keyboard(KBD_INDEX(dev)); 61260786Sps if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 61360786Sps /* XXX: we shall be forgiving and don't report error... */ 61460786Sps } else { 61560786Sps kbd_release(kbd, (void *)sc); 616128345Stjr } 617128345Stjr splx(s); 618128345Stjr return (0); 619128345Stjr} 620128345Stjr 62160786Spsstatic int 62260786Spsgenkbdread(struct cdev *dev, struct uio *uio, int flag) 62360786Sps{ 62460786Sps keyboard_t *kbd; 62560786Sps genkbd_softc_t *sc; 62660786Sps u_char buffer[KB_BUFSIZE]; 62760786Sps int len; 62860786Sps int error; 62960786Sps int s; 63060786Sps 63160786Sps /* wait for input */ 63260786Sps s = spltty(); 63360786Sps sc = dev->si_drv1; 63460786Sps kbd = kbd_get_keyboard(KBD_INDEX(dev)); 63560786Sps if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 63660786Sps splx(s); 63760786Sps return (ENXIO); 63860786Sps } 63960786Sps while (sc->gkb_q_length == 0) { 640128345Stjr if (flag & O_NONBLOCK) { 64160786Sps splx(s); 64260786Sps return (EWOULDBLOCK); 64360786Sps } 64460786Sps sc->gkb_flags |= KB_ASLEEP; 64560786Sps error = tsleep(sc, PZERO | PCATCH, "kbdrea", 0); 64660786Sps kbd = kbd_get_keyboard(KBD_INDEX(dev)); 64760786Sps if ((kbd == NULL) || !KBD_IS_VALID(kbd)) { 64860786Sps splx(s); 649128345Stjr return (ENXIO); /* our keyboard has gone... */ 65060786Sps } 65160786Sps if (error) { 65260786Sps sc->gkb_flags &= ~KB_ASLEEP; 65360786Sps splx(s); 65460786Sps return (error); 65560786Sps } 65660786Sps } 65760786Sps splx(s); 65860786Sps 65960786Sps /* copy as much input as possible */ 66060786Sps error = 0; 66160786Sps while (uio->uio_resid > 0) { 662128345Stjr len = imin(uio->uio_resid, sizeof(buffer)); 663128345Stjr len = genkbd_getc(sc, buffer, len); 664128345Stjr if (len <= 0) 665128345Stjr break; 666128345Stjr error = uiomove(buffer, len, uio); 667128345Stjr if (error) 66860786Sps break; 66960786Sps } 67060786Sps 67160786Sps return (error); 67260786Sps} 673128345Stjr 674128345Stjrstatic int 675128345Stjrgenkbdwrite(struct cdev *dev, struct uio *uio, int flag) 676128345Stjr{ 677128345Stjr keyboard_t *kbd; 678128345Stjr 67960786Sps kbd = kbd_get_keyboard(KBD_INDEX(dev)); 68060786Sps if ((kbd == NULL) || !KBD_IS_VALID(kbd)) 68160786Sps return (ENXIO); 68260786Sps return (ENODEV); 68360786Sps} 68460786Sps 68560786Spsstatic int 68660786Spsgenkbdioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 68760786Sps{ 68860786Sps keyboard_t *kbd; 68960786Sps int error; 69060786Sps 69160786Sps kbd = kbd_get_keyboard(KBD_INDEX(dev)); 69260786Sps if ((kbd == NULL) || !KBD_IS_VALID(kbd)) 69360786Sps return (ENXIO); 69460786Sps error = kbdd_ioctl(kbd, cmd, arg); 69560786Sps if (error == ENOIOCTL) 696128345Stjr error = ENODEV; 697128345Stjr return (error); 69860786Sps} 69960786Sps 70060786Spsstatic int 70160786Spsgenkbdpoll(struct cdev *dev, int events, struct thread *td) 70260786Sps{ 70360786Sps keyboard_t *kbd; 70460786Sps genkbd_softc_t *sc; 70560786Sps int revents; 70660786Sps int s; 70760786Sps 70860786Sps revents = 0; 70960786Sps s = spltty(); 71060786Sps sc = dev->si_drv1; 71160786Sps kbd = kbd_get_keyboard(KBD_INDEX(dev)); 712294286Sdelphij if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 713128345Stjr revents = POLLHUP; /* the keyboard has gone */ 714161475Sdelphij } else if (events & (POLLIN | POLLRDNORM)) { 715128345Stjr if (sc->gkb_q_length > 0) 716128345Stjr revents = events & (POLLIN | POLLRDNORM); 717128345Stjr else 71860786Sps selrecord(td, &sc->gkb_rsel); 719294286Sdelphij } 720128345Stjr splx(s); 721128345Stjr return (revents); 722128345Stjr} 723128345Stjr 724128345Stjrstatic int 725128345Stjrgenkbd_event(keyboard_t *kbd, int event, void *arg) 726128345Stjr{ 727128345Stjr genkbd_softc_t *sc; 728128345Stjr size_t len; 729128345Stjr u_char *cp; 730128345Stjr int mode; 731128345Stjr u_int c; 732128345Stjr 733128345Stjr /* assert(KBD_IS_VALID(kbd)) */ 734128345Stjr sc = (genkbd_softc_t *)arg; 735128345Stjr 736128345Stjr switch (event) { 737128345Stjr case KBDIO_KEYINPUT: 73860786Sps break; 73960786Sps case KBDIO_UNLOADING: 74060786Sps /* the keyboard is going... */ 74160786Sps kbd_release(kbd, (void *)sc); 74260786Sps if (sc->gkb_flags & KB_ASLEEP) { 74360786Sps sc->gkb_flags &= ~KB_ASLEEP; 74460786Sps wakeup(sc); 74560786Sps } 74660786Sps selwakeuppri(&sc->gkb_rsel, PZERO); 74760786Sps return (0); 74860786Sps default: 74960786Sps return (EINVAL); 75060786Sps } 75160786Sps 75260786Sps /* obtain the current key input mode */ 75360786Sps if (kbdd_ioctl(kbd, KDGKBMODE, (caddr_t)&mode)) 75460786Sps mode = K_XLATE; 75560786Sps 75660786Sps /* read all pending input */ 75760786Sps while (kbdd_check_char(kbd)) { 758128345Stjr c = kbdd_read_char(kbd, FALSE); 759161475Sdelphij if (c == NOKEY) 76060786Sps continue; 761128345Stjr if (c == ERRKEY) /* XXX: ring bell? */ 762128345Stjr continue; 763128345Stjr if (!KBD_IS_BUSY(kbd)) 764128345Stjr /* the device is not open, discard the input */ 765128345Stjr continue; 76660786Sps 76760786Sps /* store the byte as is for K_RAW and K_CODE modes */ 76860786Sps if (mode != K_XLATE) { 76960786Sps genkbd_putc(sc, KEYCHAR(c)); 770128345Stjr continue; 771128345Stjr } 772128345Stjr 77360786Sps /* K_XLATE */ 77460786Sps if (c & RELKEY) /* key release is ignored */ 77560786Sps continue; 776294286Sdelphij 777161475Sdelphij /* process special keys; most of them are just ignored... */ 778161475Sdelphij if (c & SPCLKEY) { 779128345Stjr switch (KEYCHAR(c)) { 780128345Stjr default: 781128345Stjr /* ignore them... */ 782128345Stjr continue; 78360786Sps case BTAB: /* a backtab: ESC [ Z */ 78460786Sps genkbd_putc(sc, 0x1b); 78560786Sps genkbd_putc(sc, '['); 78660786Sps genkbd_putc(sc, 'Z'); 78760786Sps continue; 78860786Sps } 78960786Sps } 79060786Sps 79160786Sps /* normal chars, normal chars with the META, function keys */ 79260786Sps switch (KEYFLAGS(c)) { 79360786Sps case 0: /* a normal char */ 79460786Sps genkbd_putc(sc, KEYCHAR(c)); 79560786Sps break; 79660786Sps case MKEY: /* the META flag: prepend ESC */ 79760786Sps genkbd_putc(sc, 0x1b); 79860786Sps genkbd_putc(sc, KEYCHAR(c)); 79960786Sps break; 80060786Sps case FKEY | SPCLKEY: /* a function key, return string */ 80160786Sps cp = kbdd_get_fkeystr(kbd, KEYCHAR(c), &len); 80260786Sps if (cp != NULL) { 80360786Sps while (len-- > 0) 80460786Sps genkbd_putc(sc, *cp++); 80560786Sps } 80660786Sps break; 80760786Sps } 80860786Sps } 80960786Sps 81060786Sps /* wake up sleeping/polling processes */ 81160786Sps if (sc->gkb_q_length > 0) { 81260786Sps if (sc->gkb_flags & KB_ASLEEP) { 81360786Sps sc->gkb_flags &= ~KB_ASLEEP; 81460786Sps wakeup(sc); 81560786Sps } 81660786Sps selwakeuppri(&sc->gkb_rsel, PZERO); 817237613Sdelphij } 818237613Sdelphij 819237613Sdelphij return (0); 820237613Sdelphij} 821237613Sdelphij 822237613Sdelphij#endif /* KBD_INSTALL_CDEV */ 823237613Sdelphij 824294286Sdelphij/* 825237613Sdelphij * Generic low-level keyboard functions 826294286Sdelphij * The low-level functions in the keyboard subdriver may use these 827237613Sdelphij * functions. 828294286Sdelphij */ 829294286Sdelphij 830294286Sdelphij#ifndef KBD_DISABLE_KEYMAP_LOAD 831294286Sdelphijstatic int key_change_ok(struct keyent_t *, struct keyent_t *, struct thread *); 832294286Sdelphijstatic int keymap_change_ok(keymap_t *, keymap_t *, struct thread *); 833294286Sdelphijstatic int accent_change_ok(accentmap_t *, accentmap_t *, struct thread *); 834294286Sdelphijstatic int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct thread *); 835294286Sdelphij#endif 836294286Sdelphij 837294286Sdelphijint 838237613Sdelphijgenkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 839237613Sdelphij{ 840237613Sdelphij#ifndef KBD_DISABLE_KEYMAP_LOAD 841237613Sdelphij keymap_t *mapp; 842237613Sdelphij#endif 84360786Sps keyarg_t *keyp; 84460786Sps fkeyarg_t *fkeyp; 84560786Sps int s; 84660786Sps int i; 84760786Sps int error; 84860786Sps 84960786Sps s = spltty(); 85060786Sps switch (cmd) { 85160786Sps 85260786Sps case KDGKBINFO: /* get keyboard information */ 85360786Sps ((keyboard_info_t *)arg)->kb_index = kbd->kb_index; 85460786Sps i = imin(strlen(kbd->kb_name) + 1, 85560786Sps sizeof(((keyboard_info_t *)arg)->kb_name)); 85660786Sps bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i); 857161475Sdelphij ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit; 85860786Sps ((keyboard_info_t *)arg)->kb_type = kbd->kb_type; 85960786Sps ((keyboard_info_t *)arg)->kb_config = kbd->kb_config; 86060786Sps ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags; 86160786Sps break; 86260786Sps 863128345Stjr case KDGKBTYPE: /* get keyboard type */ 86460786Sps *(int *)arg = kbd->kb_type; 86560786Sps break; 86660786Sps 86760786Sps case KDGETREPEAT: /* get keyboard repeat rate */ 868237613Sdelphij ((int *)arg)[0] = kbd->kb_delay1; 86960786Sps ((int *)arg)[1] = kbd->kb_delay2; 87060786Sps break; 87160786Sps 87260786Sps case GIO_KEYMAP: /* get keyboard translation table */ 87360786Sps error = copyout(kbd->kb_keymap, *(void **)arg, 874191930Sdelphij sizeof(keymap_t)); 875191930Sdelphij splx(s); 876191930Sdelphij return (error); 877191930Sdelphij case PIO_KEYMAP: /* set keyboard translation table */ 87860786Sps#ifndef KBD_DISABLE_KEYMAP_LOAD 879237613Sdelphij mapp = malloc(sizeof *mapp, M_TEMP, M_NOWAIT); 88060786Sps error = copyin(*(void **)arg, mapp, sizeof *mapp); 88160786Sps if (error != 0) { 882195941Sdelphij splx(s); 883195941Sdelphij free(mapp, M_TEMP); 884195941Sdelphij return (error); 885195941Sdelphij } 886195941Sdelphij 887195941Sdelphij error = keymap_change_ok(kbd->kb_keymap, mapp, curthread); 888195941Sdelphij if (error != 0) { 889195941Sdelphij splx(s); 890195941Sdelphij free(mapp, M_TEMP); 891237613Sdelphij return (error); 892237613Sdelphij } 893237613Sdelphij bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 894237613Sdelphij bcopy(mapp, kbd->kb_keymap, sizeof(*kbd->kb_keymap)); 895237613Sdelphij free(mapp, M_TEMP); 89660786Sps break; 897294286Sdelphij#else 898161475Sdelphij splx(s); 899161475Sdelphij return (ENODEV); 90060786Sps#endif 90160786Sps 90260786Sps case GIO_KEYMAPENT: /* get keyboard translation table entry */ 90360786Sps keyp = (keyarg_t *)arg; 90460786Sps if (keyp->keynum >= sizeof(kbd->kb_keymap->key) / 90560786Sps sizeof(kbd->kb_keymap->key[0])) { 90660786Sps splx(s); 90760786Sps return (EINVAL); 90860786Sps } 90960786Sps bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key, 91060786Sps sizeof(keyp->key)); 91160786Sps break; 91260786Sps case PIO_KEYMAPENT: /* set keyboard translation table entry */ 91360786Sps#ifndef KBD_DISABLE_KEYMAP_LOAD 91460786Sps keyp = (keyarg_t *)arg; 91560786Sps if (keyp->keynum >= sizeof(kbd->kb_keymap->key) / 91660786Sps sizeof(kbd->kb_keymap->key[0])) { 91760786Sps splx(s); 91860786Sps return (EINVAL); 91960786Sps } 92060786Sps error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum], 92160786Sps &keyp->key, curthread); 92260786Sps if (error != 0) { 92360786Sps splx(s); 924237613Sdelphij return (error); 925237613Sdelphij } 926237613Sdelphij bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum], 927237613Sdelphij sizeof(keyp->key)); 928237613Sdelphij break; 92960786Sps#else 930237613Sdelphij splx(s); 931237613Sdelphij return (ENODEV); 932237613Sdelphij#endif 933237613Sdelphij 934237613Sdelphij case GIO_DEADKEYMAP: /* get accent key translation table */ 935237613Sdelphij bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap)); 93660786Sps break; 93760786Sps case PIO_DEADKEYMAP: /* set accent key translation table */ 93860786Sps#ifndef KBD_DISABLE_KEYMAP_LOAD 93960786Sps error = accent_change_ok(kbd->kb_accentmap, 94060786Sps (accentmap_t *)arg, curthread); 94160786Sps if (error != 0) { 94260786Sps splx(s); 94360786Sps return (error); 944128345Stjr } 94560786Sps bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 946128345Stjr break; 94760786Sps#else 94860786Sps splx(s); 94960786Sps return (ENODEV); 95060786Sps#endif 951128345Stjr 95260786Sps case GETFKEY: /* get functionkey string */ 95360786Sps fkeyp = (fkeyarg_t *)arg; 95460786Sps if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 95560786Sps splx(s); 95660786Sps return (EINVAL); 95760786Sps } 95860786Sps bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef, 95960786Sps kbd->kb_fkeytab[fkeyp->keynum].len); 96060786Sps fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len; 96160786Sps break; 96260786Sps case SETFKEY: /* set functionkey string */ 96360786Sps#ifndef KBD_DISABLE_KEYMAP_LOAD 96460786Sps fkeyp = (fkeyarg_t *)arg; 96560786Sps if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 96660786Sps splx(s); 96760786Sps return (EINVAL); 968161475Sdelphij } 96960786Sps error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum], 97060786Sps fkeyp, curthread); 97160786Sps if (error != 0) { 97260786Sps splx(s); 97389019Sps return (error); 97489019Sps } 97589019Sps kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK); 97689019Sps bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str, 97789019Sps kbd->kb_fkeytab[fkeyp->keynum].len); 97889019Sps break; 97989019Sps#else 98089019Sps splx(s); 98160786Sps return (ENODEV); 98289019Sps#endif 98360786Sps 98460786Sps default: 985237613Sdelphij splx(s); 986237613Sdelphij return (ENOIOCTL); 987294286Sdelphij } 988237613Sdelphij 989237613Sdelphij splx(s); 990294286Sdelphij return (0); 991161475Sdelphij} 992161475Sdelphij 99360786Sps#ifndef KBD_DISABLE_KEYMAP_LOAD 99460786Sps#define RESTRICTED_KEY(key, i) \ 99560786Sps ((key->spcl & (0x80 >> i)) && \ 99660786Sps (key->map[i] == RBT || key->map[i] == SUSP || \ 99760786Sps key->map[i] == STBY || key->map[i] == DBG || \ 99860786Sps key->map[i] == PNC || key->map[i] == HALT || \ 99960786Sps key->map[i] == PDWN)) 100060786Sps 100160786Spsstatic int 100260786Spskey_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct thread *td) 100360786Sps{ 100460786Sps int i; 100560786Sps 100660786Sps /* Low keymap_restrict_change means any changes are OK. */ 100760786Sps if (keymap_restrict_change <= 0) 100860786Sps return (0); 1009128345Stjr 101060786Sps /* High keymap_restrict_change means only root can change the keymap. */ 101160786Sps if (keymap_restrict_change >= 2) { 101260786Sps for (i = 0; i < NUM_STATES; i++) 101360786Sps if (oldkey->map[i] != newkey->map[i]) 101460786Sps return priv_check(td, PRIV_KEYBOARD); 101560786Sps if (oldkey->spcl != newkey->spcl) 101660786Sps return priv_check(td, PRIV_KEYBOARD); 101760786Sps if (oldkey->flgs != newkey->flgs) 101860786Sps return priv_check(td, PRIV_KEYBOARD); 101960786Sps return (0); 102060786Sps } 102160786Sps 102260786Sps /* Otherwise we have to see if any special keys are being changed. */ 102360786Sps for (i = 0; i < NUM_STATES; i++) { 102460786Sps /* 102560786Sps * If either the oldkey or the newkey action is restricted 102660786Sps * then we must make sure that the action doesn't change. 102760786Sps */ 102860786Sps if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i)) 102960786Sps continue; 103060786Sps if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i)) 103160786Sps && oldkey->map[i] == newkey->map[i]) 103260786Sps continue; 103360786Sps return priv_check(td, PRIV_KEYBOARD); 103460786Sps } 103560786Sps 103660786Sps return (0); 103760786Sps} 103860786Sps 103960786Spsstatic int 104060786Spskeymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct thread *td) 104160786Sps{ 104260786Sps int keycode, error; 104360786Sps 104460786Sps for (keycode = 0; keycode < NUM_KEYS; keycode++) { 1045128345Stjr if ((error = key_change_ok(&oldmap->key[keycode], 1046170256Sdelphij &newmap->key[keycode], td)) != 0) 104760786Sps return (error); 1048128345Stjr } 104960786Sps return (0); 1050128345Stjr} 105160786Sps 105260786Spsstatic int 1053128345Stjraccent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct thread *td) 105460786Sps{ 105560786Sps struct acc_t *oldacc, *newacc; 105660786Sps int accent, i; 105760786Sps 105860786Sps if (keymap_restrict_change <= 2) 105960786Sps return (0); 106060786Sps 106160786Sps if (oldmap->n_accs != newmap->n_accs) 106260786Sps return priv_check(td, PRIV_KEYBOARD); 106360786Sps 106460786Sps for (accent = 0; accent < oldmap->n_accs; accent++) { 106560786Sps oldacc = &oldmap->acc[accent]; 106660786Sps newacc = &newmap->acc[accent]; 106760786Sps if (oldacc->accchar != newacc->accchar) 106860786Sps return priv_check(td, PRIV_KEYBOARD); 106960786Sps for (i = 0; i < NUM_ACCENTCHARS; ++i) { 107060786Sps if (oldacc->map[i][0] != newacc->map[i][0]) 107160786Sps return priv_check(td, PRIV_KEYBOARD); 107260786Sps if (oldacc->map[i][0] == 0) /* end of table */ 107360786Sps break; 107460786Sps if (oldacc->map[i][1] != newacc->map[i][1]) 107560786Sps return priv_check(td, PRIV_KEYBOARD); 107660786Sps } 107760786Sps } 107860786Sps 107960786Sps return (0); 108060786Sps} 108160786Sps 108260786Spsstatic int 108360786Spsfkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct thread *td) 108460786Sps{ 108560786Sps if (keymap_restrict_change <= 3) 108660786Sps return (0); 108760786Sps 108860786Sps if (oldkey->len != newkey->flen || 108960786Sps bcmp(oldkey->str, newkey->keydef, oldkey->len) != 0) 109060786Sps return priv_check(td, PRIV_KEYBOARD); 109160786Sps 109260786Sps return (0); 109360786Sps} 109460786Sps#endif 109560786Sps 109660786Sps/* get a pointer to the string associated with the given function key */ 109760786Spsu_char 109860786Sps*genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len) 109960786Sps{ 110060786Sps if (kbd == NULL) 110160786Sps return (NULL); 110260786Sps fkey -= F_FN; 110360786Sps if (fkey > kbd->kb_fkeytab_size) 110460786Sps return (NULL); 1105128345Stjr *len = kbd->kb_fkeytab[fkey].len; 1106128345Stjr return (kbd->kb_fkeytab[fkey].str); 1107128345Stjr} 1108128345Stjr 1109128345Stjr/* diagnostic dump */ 1110128345Stjrstatic char 1111128345Stjr*get_kbd_type_name(int type) 1112128345Stjr{ 1113221715Sdelphij static struct { 1114221715Sdelphij int type; 1115221715Sdelphij char *name; 1116221715Sdelphij } name_table[] = { 1117221715Sdelphij { KB_84, "AT 84" }, 1118221715Sdelphij { KB_101, "AT 101/102" }, 1119221715Sdelphij { KB_OTHER, "generic" }, 1120221715Sdelphij }; 1121221715Sdelphij int i; 1122221715Sdelphij 1123221715Sdelphij for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) { 1124221715Sdelphij if (type == name_table[i].type) 1125221715Sdelphij return (name_table[i].name); 1126221715Sdelphij } 1127221715Sdelphij return ("unknown"); 1128221715Sdelphij} 1129221715Sdelphij 1130221715Sdelphijvoid 1131221715Sdelphijgenkbd_diag(keyboard_t *kbd, int level) 1132{ 1133 if (level > 0) { 1134 printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x", 1135 kbd->kb_index, kbd->kb_name, kbd->kb_unit, 1136 get_kbd_type_name(kbd->kb_type), kbd->kb_type, 1137 kbd->kb_config, kbd->kb_flags); 1138 if (kbd->kb_io_base > 0) 1139 printf(", port:0x%x-0x%x", kbd->kb_io_base, 1140 kbd->kb_io_base + kbd->kb_io_size - 1); 1141 printf("\n"); 1142 } 1143} 1144 1145#define set_lockkey_state(k, s, l) \ 1146 if (!((s) & l ## DOWN)) { \ 1147 int i; \ 1148 (s) |= l ## DOWN; \ 1149 (s) ^= l ## ED; \ 1150 i = (s) & LOCK_MASK; \ 1151 (void)kbdd_ioctl((k), KDSETLED, (caddr_t)&i); \ 1152 } 1153 1154static u_int 1155save_accent_key(keyboard_t *kbd, u_int key, int *accents) 1156{ 1157 int i; 1158 1159 /* make an index into the accent map */ 1160 i = key - F_ACC + 1; 1161 if ((i > kbd->kb_accentmap->n_accs) 1162 || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) { 1163 /* the index is out of range or pointing to an empty entry */ 1164 *accents = 0; 1165 return (ERRKEY); 1166 } 1167 1168 /* 1169 * If the same accent key has been hit twice, produce the accent 1170 * char itself. 1171 */ 1172 if (i == *accents) { 1173 key = kbd->kb_accentmap->acc[i - 1].accchar; 1174 *accents = 0; 1175 return (key); 1176 } 1177 1178 /* remember the index and wait for the next key */ 1179 *accents = i; 1180 return (NOKEY); 1181} 1182 1183static u_int 1184make_accent_char(keyboard_t *kbd, u_int ch, int *accents) 1185{ 1186 struct acc_t *acc; 1187 int i; 1188 1189 acc = &kbd->kb_accentmap->acc[*accents - 1]; 1190 *accents = 0; 1191 1192 /* 1193 * If the accent key is followed by the space key, 1194 * produce the accent char itself. 1195 */ 1196 if (ch == ' ') 1197 return (acc->accchar); 1198 1199 /* scan the accent map */ 1200 for (i = 0; i < NUM_ACCENTCHARS; ++i) { 1201 if (acc->map[i][0] == 0) /* end of table */ 1202 break; 1203 if (acc->map[i][0] == ch) 1204 return (acc->map[i][1]); 1205 } 1206 /* this char cannot be accented... */ 1207 return (ERRKEY); 1208} 1209 1210int 1211genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate, 1212 int *accents) 1213{ 1214 struct keyent_t *key; 1215 int state = *shiftstate; 1216 int action; 1217 int f; 1218 int i; 1219 1220 i = keycode; 1221 f = state & (AGRS | ALKED); 1222 if ((f == AGRS1) || (f == AGRS2) || (f == ALKED)) 1223 i += ALTGR_OFFSET; 1224 key = &kbd->kb_keymap->key[i]; 1225 i = ((state & SHIFTS) ? 1 : 0) 1226 | ((state & CTLS) ? 2 : 0) 1227 | ((state & ALTS) ? 4 : 0); 1228 if (((key->flgs & FLAG_LOCK_C) && (state & CLKED)) 1229 || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) ) 1230 i ^= 1; 1231 1232 if (up) { /* break: key released */ 1233 action = kbd->kb_lastact[keycode]; 1234 kbd->kb_lastact[keycode] = NOP; 1235 switch (action) { 1236 case LSHA: 1237 if (state & SHIFTAON) { 1238 set_lockkey_state(kbd, state, ALK); 1239 state &= ~ALKDOWN; 1240 } 1241 action = LSH; 1242 /* FALL THROUGH */ 1243 case LSH: 1244 state &= ~SHIFTS1; 1245 break; 1246 case RSHA: 1247 if (state & SHIFTAON) { 1248 set_lockkey_state(kbd, state, ALK); 1249 state &= ~ALKDOWN; 1250 } 1251 action = RSH; 1252 /* FALL THROUGH */ 1253 case RSH: 1254 state &= ~SHIFTS2; 1255 break; 1256 case LCTRA: 1257 if (state & SHIFTAON) { 1258 set_lockkey_state(kbd, state, ALK); 1259 state &= ~ALKDOWN; 1260 } 1261 action = LCTR; 1262 /* FALL THROUGH */ 1263 case LCTR: 1264 state &= ~CTLS1; 1265 break; 1266 case RCTRA: 1267 if (state & SHIFTAON) { 1268 set_lockkey_state(kbd, state, ALK); 1269 state &= ~ALKDOWN; 1270 } 1271 action = RCTR; 1272 /* FALL THROUGH */ 1273 case RCTR: 1274 state &= ~CTLS2; 1275 break; 1276 case LALTA: 1277 if (state & SHIFTAON) { 1278 set_lockkey_state(kbd, state, ALK); 1279 state &= ~ALKDOWN; 1280 } 1281 action = LALT; 1282 /* FALL THROUGH */ 1283 case LALT: 1284 state &= ~ALTS1; 1285 break; 1286 case RALTA: 1287 if (state & SHIFTAON) { 1288 set_lockkey_state(kbd, state, ALK); 1289 state &= ~ALKDOWN; 1290 } 1291 action = RALT; 1292 /* FALL THROUGH */ 1293 case RALT: 1294 state &= ~ALTS2; 1295 break; 1296 case ASH: 1297 state &= ~AGRS1; 1298 break; 1299 case META: 1300 state &= ~METAS1; 1301 break; 1302 case NLK: 1303 state &= ~NLKDOWN; 1304 break; 1305 case CLK: 1306#ifndef PC98 1307 state &= ~CLKDOWN; 1308#else 1309 state &= ~CLKED; 1310 i = state & LOCK_MASK; 1311 (void)kbdd_ioctl(kbd, KDSETLED, (caddr_t)&i); 1312#endif 1313 break; 1314 case SLK: 1315 state &= ~SLKDOWN; 1316 break; 1317 case ALK: 1318 state &= ~ALKDOWN; 1319 break; 1320 case NOP: 1321 /* release events of regular keys are not reported */ 1322 *shiftstate &= ~SHIFTAON; 1323 return (NOKEY); 1324 } 1325 *shiftstate = state & ~SHIFTAON; 1326 return (SPCLKEY | RELKEY | action); 1327 } else { /* make: key pressed */ 1328 action = key->map[i]; 1329 state &= ~SHIFTAON; 1330 if (key->spcl & (0x80 >> i)) { 1331 /* special keys */ 1332 if (kbd->kb_lastact[keycode] == NOP) 1333 kbd->kb_lastact[keycode] = action; 1334 if (kbd->kb_lastact[keycode] != action) 1335 action = NOP; 1336 switch (action) { 1337 /* LOCKING KEYS */ 1338 case NLK: 1339 set_lockkey_state(kbd, state, NLK); 1340 break; 1341 case CLK: 1342#ifndef PC98 1343 set_lockkey_state(kbd, state, CLK); 1344#else 1345 state |= CLKED; 1346 i = state & LOCK_MASK; 1347 (void)kbdd_ioctl(kbd, KDSETLED, (caddr_t)&i); 1348#endif 1349 break; 1350 case SLK: 1351 set_lockkey_state(kbd, state, SLK); 1352 break; 1353 case ALK: 1354 set_lockkey_state(kbd, state, ALK); 1355 break; 1356 /* NON-LOCKING KEYS */ 1357 case SPSC: case RBT: case SUSP: case STBY: 1358 case DBG: case NEXT: case PREV: case PNC: 1359 case HALT: case PDWN: 1360 *accents = 0; 1361 break; 1362 case BTAB: 1363 *accents = 0; 1364 action |= BKEY; 1365 break; 1366 case LSHA: 1367 state |= SHIFTAON; 1368 action = LSH; 1369 /* FALL THROUGH */ 1370 case LSH: 1371 state |= SHIFTS1; 1372 break; 1373 case RSHA: 1374 state |= SHIFTAON; 1375 action = RSH; 1376 /* FALL THROUGH */ 1377 case RSH: 1378 state |= SHIFTS2; 1379 break; 1380 case LCTRA: 1381 state |= SHIFTAON; 1382 action = LCTR; 1383 /* FALL THROUGH */ 1384 case LCTR: 1385 state |= CTLS1; 1386 break; 1387 case RCTRA: 1388 state |= SHIFTAON; 1389 action = RCTR; 1390 /* FALL THROUGH */ 1391 case RCTR: 1392 state |= CTLS2; 1393 break; 1394 case LALTA: 1395 state |= SHIFTAON; 1396 action = LALT; 1397 /* FALL THROUGH */ 1398 case LALT: 1399 state |= ALTS1; 1400 break; 1401 case RALTA: 1402 state |= SHIFTAON; 1403 action = RALT; 1404 /* FALL THROUGH */ 1405 case RALT: 1406 state |= ALTS2; 1407 break; 1408 case ASH: 1409 state |= AGRS1; 1410 break; 1411 case META: 1412 state |= METAS1; 1413 break; 1414 case NOP: 1415 *shiftstate = state; 1416 return (NOKEY); 1417 default: 1418 /* is this an accent (dead) key? */ 1419 *shiftstate = state; 1420 if (action >= F_ACC && action <= L_ACC) { 1421 action = save_accent_key(kbd, action, 1422 accents); 1423 switch (action) { 1424 case NOKEY: 1425 case ERRKEY: 1426 return (action); 1427 default: 1428 if (state & METAS) 1429 return (action | MKEY); 1430 else 1431 return (action); 1432 } 1433 /* NOT REACHED */ 1434 } 1435 /* other special keys */ 1436 if (*accents > 0) { 1437 *accents = 0; 1438 return (ERRKEY); 1439 } 1440 if (action >= F_FN && action <= L_FN) 1441 action |= FKEY; 1442 /* XXX: return fkey string for the FKEY? */ 1443 return (SPCLKEY | action); 1444 } 1445 *shiftstate = state; 1446 return (SPCLKEY | action); 1447 } else { 1448 /* regular keys */ 1449 kbd->kb_lastact[keycode] = NOP; 1450 *shiftstate = state; 1451 if (*accents > 0) { 1452 /* make an accented char */ 1453 action = make_accent_char(kbd, action, accents); 1454 if (action == ERRKEY) 1455 return (action); 1456 } 1457 if (state & METAS) 1458 action |= MKEY; 1459 return (action); 1460 } 1461 } 1462 /* NOT REACHED */ 1463} 1464