kbd.c revision 164033
142421Syokota/*- 242421Syokota * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> 342421Syokota * All rights reserved. 442421Syokota * 542421Syokota * Redistribution and use in source and binary forms, with or without 642421Syokota * modification, are permitted provided that the following conditions 742421Syokota * are met: 842421Syokota * 1. Redistributions of source code must retain the above copyright 942421Syokota * notice, this list of conditions and the following disclaimer as 1042421Syokota * the first lines of this file unmodified. 1142421Syokota * 2. Redistributions in binary form must reproduce the above copyright 1242421Syokota * notice, this list of conditions and the following disclaimer in the 1342421Syokota * documentation and/or other materials provided with the distribution. 1442421Syokota * 1542421Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 1642421Syokota * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1742421Syokota * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1842421Syokota * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, 1942421Syokota * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2042421Syokota * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2142421Syokota * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2242421Syokota * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2342421Syokota * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2442421Syokota * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2542421Syokota * 2642421Syokota */ 2742421Syokota 28119418Sobrien#include <sys/cdefs.h> 29119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/kbd/kbd.c 164033 2006-11-06 13:42:10Z rwatson $"); 30119418Sobrien 3142421Syokota#include "opt_kbd.h" 3242421Syokota 3342421Syokota#include <sys/param.h> 3442421Syokota#include <sys/systm.h> 3542421Syokota#include <sys/kernel.h> 3642421Syokota#include <sys/malloc.h> 3742421Syokota#include <sys/conf.h> 38139193Sphk#include <sys/fcntl.h> 3942421Syokota#include <sys/tty.h> 4042421Syokota#include <sys/poll.h> 41164033Srwatson#include <sys/priv.h> 42112050Sdwmalone#include <sys/proc.h> 43112050Sdwmalone#include <sys/sysctl.h> 4442421Syokota#include <sys/uio.h> 4542421Syokota 4666834Sphk#include <sys/kbio.h> 4742421Syokota 4842421Syokota#include <dev/kbd/kbdreg.h> 4942421Syokota 5050154Syokota#define KBD_INDEX(dev) minor(dev) 5150154Syokota 5250154Syokotatypedef struct genkbd_softc { 5350154Syokota int gkb_flags; /* flag/status bits */ 5450154Syokota#define KB_ASLEEP (1 << 0) 5550154Syokota struct clist gkb_q; /* input queue */ 5650154Syokota struct selinfo gkb_rsel; 5750154Syokota} genkbd_softc_t; 5850154Syokota 5960938Sjakestatic SLIST_HEAD(, keyboard_driver) keyboard_drivers = 60127751Sdes SLIST_HEAD_INITIALIZER(keyboard_drivers); 6154545Syokota 6278161SpeterSET_DECLARE(kbddriver_set, const keyboard_driver_t); 6378161Speter 6442421Syokota/* local arrays */ 6542421Syokota 6642421Syokota/* 6742421Syokota * We need at least one entry each in order to initialize a keyboard 6842421Syokota * for the kernel console. The arrays will be increased dynamically 6942421Syokota * when necessary. 7042421Syokota */ 7142564Syokota 7242564Syokotastatic int keyboards = 1; 7342421Syokotastatic keyboard_t *kbd_ini; 7442564Syokotastatic keyboard_t **keyboard = &kbd_ini; 7542421Syokotastatic keyboard_switch_t *kbdsw_ini; 7642421Syokota keyboard_switch_t **kbdsw = &kbdsw_ini; 7742421Syokota 78112050Sdwmalonestatic int keymap_restrict_change; 79112050SdwmaloneSYSCTL_NODE(_hw, OID_AUTO, kbd, CTLFLAG_RD, 0, "kbd"); 80112050SdwmaloneSYSCTL_INT(_hw_kbd, OID_AUTO, keymap_restrict_change, CTLFLAG_RW, 81112050Sdwmalone &keymap_restrict_change, 0, "restrict ability to change keymap"); 82112050Sdwmalone 8342421Syokota#define ARRAY_DELTA 4 8442421Syokota 8544628Syokotastatic int 8642421Syokotakbd_realloc_array(void) 8742421Syokota{ 8842421Syokota keyboard_t **new_kbd; 8942421Syokota keyboard_switch_t **new_kbdsw; 9042421Syokota int newsize; 9142421Syokota int s; 9242421Syokota 9342421Syokota s = spltty(); 9442421Syokota newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA; 9569781Sdwmalone new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT|M_ZERO); 9644628Syokota if (new_kbd == NULL) { 9744628Syokota splx(s); 98127752Sdes return (ENOMEM); 9944628Syokota } 10069781Sdwmalone new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF, 10169781Sdwmalone M_NOWAIT|M_ZERO); 10244628Syokota if (new_kbdsw == NULL) { 10344628Syokota free(new_kbd, M_DEVBUF); 10444628Syokota splx(s); 105127752Sdes return (ENOMEM); 10644628Syokota } 10742421Syokota bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards); 10842421Syokota bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards); 10942421Syokota if (keyboards > 1) { 11042421Syokota free(keyboard, M_DEVBUF); 11142421Syokota free(kbdsw, M_DEVBUF); 11242421Syokota } 11342421Syokota keyboard = new_kbd; 11442421Syokota kbdsw = new_kbdsw; 11542421Syokota keyboards = newsize; 11642421Syokota splx(s); 11742421Syokota 11842421Syokota if (bootverbose) 11942421Syokota printf("kbd: new array size %d\n", keyboards); 12044628Syokota 121127752Sdes return (0); 12242421Syokota} 12342421Syokota 12442421Syokota/* 12542421Syokota * Low-level keyboard driver functions 12642421Syokota * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard 12742421Syokota * driver, call these functions to initialize the keyboard_t structure 12842421Syokota * and register it to the virtual keyboard driver `kbd'. 12942421Syokota */ 13042421Syokota 13142421Syokota/* initialize the keyboard_t structure */ 13242421Syokotavoid 13342421Syokotakbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config, 13442421Syokota int port, int port_size) 13542421Syokota{ 13642421Syokota kbd->kb_flags = KB_NO_DEVICE; /* device has not been found */ 13742421Syokota kbd->kb_name = name; 13842421Syokota kbd->kb_type = type; 13942421Syokota kbd->kb_unit = unit; 14044628Syokota kbd->kb_config = config & ~KB_CONF_PROBE_ONLY; 14142421Syokota kbd->kb_led = 0; /* unknown */ 14242421Syokota kbd->kb_io_base = port; 14342421Syokota kbd->kb_io_size = port_size; 14442421Syokota kbd->kb_data = NULL; 14542421Syokota kbd->kb_keymap = NULL; 14642421Syokota kbd->kb_accentmap = NULL; 14742421Syokota kbd->kb_fkeytab = NULL; 14842421Syokota kbd->kb_fkeytab_size = 0; 14944628Syokota kbd->kb_delay1 = KB_DELAY1; /* these values are advisory only */ 15044628Syokota kbd->kb_delay2 = KB_DELAY2; 15154382Syokota kbd->kb_count = 0L; 15280040Syokota bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact)); 15342421Syokota} 15442421Syokota 15542421Syokotavoid 15642421Syokotakbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap, 15742421Syokota fkeytab_t *fkeymap, int fkeymap_size) 15842421Syokota{ 15942421Syokota kbd->kb_keymap = keymap; 16042421Syokota kbd->kb_accentmap = accmap; 16142421Syokota kbd->kb_fkeytab = fkeymap; 16242421Syokota kbd->kb_fkeytab_size = fkeymap_size; 16342421Syokota} 16442421Syokota 16554545Syokota/* declare a new keyboard driver */ 16654545Syokotaint 16754545Syokotakbd_add_driver(keyboard_driver_t *driver) 16854545Syokota{ 16954545Syokota if (SLIST_NEXT(driver, link)) 170127752Sdes return (EINVAL); 17154545Syokota SLIST_INSERT_HEAD(&keyboard_drivers, driver, link); 172127752Sdes return (0); 17354545Syokota} 17454545Syokota 17554545Syokotaint 17654545Syokotakbd_delete_driver(keyboard_driver_t *driver) 17754545Syokota{ 17860938Sjake SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link); 17954545Syokota SLIST_NEXT(driver, link) = NULL; 180127752Sdes return (0); 18154545Syokota} 18254545Syokota 18342421Syokota/* register a keyboard and associate it with a function table */ 18442421Syokotaint 18542421Syokotakbd_register(keyboard_t *kbd) 18642421Syokota{ 18747295Syokota const keyboard_driver_t **list; 18847295Syokota const keyboard_driver_t *p; 189156126Semax keyboard_t *mux; 190156126Semax keyboard_info_t ki; 19142421Syokota int index; 19242421Syokota 193156126Semax mux = kbd_get_keyboard(kbd_find_keyboard("kbdmux", -1)); 194156126Semax 19542421Syokota for (index = 0; index < keyboards; ++index) { 19642421Syokota if (keyboard[index] == NULL) 19742421Syokota break; 19842421Syokota } 19944628Syokota if (index >= keyboards) { 20044628Syokota if (kbd_realloc_array()) 201127752Sdes return (-1); 20244628Syokota } 20342421Syokota 20442421Syokota kbd->kb_index = index; 20542421Syokota KBD_UNBUSY(kbd); 20642421Syokota KBD_VALID(kbd); 20742421Syokota kbd->kb_active = 0; /* disabled until someone calls kbd_enable() */ 20842421Syokota kbd->kb_token = NULL; 20942421Syokota kbd->kb_callback.kc_func = NULL; 21042421Syokota kbd->kb_callback.kc_arg = NULL; 21142421Syokota 21254545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 21354545Syokota if (strcmp(p->name, kbd->kb_name) == 0) { 21454545Syokota keyboard[index] = kbd; 21554545Syokota kbdsw[index] = p->kbdsw; 216156126Semax 217156126Semax if (mux != NULL) { 218156126Semax bzero(&ki, sizeof(ki)); 219156126Semax strcpy(ki.kb_name, kbd->kb_name); 220156126Semax ki.kb_unit = kbd->kb_unit; 221156126Semax 222156126Semax (*kbdsw[mux->kb_index]->ioctl) 223156126Semax (mux, KBADDKBD, (caddr_t) &ki); 224156126Semax } 225156126Semax 226127752Sdes return (index); 22754545Syokota } 22854545Syokota } 22978161Speter SET_FOREACH(list, kbddriver_set) { 23078161Speter p = *list; 23142421Syokota if (strcmp(p->name, kbd->kb_name) == 0) { 23242421Syokota keyboard[index] = kbd; 23342421Syokota kbdsw[index] = p->kbdsw; 234156126Semax 235156126Semax if (mux != NULL) { 236156126Semax bzero(&ki, sizeof(ki)); 237156126Semax strcpy(ki.kb_name, kbd->kb_name); 238156126Semax ki.kb_unit = kbd->kb_unit; 239156126Semax 240156126Semax (*kbdsw[mux->kb_index]->ioctl) 241156126Semax (mux, KBADDKBD, (caddr_t) &ki); 242156126Semax } 243156126Semax 244127752Sdes return (index); 24542421Syokota } 24642421Syokota } 24742421Syokota 248127752Sdes return (-1); 24942421Syokota} 25042421Syokota 25142421Syokotaint 25242421Syokotakbd_unregister(keyboard_t *kbd) 25342421Syokota{ 25442421Syokota int error; 25542421Syokota int s; 25642421Syokota 25742421Syokota if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards)) 258127752Sdes return (ENOENT); 25942421Syokota if (keyboard[kbd->kb_index] != kbd) 260127752Sdes return (ENOENT); 26142421Syokota 26242421Syokota s = spltty(); 26342421Syokota if (KBD_IS_BUSY(kbd)) { 26442421Syokota error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING, 265127752Sdes kbd->kb_callback.kc_arg); 26642421Syokota if (error) { 26742421Syokota splx(s); 268127752Sdes return (error); 26942421Syokota } 27042421Syokota if (KBD_IS_BUSY(kbd)) { 27142421Syokota splx(s); 272127752Sdes return (EBUSY); 27342421Syokota } 27442421Syokota } 27542421Syokota KBD_INVALID(kbd); 27642421Syokota keyboard[kbd->kb_index] = NULL; 27742421Syokota kbdsw[kbd->kb_index] = NULL; 27842421Syokota 27942421Syokota splx(s); 280127752Sdes return (0); 28142421Syokota} 28242421Syokota 28342421Syokota/* find a funciton table by the driver name */ 28442421Syokotakeyboard_switch_t 28542421Syokota*kbd_get_switch(char *driver) 28642421Syokota{ 28747295Syokota const keyboard_driver_t **list; 28847295Syokota const keyboard_driver_t *p; 28942421Syokota 29054545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 29154545Syokota if (strcmp(p->name, driver) == 0) 292127752Sdes return (p->kbdsw); 29354545Syokota } 29478161Speter SET_FOREACH(list, kbddriver_set) { 29578161Speter p = *list; 29642421Syokota if (strcmp(p->name, driver) == 0) 297127752Sdes return (p->kbdsw); 29842421Syokota } 29942421Syokota 300127752Sdes return (NULL); 30142421Syokota} 30242421Syokota 30342421Syokota/* 30442421Syokota * Keyboard client functions 30542421Syokota * Keyboard clients, such as the console driver `syscons' and the keyboard 30642421Syokota * cdev driver, use these functions to claim and release a keyboard for 30742421Syokota * exclusive use. 30842421Syokota */ 30942421Syokota 310147980Semax/* 311147980Semax * find the keyboard specified by a driver name and a unit number 312147980Semax * starting at given index 313147980Semax */ 31442421Syokotaint 315147980Semaxkbd_find_keyboard2(char *driver, int unit, int index) 31642421Syokota{ 31742421Syokota int i; 31842421Syokota 319147980Semax if ((index < 0) || (index >= keyboards)) 320147980Semax return (-1); 321147980Semax 322147980Semax for (i = index; i < keyboards; ++i) { 32342421Syokota if (keyboard[i] == NULL) 32442421Syokota continue; 32542421Syokota if (!KBD_IS_VALID(keyboard[i])) 32642421Syokota continue; 32742421Syokota if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver)) 32842421Syokota continue; 32942421Syokota if ((unit != -1) && (keyboard[i]->kb_unit != unit)) 33042421Syokota continue; 331127752Sdes return (i); 33242421Syokota } 333147980Semax 334127752Sdes return (-1); 33542421Syokota} 33642421Syokota 337147980Semax/* find the keyboard specified by a driver name and a unit number */ 338147980Semaxint 339147980Semaxkbd_find_keyboard(char *driver, int unit) 340147980Semax{ 341147980Semax return (kbd_find_keyboard2(driver, unit, 0)); 342147980Semax} 343147980Semax 34442421Syokota/* allocate a keyboard */ 34542421Syokotaint 34642421Syokotakbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func, 34742421Syokota void *arg) 34842421Syokota{ 34942421Syokota int index; 35042421Syokota int s; 35142421Syokota 35242421Syokota if (func == NULL) 353127752Sdes return (-1); 35442421Syokota 35542421Syokota s = spltty(); 35642421Syokota index = kbd_find_keyboard(driver, unit); 35742421Syokota if (index >= 0) { 35842421Syokota if (KBD_IS_BUSY(keyboard[index])) { 35942421Syokota splx(s); 360127752Sdes return (-1); 36142421Syokota } 36242421Syokota keyboard[index]->kb_token = id; 36342421Syokota KBD_BUSY(keyboard[index]); 36442421Syokota keyboard[index]->kb_callback.kc_func = func; 36542421Syokota keyboard[index]->kb_callback.kc_arg = arg; 36642421Syokota (*kbdsw[index]->clear_state)(keyboard[index]); 36742421Syokota } 36842421Syokota splx(s); 369127752Sdes return (index); 37042421Syokota} 37142421Syokota 37242421Syokotaint 37342421Syokotakbd_release(keyboard_t *kbd, void *id) 37442421Syokota{ 37542421Syokota int error; 37642421Syokota int s; 37742421Syokota 37842421Syokota s = spltty(); 37942421Syokota if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 38042421Syokota error = EINVAL; 38142421Syokota } else if (kbd->kb_token != id) { 38242421Syokota error = EPERM; 38342421Syokota } else { 38442421Syokota kbd->kb_token = NULL; 38542421Syokota KBD_UNBUSY(kbd); 38642421Syokota kbd->kb_callback.kc_func = NULL; 38742421Syokota kbd->kb_callback.kc_arg = NULL; 38842421Syokota (*kbdsw[kbd->kb_index]->clear_state)(kbd); 38942421Syokota error = 0; 39042421Syokota } 39142421Syokota splx(s); 392127752Sdes return (error); 39342421Syokota} 39442421Syokota 39542421Syokotaint 39642421Syokotakbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func, 39742421Syokota void *arg) 39842421Syokota{ 39942421Syokota int error; 40042421Syokota int s; 40142421Syokota 40242421Syokota s = spltty(); 40342421Syokota if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 40442421Syokota error = EINVAL; 40542421Syokota } else if (kbd->kb_token != id) { 40642421Syokota error = EPERM; 40742421Syokota } else if (func == NULL) { 40842421Syokota error = EINVAL; 40942421Syokota } else { 41042421Syokota kbd->kb_callback.kc_func = func; 41142421Syokota kbd->kb_callback.kc_arg = arg; 41242421Syokota error = 0; 41342421Syokota } 41442421Syokota splx(s); 415127752Sdes return (error); 41642421Syokota} 41742421Syokota 41842421Syokota/* get a keyboard structure */ 41942421Syokotakeyboard_t 42042421Syokota*kbd_get_keyboard(int index) 42142421Syokota{ 42242421Syokota if ((index < 0) || (index >= keyboards)) 423127752Sdes return (NULL); 42450154Syokota if (keyboard[index] == NULL) 425127752Sdes return (NULL); 42642421Syokota if (!KBD_IS_VALID(keyboard[index])) 427127752Sdes return (NULL); 428127752Sdes return (keyboard[index]); 42942421Syokota} 43042421Syokota 43142421Syokota/* 43242421Syokota * The back door for the console driver; configure keyboards 43342421Syokota * This function is for the kernel console to initialize keyboards 43442421Syokota * at very early stage. 43542421Syokota */ 43642421Syokota 43742421Syokotaint 43842421Syokotakbd_configure(int flags) 43942421Syokota{ 44047295Syokota const keyboard_driver_t **list; 44147295Syokota const keyboard_driver_t *p; 44242421Syokota 44354545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 44454545Syokota if (p->configure != NULL) 44554545Syokota (*p->configure)(flags); 44654545Syokota } 44778161Speter SET_FOREACH(list, kbddriver_set) { 44878161Speter p = *list; 44942421Syokota if (p->configure != NULL) 45042421Syokota (*p->configure)(flags); 45142421Syokota } 45242421Syokota 453127752Sdes return (0); 45442421Syokota} 45542421Syokota 45642421Syokota#ifdef KBD_INSTALL_CDEV 45742421Syokota 45842421Syokota/* 45942421Syokota * Virtual keyboard cdev driver functions 46042421Syokota * The virtual keyboard driver dispatches driver functions to 46142421Syokota * appropriate subdrivers. 46242421Syokota */ 46342421Syokota 46442421Syokota#define KBD_UNIT(dev) minor(dev) 46542421Syokota 46650154Syokotastatic d_open_t genkbdopen; 46750154Syokotastatic d_close_t genkbdclose; 46850154Syokotastatic d_read_t genkbdread; 46950154Syokotastatic d_write_t genkbdwrite; 47050154Syokotastatic d_ioctl_t genkbdioctl; 47150154Syokotastatic d_poll_t genkbdpoll; 47242421Syokota 47342421Syokota 47442421Syokotastatic struct cdevsw kbd_cdevsw = { 475126080Sphk .d_version = D_VERSION, 476126080Sphk .d_flags = D_NEEDGIANT, 477111815Sphk .d_open = genkbdopen, 478111815Sphk .d_close = genkbdclose, 479111815Sphk .d_read = genkbdread, 480111815Sphk .d_write = genkbdwrite, 481111815Sphk .d_ioctl = genkbdioctl, 482111815Sphk .d_poll = genkbdpoll, 483111815Sphk .d_name = "kbd", 48442421Syokota}; 48542421Syokota 48642421Syokotaint 48750154Syokotakbd_attach(keyboard_t *kbd) 48842421Syokota{ 48942421Syokota 49042421Syokota if (kbd->kb_index >= keyboards) 491127752Sdes return (EINVAL); 49242421Syokota if (keyboard[kbd->kb_index] != kbd) 493127752Sdes return (EINVAL); 49442421Syokota 495127751Sdes kbd->kb_dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 496127751Sdes 0600, "%s%r", kbd->kb_name, kbd->kb_unit); 497125087Sdes make_dev_alias(kbd->kb_dev, "kbd%r", kbd->kb_index); 498120502Sphk kbd->kb_dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF, 499127751Sdes M_WAITOK | M_ZERO); 50042421Syokota printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit); 501127752Sdes return (0); 50242421Syokota} 50342421Syokota 50442421Syokotaint 50550154Syokotakbd_detach(keyboard_t *kbd) 50642421Syokota{ 50754545Syokota 50842421Syokota if (kbd->kb_index >= keyboards) 509127752Sdes return (EINVAL); 51042421Syokota if (keyboard[kbd->kb_index] != kbd) 511127752Sdes return (EINVAL); 51242421Syokota 513120502Sphk free(kbd->kb_dev->si_drv1, M_DEVBUF); 514120502Sphk destroy_dev(kbd->kb_dev); 51554545Syokota 516127752Sdes return (0); 51742421Syokota} 51842421Syokota 51942421Syokota/* 52042421Syokota * Generic keyboard cdev driver functions 52142421Syokota * Keyboard subdrivers may call these functions to implement common 52242421Syokota * driver functions. 52342421Syokota */ 52442421Syokota 52542421Syokota#define KB_QSIZE 512 52642421Syokota#define KB_BUFSIZE 64 52742421Syokota 52842421Syokotastatic kbd_callback_func_t genkbd_event; 52942421Syokota 53050154Syokotastatic int 531130585Sphkgenkbdopen(struct cdev *dev, int mode, int flag, struct thread *td) 53242421Syokota{ 53350154Syokota keyboard_t *kbd; 53450154Syokota genkbd_softc_t *sc; 53542421Syokota int s; 53642421Syokota int i; 53742421Syokota 53842421Syokota s = spltty(); 53950154Syokota sc = dev->si_drv1; 54050154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 54150154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 54242421Syokota splx(s); 543127752Sdes return (ENXIO); 54442421Syokota } 54542421Syokota i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc, 546127751Sdes genkbd_event, (void *)sc); 54742421Syokota if (i < 0) { 54842421Syokota splx(s); 549127752Sdes return (EBUSY); 55042421Syokota } 55142421Syokota /* assert(i == kbd->kb_index) */ 55242421Syokota /* assert(kbd == kbd_get_keyboard(i)) */ 55342421Syokota 55442421Syokota /* 55542421Syokota * NOTE: even when we have successfully claimed a keyboard, 55642421Syokota * the device may still be missing (!KBD_HAS_DEVICE(kbd)). 55742421Syokota */ 55842421Syokota 55942421Syokota#if 0 56042421Syokota bzero(&sc->gkb_q, sizeof(sc->gkb_q)); 56142421Syokota#endif 56242421Syokota clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */ 56342421Syokota splx(s); 56442421Syokota 565127752Sdes return (0); 56642421Syokota} 56742421Syokota 56850154Syokotastatic int 569130585Sphkgenkbdclose(struct cdev *dev, int mode, int flag, struct thread *td) 57042421Syokota{ 57150154Syokota keyboard_t *kbd; 57250154Syokota genkbd_softc_t *sc; 57342421Syokota int s; 57442421Syokota 57542421Syokota /* 57642421Syokota * NOTE: the device may have already become invalid. 57750154Syokota * kbd == NULL || !KBD_IS_VALID(kbd) 57842421Syokota */ 57942421Syokota s = spltty(); 58050154Syokota sc = dev->si_drv1; 58150154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 58250154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 58350154Syokota /* XXX: we shall be forgiving and don't report error... */ 58450154Syokota } else { 58550154Syokota kbd_release(kbd, (void *)sc); 58642421Syokota#if 0 58750154Syokota clist_free_cblocks(&sc->gkb_q); 58842421Syokota#endif 58950154Syokota } 59042421Syokota splx(s); 591127752Sdes return (0); 59242421Syokota} 59342421Syokota 59450154Syokotastatic int 595130585Sphkgenkbdread(struct cdev *dev, struct uio *uio, int flag) 59642421Syokota{ 59750154Syokota keyboard_t *kbd; 59850154Syokota genkbd_softc_t *sc; 59942421Syokota u_char buffer[KB_BUFSIZE]; 60042421Syokota int len; 60142421Syokota int error; 60242421Syokota int s; 60342421Syokota 60442421Syokota /* wait for input */ 60542421Syokota s = spltty(); 60650154Syokota sc = dev->si_drv1; 60750154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 60850154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 60950154Syokota splx(s); 610127752Sdes return (ENXIO); 61150154Syokota } 61242421Syokota while (sc->gkb_q.c_cc == 0) { 613139193Sphk if (flag & O_NONBLOCK) { 61442421Syokota splx(s); 615127752Sdes return (EWOULDBLOCK); 61642421Syokota } 61742421Syokota sc->gkb_flags |= KB_ASLEEP; 618111748Sdes error = tsleep(sc, PZERO | PCATCH, "kbdrea", 0); 61950154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 62050154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) { 62150154Syokota splx(s); 622127752Sdes return (ENXIO); /* our keyboard has gone... */ 62350154Syokota } 62442421Syokota if (error) { 62542421Syokota sc->gkb_flags &= ~KB_ASLEEP; 62642421Syokota splx(s); 627127752Sdes return (error); 62842421Syokota } 62942421Syokota } 63042421Syokota splx(s); 63142421Syokota 63242421Syokota /* copy as much input as possible */ 63342421Syokota error = 0; 63442421Syokota while (uio->uio_resid > 0) { 63542421Syokota len = imin(uio->uio_resid, sizeof(buffer)); 63642421Syokota len = q_to_b(&sc->gkb_q, buffer, len); 63742421Syokota if (len <= 0) 63842421Syokota break; 63942421Syokota error = uiomove(buffer, len, uio); 64042421Syokota if (error) 64142421Syokota break; 64242421Syokota } 64342421Syokota 644127752Sdes return (error); 64542421Syokota} 64642421Syokota 64750154Syokotastatic int 648130585Sphkgenkbdwrite(struct cdev *dev, struct uio *uio, int flag) 64942421Syokota{ 65050154Syokota keyboard_t *kbd; 65150154Syokota 65250154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 65350154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) 654127752Sdes return (ENXIO); 655127752Sdes return (ENODEV); 65642421Syokota} 65742421Syokota 65850154Syokotastatic int 659130585Sphkgenkbdioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 66042421Syokota{ 66150154Syokota keyboard_t *kbd; 66242421Syokota int error; 66342421Syokota 66450154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 66550154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) 666127752Sdes return (ENXIO); 66742421Syokota error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg); 66842421Syokota if (error == ENOIOCTL) 66942421Syokota error = ENODEV; 670127752Sdes return (error); 67142421Syokota} 67242421Syokota 67350154Syokotastatic int 674130585Sphkgenkbdpoll(struct cdev *dev, int events, struct thread *td) 67542421Syokota{ 67650154Syokota keyboard_t *kbd; 67750154Syokota genkbd_softc_t *sc; 67842421Syokota int revents; 67942421Syokota int s; 68042421Syokota 68142421Syokota revents = 0; 68242421Syokota s = spltty(); 68350154Syokota sc = dev->si_drv1; 68450154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 68550154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 68650154Syokota revents = POLLHUP; /* the keyboard has gone */ 68750154Syokota } else if (events & (POLLIN | POLLRDNORM)) { 68850154Syokota if (sc->gkb_q.c_cc > 0) 68950154Syokota revents = events & (POLLIN | POLLRDNORM); 69042421Syokota else 69183366Sjulian selrecord(td, &sc->gkb_rsel); 69242421Syokota } 69342421Syokota splx(s); 694127752Sdes return (revents); 69542421Syokota} 69642421Syokota 69742421Syokotastatic int 69842421Syokotagenkbd_event(keyboard_t *kbd, int event, void *arg) 69942421Syokota{ 70042421Syokota genkbd_softc_t *sc; 70142421Syokota size_t len; 70242421Syokota u_char *cp; 70342421Syokota int mode; 70442421Syokota int c; 70542421Syokota 70642421Syokota /* assert(KBD_IS_VALID(kbd)) */ 70742421Syokota sc = (genkbd_softc_t *)arg; 70842421Syokota 70942421Syokota switch (event) { 71042421Syokota case KBDIO_KEYINPUT: 71142421Syokota break; 71242421Syokota case KBDIO_UNLOADING: 71342421Syokota /* the keyboard is going... */ 71442421Syokota kbd_release(kbd, (void *)sc); 71550154Syokota if (sc->gkb_flags & KB_ASLEEP) { 71650154Syokota sc->gkb_flags &= ~KB_ASLEEP; 717111748Sdes wakeup(sc); 71850154Syokota } 719122352Stanimura selwakeuppri(&sc->gkb_rsel, PZERO); 720127752Sdes return (0); 72142421Syokota default: 722127752Sdes return (EINVAL); 72342421Syokota } 72442421Syokota 72542421Syokota /* obtain the current key input mode */ 72642421Syokota if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode)) 72742421Syokota mode = K_XLATE; 72842421Syokota 72942421Syokota /* read all pending input */ 73042421Syokota while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) { 73142421Syokota c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE); 73242421Syokota if (c == NOKEY) 73342421Syokota continue; 73442421Syokota if (c == ERRKEY) /* XXX: ring bell? */ 73542421Syokota continue; 73642421Syokota if (!KBD_IS_BUSY(kbd)) 73742421Syokota /* the device is not open, discard the input */ 73842421Syokota continue; 73942421Syokota 74042421Syokota /* store the byte as is for K_RAW and K_CODE modes */ 74142421Syokota if (mode != K_XLATE) { 74242421Syokota putc(KEYCHAR(c), &sc->gkb_q); 74342421Syokota continue; 74442421Syokota } 74542421Syokota 74642421Syokota /* K_XLATE */ 74742421Syokota if (c & RELKEY) /* key release is ignored */ 74842421Syokota continue; 74942421Syokota 75042421Syokota /* process special keys; most of them are just ignored... */ 75142421Syokota if (c & SPCLKEY) { 75242421Syokota switch (KEYCHAR(c)) { 75354382Syokota default: 75442421Syokota /* ignore them... */ 75542421Syokota continue; 75642421Syokota case BTAB: /* a backtab: ESC [ Z */ 75742421Syokota putc(0x1b, &sc->gkb_q); 75842421Syokota putc('[', &sc->gkb_q); 75942421Syokota putc('Z', &sc->gkb_q); 76042421Syokota continue; 76142421Syokota } 76242421Syokota } 76342421Syokota 76442421Syokota /* normal chars, normal chars with the META, function keys */ 76542421Syokota switch (KEYFLAGS(c)) { 76642421Syokota case 0: /* a normal char */ 76742421Syokota putc(KEYCHAR(c), &sc->gkb_q); 76842421Syokota break; 76942421Syokota case MKEY: /* the META flag: prepend ESC */ 77042421Syokota putc(0x1b, &sc->gkb_q); 77142421Syokota putc(KEYCHAR(c), &sc->gkb_q); 77242421Syokota break; 77342421Syokota case FKEY | SPCLKEY: /* a function key, return string */ 77442421Syokota cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd, 775127751Sdes KEYCHAR(c), &len); 77642421Syokota if (cp != NULL) { 77742421Syokota while (len-- > 0) 77842421Syokota putc(*cp++, &sc->gkb_q); 77942421Syokota } 78042421Syokota break; 78142421Syokota } 78242421Syokota } 78342421Syokota 78442421Syokota /* wake up sleeping/polling processes */ 78542421Syokota if (sc->gkb_q.c_cc > 0) { 78642421Syokota if (sc->gkb_flags & KB_ASLEEP) { 78742421Syokota sc->gkb_flags &= ~KB_ASLEEP; 788111748Sdes wakeup(sc); 78942421Syokota } 790122352Stanimura selwakeuppri(&sc->gkb_rsel, PZERO); 79142421Syokota } 79242421Syokota 793127752Sdes return (0); 79442421Syokota} 79542421Syokota 79642421Syokota#endif /* KBD_INSTALL_CDEV */ 79742421Syokota 79842421Syokota/* 79942421Syokota * Generic low-level keyboard functions 80042421Syokota * The low-level functions in the keyboard subdriver may use these 80142421Syokota * functions. 80242421Syokota */ 80342421Syokota 804112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 805112050Sdwmalonestatic int key_change_ok(struct keyent_t *, struct keyent_t *, struct thread *); 806112050Sdwmalonestatic int keymap_change_ok(keymap_t *, keymap_t *, struct thread *); 807112050Sdwmalonestatic int accent_change_ok(accentmap_t *, accentmap_t *, struct thread *); 808112050Sdwmalonestatic int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct thread *); 809112050Sdwmalone#endif 810112050Sdwmalone 81142421Syokotaint 81242421Syokotagenkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 81342421Syokota{ 81442421Syokota keyarg_t *keyp; 81542421Syokota fkeyarg_t *fkeyp; 81642421Syokota int s; 81742421Syokota int i; 818112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 819112050Sdwmalone int error; 820112050Sdwmalone#endif 82142421Syokota 82242421Syokota s = spltty(); 82342421Syokota switch (cmd) { 82442421Syokota 82542421Syokota case KDGKBINFO: /* get keyboard information */ 82642421Syokota ((keyboard_info_t *)arg)->kb_index = kbd->kb_index; 82742421Syokota i = imin(strlen(kbd->kb_name) + 1, 828127751Sdes sizeof(((keyboard_info_t *)arg)->kb_name)); 82942421Syokota bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i); 83042421Syokota ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit; 83142421Syokota ((keyboard_info_t *)arg)->kb_type = kbd->kb_type; 83242421Syokota ((keyboard_info_t *)arg)->kb_config = kbd->kb_config; 83342421Syokota ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags; 83442421Syokota break; 83542421Syokota 83642421Syokota case KDGKBTYPE: /* get keyboard type */ 83742421Syokota *(int *)arg = kbd->kb_type; 83842421Syokota break; 83942421Syokota 84054543Syokota case KDGETREPEAT: /* get keyboard repeat rate */ 84154543Syokota ((int *)arg)[0] = kbd->kb_delay1; 842127751Sdes ((int *)arg)[1] = kbd->kb_delay2; 84354543Syokota break; 84454543Syokota 84542421Syokota case GIO_KEYMAP: /* get keyboard translation table */ 84642421Syokota bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap)); 84742421Syokota break; 84842421Syokota case PIO_KEYMAP: /* set keyboard translation table */ 84944628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 850112050Sdwmalone error = keymap_change_ok(kbd->kb_keymap, (keymap_t *)arg, 851112050Sdwmalone curthread); 852112050Sdwmalone if (error != 0) { 853112050Sdwmalone splx(s); 854127752Sdes return (error); 855112050Sdwmalone } 85642421Syokota bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 85742421Syokota bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap)); 85842421Syokota break; 85944628Syokota#else 86044628Syokota splx(s); 861127752Sdes return (ENODEV); 86244628Syokota#endif 86342421Syokota 86442421Syokota case GIO_KEYMAPENT: /* get keyboard translation table entry */ 86542421Syokota keyp = (keyarg_t *)arg; 866127751Sdes if (keyp->keynum >= sizeof(kbd->kb_keymap->key) / 867127751Sdes sizeof(kbd->kb_keymap->key[0])) { 86842421Syokota splx(s); 869127752Sdes return (EINVAL); 87042421Syokota } 87142573Syokota bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key, 872127751Sdes sizeof(keyp->key)); 87342421Syokota break; 87442421Syokota case PIO_KEYMAPENT: /* set keyboard translation table entry */ 87544628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 87642421Syokota keyp = (keyarg_t *)arg; 877127751Sdes if (keyp->keynum >= sizeof(kbd->kb_keymap->key) / 878127751Sdes sizeof(kbd->kb_keymap->key[0])) { 87942421Syokota splx(s); 880127752Sdes return (EINVAL); 88142421Syokota } 882112050Sdwmalone error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum], 883112050Sdwmalone &keyp->key, curthread); 884112050Sdwmalone if (error != 0) { 885112050Sdwmalone splx(s); 886127752Sdes return (error); 887112050Sdwmalone } 88842573Syokota bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum], 889127751Sdes sizeof(keyp->key)); 89042421Syokota break; 89144628Syokota#else 89244628Syokota splx(s); 893127752Sdes return (ENODEV); 89444628Syokota#endif 89542421Syokota 89642421Syokota case GIO_DEADKEYMAP: /* get accent key translation table */ 89742421Syokota bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap)); 89842421Syokota break; 89942421Syokota case PIO_DEADKEYMAP: /* set accent key translation table */ 90044628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 901112050Sdwmalone error = accent_change_ok(kbd->kb_accentmap, 902112050Sdwmalone (accentmap_t *)arg, curthread); 903112050Sdwmalone if (error != 0) { 904112050Sdwmalone splx(s); 905127752Sdes return (error); 906112050Sdwmalone } 90742421Syokota bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 90842421Syokota break; 90944628Syokota#else 91044628Syokota splx(s); 911127752Sdes return (ENODEV); 91244628Syokota#endif 91342421Syokota 91442421Syokota case GETFKEY: /* get functionkey string */ 91542421Syokota fkeyp = (fkeyarg_t *)arg; 91642421Syokota if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 91742421Syokota splx(s); 918127752Sdes return (EINVAL); 91942421Syokota } 92042421Syokota bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef, 921127751Sdes kbd->kb_fkeytab[fkeyp->keynum].len); 92242421Syokota fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len; 92342421Syokota break; 92442421Syokota case SETFKEY: /* set functionkey string */ 92544628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 92642421Syokota fkeyp = (fkeyarg_t *)arg; 92742421Syokota if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 92842421Syokota splx(s); 929127752Sdes return (EINVAL); 93042421Syokota } 931112050Sdwmalone error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum], 932112050Sdwmalone fkeyp, curthread); 933112050Sdwmalone if (error != 0) { 934112050Sdwmalone splx(s); 935127752Sdes return (error); 936112050Sdwmalone } 93742421Syokota kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK); 93842421Syokota bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str, 939127751Sdes kbd->kb_fkeytab[fkeyp->keynum].len); 94042421Syokota break; 94144628Syokota#else 94244628Syokota splx(s); 943127752Sdes return (ENODEV); 94444628Syokota#endif 94542421Syokota 94642421Syokota default: 94742421Syokota splx(s); 948127752Sdes return (ENOIOCTL); 94942421Syokota } 95042421Syokota 95142421Syokota splx(s); 952127752Sdes return (0); 95342421Syokota} 95442421Syokota 955112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 956112050Sdwmalone#define RESTRICTED_KEY(key, i) \ 957112050Sdwmalone ((key->spcl & (0x80 >> i)) && \ 958112050Sdwmalone (key->map[i] == RBT || key->map[i] == SUSP || \ 959112050Sdwmalone key->map[i] == STBY || key->map[i] == DBG || \ 960112050Sdwmalone key->map[i] == PNC || key->map[i] == HALT || \ 961112050Sdwmalone key->map[i] == PDWN)) 962112050Sdwmalone 963112050Sdwmalonestatic int 964112050Sdwmalonekey_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct thread *td) 965112050Sdwmalone{ 966112050Sdwmalone int i; 967112050Sdwmalone 968112050Sdwmalone /* Low keymap_restrict_change means any changes are OK. */ 969112050Sdwmalone if (keymap_restrict_change <= 0) 970127752Sdes return (0); 971112050Sdwmalone 972112050Sdwmalone /* High keymap_restrict_change means only root can change the keymap. */ 973112050Sdwmalone if (keymap_restrict_change >= 2) { 974112050Sdwmalone for (i = 0; i < NUM_STATES; i++) 975112050Sdwmalone if (oldkey->map[i] != newkey->map[i]) 976164033Srwatson return priv_check(td, PRIV_KEYBOARD); 977112050Sdwmalone if (oldkey->spcl != newkey->spcl) 978164033Srwatson return priv_check(td, PRIV_KEYBOARD); 979112050Sdwmalone if (oldkey->flgs != newkey->flgs) 980164033Srwatson return priv_check(td, PRIV_KEYBOARD); 981127752Sdes return (0); 982112050Sdwmalone } 983112050Sdwmalone 984112050Sdwmalone /* Otherwise we have to see if any special keys are being changed. */ 985112050Sdwmalone for (i = 0; i < NUM_STATES; i++) { 986112050Sdwmalone /* 987112050Sdwmalone * If either the oldkey or the newkey action is restricted 988112050Sdwmalone * then we must make sure that the action doesn't change. 989112050Sdwmalone */ 990112050Sdwmalone if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i)) 991112050Sdwmalone continue; 992112050Sdwmalone if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i)) 993112050Sdwmalone && oldkey->map[i] == newkey->map[i]) 994112050Sdwmalone continue; 995164033Srwatson return priv_check(td, PRIV_KEYBOARD); 996112050Sdwmalone } 997112050Sdwmalone 998127752Sdes return (0); 999112050Sdwmalone} 1000112050Sdwmalone 1001112050Sdwmalonestatic int 1002112050Sdwmalonekeymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct thread *td) 1003112050Sdwmalone{ 1004112050Sdwmalone int keycode, error; 1005112050Sdwmalone 1006112050Sdwmalone for (keycode = 0; keycode < NUM_KEYS; keycode++) { 1007112050Sdwmalone if ((error = key_change_ok(&oldmap->key[keycode], 1008112050Sdwmalone &newmap->key[keycode], td)) != 0) 1009127752Sdes return (error); 1010112050Sdwmalone } 1011127752Sdes return (0); 1012112050Sdwmalone} 1013112050Sdwmalone 1014112050Sdwmalonestatic int 1015112050Sdwmaloneaccent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct thread *td) 1016112050Sdwmalone{ 1017112050Sdwmalone struct acc_t *oldacc, *newacc; 1018112050Sdwmalone int accent, i; 1019112050Sdwmalone 1020112050Sdwmalone if (keymap_restrict_change <= 2) 1021127752Sdes return (0); 1022112050Sdwmalone 1023112050Sdwmalone if (oldmap->n_accs != newmap->n_accs) 1024164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1025112050Sdwmalone 1026112050Sdwmalone for (accent = 0; accent < oldmap->n_accs; accent++) { 1027112050Sdwmalone oldacc = &oldmap->acc[accent]; 1028112050Sdwmalone newacc = &newmap->acc[accent]; 1029112050Sdwmalone if (oldacc->accchar != newacc->accchar) 1030164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1031112050Sdwmalone for (i = 0; i < NUM_ACCENTCHARS; ++i) { 1032112050Sdwmalone if (oldacc->map[i][0] != newacc->map[i][0]) 1033164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1034112050Sdwmalone if (oldacc->map[i][0] == 0) /* end of table */ 1035112050Sdwmalone break; 1036112050Sdwmalone if (oldacc->map[i][1] != newacc->map[i][1]) 1037164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1038112050Sdwmalone } 1039112050Sdwmalone } 1040112050Sdwmalone 1041127752Sdes return (0); 1042112050Sdwmalone} 1043112050Sdwmalone 1044112050Sdwmalonestatic int 1045112050Sdwmalonefkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct thread *td) 1046112050Sdwmalone{ 1047112050Sdwmalone if (keymap_restrict_change <= 3) 1048127752Sdes return (0); 1049112050Sdwmalone 1050112050Sdwmalone if (oldkey->len != newkey->flen || 1051112050Sdwmalone bcmp(oldkey->str, newkey->keydef, oldkey->len) != 0) 1052164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1053112050Sdwmalone 1054127752Sdes return (0); 1055112050Sdwmalone} 1056112050Sdwmalone#endif 1057112050Sdwmalone 105842421Syokota/* get a pointer to the string associated with the given function key */ 105942421Syokotau_char 106042421Syokota*genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len) 106142421Syokota{ 106242421Syokota if (kbd == NULL) 1063127752Sdes return (NULL); 106442421Syokota fkey -= F_FN; 106542421Syokota if (fkey > kbd->kb_fkeytab_size) 1066127752Sdes return (NULL); 106742421Syokota *len = kbd->kb_fkeytab[fkey].len; 1068127752Sdes return (kbd->kb_fkeytab[fkey].str); 106942421Syokota} 107042421Syokota 107142421Syokota/* diagnostic dump */ 107242421Syokotastatic char 107342421Syokota*get_kbd_type_name(int type) 107442421Syokota{ 107542421Syokota static struct { 107642421Syokota int type; 107742421Syokota char *name; 107842421Syokota } name_table[] = { 107942421Syokota { KB_84, "AT 84" }, 108042421Syokota { KB_101, "AT 101/102" }, 108142421Syokota { KB_OTHER, "generic" }, 108242421Syokota }; 108342421Syokota int i; 108442421Syokota 108542421Syokota for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) { 108642421Syokota if (type == name_table[i].type) 1087127752Sdes return (name_table[i].name); 108842421Syokota } 1089127752Sdes return ("unknown"); 109042421Syokota} 109142421Syokota 109242421Syokotavoid 109342421Syokotagenkbd_diag(keyboard_t *kbd, int level) 109442421Syokota{ 109542421Syokota if (level > 0) { 1096127751Sdes printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x", 1097127751Sdes kbd->kb_index, kbd->kb_name, kbd->kb_unit, 1098127751Sdes get_kbd_type_name(kbd->kb_type), kbd->kb_type, 1099127751Sdes kbd->kb_config, kbd->kb_flags); 110042421Syokota if (kbd->kb_io_base > 0) 1101127751Sdes printf(", port:0x%x-0x%x", kbd->kb_io_base, 1102127751Sdes kbd->kb_io_base + kbd->kb_io_size - 1); 110342421Syokota printf("\n"); 110442421Syokota } 110542421Syokota} 110642421Syokota 110742421Syokota#define set_lockkey_state(k, s, l) \ 110842421Syokota if (!((s) & l ## DOWN)) { \ 110942421Syokota int i; \ 111042421Syokota (s) |= l ## DOWN; \ 111142421Syokota (s) ^= l ## ED; \ 111242421Syokota i = (s) & LOCK_MASK; \ 111342421Syokota (*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \ 111442421Syokota } 111542421Syokota 111642421Syokotastatic u_int 111742421Syokotasave_accent_key(keyboard_t *kbd, u_int key, int *accents) 111842421Syokota{ 111942421Syokota int i; 112042421Syokota 112142421Syokota /* make an index into the accent map */ 112242421Syokota i = key - F_ACC + 1; 112342421Syokota if ((i > kbd->kb_accentmap->n_accs) 112442421Syokota || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) { 112542421Syokota /* the index is out of range or pointing to an empty entry */ 112642421Syokota *accents = 0; 1127127752Sdes return (ERRKEY); 112842421Syokota } 112942421Syokota 1130127751Sdes /* 1131127751Sdes * If the same accent key has been hit twice, produce the accent 1132127751Sdes * char itself. 113342421Syokota */ 113442421Syokota if (i == *accents) { 113542421Syokota key = kbd->kb_accentmap->acc[i - 1].accchar; 113642421Syokota *accents = 0; 1137127752Sdes return (key); 113842421Syokota } 113942421Syokota 114042421Syokota /* remember the index and wait for the next key */ 1141127751Sdes *accents = i; 1142127752Sdes return (NOKEY); 114342421Syokota} 114442421Syokota 114542421Syokotastatic u_int 114642421Syokotamake_accent_char(keyboard_t *kbd, u_int ch, int *accents) 114742421Syokota{ 114842421Syokota struct acc_t *acc; 114942421Syokota int i; 115042421Syokota 115142421Syokota acc = &kbd->kb_accentmap->acc[*accents - 1]; 115242421Syokota *accents = 0; 115342421Syokota 1154127751Sdes /* 115542421Syokota * If the accent key is followed by the space key, 115642421Syokota * produce the accent char itself. 115742421Syokota */ 115842421Syokota if (ch == ' ') 1159127752Sdes return (acc->accchar); 116042421Syokota 116142421Syokota /* scan the accent map */ 116242421Syokota for (i = 0; i < NUM_ACCENTCHARS; ++i) { 116342421Syokota if (acc->map[i][0] == 0) /* end of table */ 116442421Syokota break; 116542421Syokota if (acc->map[i][0] == ch) 1166127752Sdes return (acc->map[i][1]); 116742421Syokota } 116842421Syokota /* this char cannot be accented... */ 1169127752Sdes return (ERRKEY); 117042421Syokota} 117142421Syokota 117242421Syokotaint 117342421Syokotagenkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate, 117442421Syokota int *accents) 117542421Syokota{ 117642421Syokota struct keyent_t *key; 117742421Syokota int state = *shiftstate; 117842421Syokota int action; 117942421Syokota int f; 118042421Syokota int i; 118142421Syokota 118254382Syokota i = keycode; 118342421Syokota f = state & (AGRS | ALKED); 118442421Syokota if ((f == AGRS1) || (f == AGRS2) || (f == ALKED)) 118554382Syokota i += ALTGR_OFFSET; 118654382Syokota key = &kbd->kb_keymap->key[i]; 118742421Syokota i = ((state & SHIFTS) ? 1 : 0) 118842421Syokota | ((state & CTLS) ? 2 : 0) 118942421Syokota | ((state & ALTS) ? 4 : 0); 119042421Syokota if (((key->flgs & FLAG_LOCK_C) && (state & CLKED)) 119142421Syokota || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) ) 119242421Syokota i ^= 1; 119342421Syokota 119442421Syokota if (up) { /* break: key released */ 119580040Syokota action = kbd->kb_lastact[keycode]; 119680040Syokota kbd->kb_lastact[keycode] = NOP; 119780040Syokota switch (action) { 119880040Syokota case LSHA: 119980040Syokota if (state & SHIFTAON) { 120080040Syokota set_lockkey_state(kbd, state, ALK); 120180040Syokota state &= ~ALKDOWN; 120280040Syokota } 120380040Syokota action = LSH; 120480040Syokota /* FALL THROUGH */ 120580040Syokota case LSH: 120680040Syokota state &= ~SHIFTS1; 120780040Syokota break; 120880040Syokota case RSHA: 120980040Syokota if (state & SHIFTAON) { 121080040Syokota set_lockkey_state(kbd, state, ALK); 121180040Syokota state &= ~ALKDOWN; 121280040Syokota } 121380040Syokota action = RSH; 121480040Syokota /* FALL THROUGH */ 121580040Syokota case RSH: 121680040Syokota state &= ~SHIFTS2; 121780040Syokota break; 121880040Syokota case LCTRA: 121980040Syokota if (state & SHIFTAON) { 122080040Syokota set_lockkey_state(kbd, state, ALK); 122180040Syokota state &= ~ALKDOWN; 122280040Syokota } 122380040Syokota action = LCTR; 122480040Syokota /* FALL THROUGH */ 122580040Syokota case LCTR: 122680040Syokota state &= ~CTLS1; 122780040Syokota break; 122880040Syokota case RCTRA: 122980040Syokota if (state & SHIFTAON) { 123080040Syokota set_lockkey_state(kbd, state, ALK); 123180040Syokota state &= ~ALKDOWN; 123280040Syokota } 123380040Syokota action = RCTR; 123480040Syokota /* FALL THROUGH */ 123580040Syokota case RCTR: 123680040Syokota state &= ~CTLS2; 123780040Syokota break; 123880040Syokota case LALTA: 123980040Syokota if (state & SHIFTAON) { 124080040Syokota set_lockkey_state(kbd, state, ALK); 124180040Syokota state &= ~ALKDOWN; 124280040Syokota } 124380040Syokota action = LALT; 124480040Syokota /* FALL THROUGH */ 124580040Syokota case LALT: 124680040Syokota state &= ~ALTS1; 124780040Syokota break; 124880040Syokota case RALTA: 124980040Syokota if (state & SHIFTAON) { 125080040Syokota set_lockkey_state(kbd, state, ALK); 125180040Syokota state &= ~ALKDOWN; 125280040Syokota } 125380040Syokota action = RALT; 125480040Syokota /* FALL THROUGH */ 125580040Syokota case RALT: 125680040Syokota state &= ~ALTS2; 125780040Syokota break; 125880040Syokota case ASH: 125980040Syokota state &= ~AGRS1; 126080040Syokota break; 126180040Syokota case META: 126280040Syokota state &= ~METAS1; 126380040Syokota break; 126480040Syokota case NLK: 126580040Syokota state &= ~NLKDOWN; 126680040Syokota break; 126780040Syokota case CLK: 126842421Syokota#ifndef PC98 126980040Syokota state &= ~CLKDOWN; 127042421Syokota#else 127180040Syokota state &= ~CLKED; 127280040Syokota i = state & LOCK_MASK; 127380040Syokota (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED, 127480040Syokota (caddr_t)&i); 127542421Syokota#endif 127680040Syokota break; 127780040Syokota case SLK: 127880040Syokota state &= ~SLKDOWN; 127980040Syokota break; 128080040Syokota case ALK: 128180040Syokota state &= ~ALKDOWN; 128280040Syokota break; 128380040Syokota case NOP: 128480040Syokota /* release events of regular keys are not reported */ 128580040Syokota *shiftstate &= ~SHIFTAON; 1286127752Sdes return (NOKEY); 128742421Syokota } 128880040Syokota *shiftstate = state & ~SHIFTAON; 128980040Syokota return (SPCLKEY | RELKEY | action); 129042421Syokota } else { /* make: key pressed */ 129180040Syokota action = key->map[i]; 129255820Syokota state &= ~SHIFTAON; 129342421Syokota if (key->spcl & (0x80 >> i)) { 129442421Syokota /* special keys */ 129580040Syokota if (kbd->kb_lastact[keycode] == NOP) 129680040Syokota kbd->kb_lastact[keycode] = action; 129780040Syokota if (kbd->kb_lastact[keycode] != action) 129880040Syokota action = NOP; 129942421Syokota switch (action) { 130042421Syokota /* LOCKING KEYS */ 130142421Syokota case NLK: 130242421Syokota set_lockkey_state(kbd, state, NLK); 130342421Syokota break; 130442421Syokota case CLK: 130542421Syokota#ifndef PC98 130642421Syokota set_lockkey_state(kbd, state, CLK); 130742421Syokota#else 130842421Syokota state |= CLKED; 130942421Syokota i = state & LOCK_MASK; 131042421Syokota (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED, 131142421Syokota (caddr_t)&i); 131242421Syokota#endif 131342421Syokota break; 131442421Syokota case SLK: 131542421Syokota set_lockkey_state(kbd, state, SLK); 131642421Syokota break; 131742421Syokota case ALK: 131842421Syokota set_lockkey_state(kbd, state, ALK); 131942421Syokota break; 132042421Syokota /* NON-LOCKING KEYS */ 132142421Syokota case SPSC: case RBT: case SUSP: case STBY: 132254382Syokota case DBG: case NEXT: case PREV: case PNC: 132365759Sdwmalone case HALT: case PDWN: 132442421Syokota *accents = 0; 132542421Syokota break; 132642421Syokota case BTAB: 132742421Syokota *accents = 0; 132842421Syokota action |= BKEY; 132942421Syokota break; 133054382Syokota case LSHA: 133155820Syokota state |= SHIFTAON; 133254382Syokota action = LSH; 133354382Syokota /* FALL THROUGH */ 133442421Syokota case LSH: 133542421Syokota state |= SHIFTS1; 133642421Syokota break; 133754382Syokota case RSHA: 133855820Syokota state |= SHIFTAON; 133954382Syokota action = RSH; 134054382Syokota /* FALL THROUGH */ 134142421Syokota case RSH: 134242421Syokota state |= SHIFTS2; 134342421Syokota break; 134454382Syokota case LCTRA: 134555820Syokota state |= SHIFTAON; 134654382Syokota action = LCTR; 134754382Syokota /* FALL THROUGH */ 134842421Syokota case LCTR: 134942421Syokota state |= CTLS1; 135042421Syokota break; 135154382Syokota case RCTRA: 135255820Syokota state |= SHIFTAON; 135354382Syokota action = RCTR; 135454382Syokota /* FALL THROUGH */ 135542421Syokota case RCTR: 135642421Syokota state |= CTLS2; 135742421Syokota break; 135854382Syokota case LALTA: 135955820Syokota state |= SHIFTAON; 136054382Syokota action = LALT; 136154382Syokota /* FALL THROUGH */ 136242421Syokota case LALT: 136342421Syokota state |= ALTS1; 136442421Syokota break; 136554382Syokota case RALTA: 136655820Syokota state |= SHIFTAON; 136754382Syokota action = RALT; 136854382Syokota /* FALL THROUGH */ 136942421Syokota case RALT: 137042421Syokota state |= ALTS2; 137142421Syokota break; 137242421Syokota case ASH: 137342421Syokota state |= AGRS1; 137442421Syokota break; 137542421Syokota case META: 137642421Syokota state |= METAS1; 137742421Syokota break; 137880040Syokota case NOP: 137980040Syokota *shiftstate = state; 1380127752Sdes return (NOKEY); 138142421Syokota default: 138242421Syokota /* is this an accent (dead) key? */ 138355820Syokota *shiftstate = state; 138442421Syokota if (action >= F_ACC && action <= L_ACC) { 138542421Syokota action = save_accent_key(kbd, action, 138642421Syokota accents); 138742421Syokota switch (action) { 138842421Syokota case NOKEY: 138942421Syokota case ERRKEY: 1390127752Sdes return (action); 139142421Syokota default: 139242421Syokota if (state & METAS) 139342421Syokota return (action | MKEY); 139442421Syokota else 1395127752Sdes return (action); 139642421Syokota } 139742421Syokota /* NOT REACHED */ 139842421Syokota } 139942421Syokota /* other special keys */ 140042421Syokota if (*accents > 0) { 140142421Syokota *accents = 0; 1402127752Sdes return (ERRKEY); 140342421Syokota } 140442421Syokota if (action >= F_FN && action <= L_FN) 140542421Syokota action |= FKEY; 140642421Syokota /* XXX: return fkey string for the FKEY? */ 140755820Syokota return (SPCLKEY | action); 140842421Syokota } 140942421Syokota *shiftstate = state; 141042421Syokota return (SPCLKEY | action); 141142421Syokota } else { 141242421Syokota /* regular keys */ 141380040Syokota kbd->kb_lastact[keycode] = NOP; 141455820Syokota *shiftstate = state; 141542421Syokota if (*accents > 0) { 141642421Syokota /* make an accented char */ 141742421Syokota action = make_accent_char(kbd, action, accents); 141842421Syokota if (action == ERRKEY) 1419127752Sdes return (action); 142042421Syokota } 142142421Syokota if (state & METAS) 142242421Syokota action |= MKEY; 1423127752Sdes return (action); 142442421Syokota } 142542421Syokota } 142642421Syokota /* NOT REACHED */ 142742421Syokota} 1428