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$"); 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/poll.h> 40164033Srwatson#include <sys/priv.h> 41112050Sdwmalone#include <sys/proc.h> 42180777Sed#include <sys/selinfo.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 50183397Sed#define KBD_INDEX(dev) dev2unit(dev) 5150154Syokota 52193512Sed#define KB_QSIZE 512 53193512Sed#define KB_BUFSIZE 64 54193512Sed 5550154Syokotatypedef struct genkbd_softc { 5650154Syokota int gkb_flags; /* flag/status bits */ 5750154Syokota#define KB_ASLEEP (1 << 0) 5850154Syokota struct selinfo gkb_rsel; 59193512Sed char gkb_q[KB_QSIZE]; /* input queue */ 60193512Sed unsigned int gkb_q_start; 61193512Sed unsigned int gkb_q_length; 6250154Syokota} genkbd_softc_t; 6350154Syokota 6460938Sjakestatic SLIST_HEAD(, keyboard_driver) keyboard_drivers = 65127751Sdes SLIST_HEAD_INITIALIZER(keyboard_drivers); 6654545Syokota 6778161SpeterSET_DECLARE(kbddriver_set, const keyboard_driver_t); 6878161Speter 6942421Syokota/* local arrays */ 7042421Syokota 7142421Syokota/* 7242421Syokota * We need at least one entry each in order to initialize a keyboard 7342421Syokota * for the kernel console. The arrays will be increased dynamically 7442421Syokota * when necessary. 7542421Syokota */ 7642564Syokota 7742564Syokotastatic int keyboards = 1; 7842421Syokotastatic keyboard_t *kbd_ini; 7942564Syokotastatic keyboard_t **keyboard = &kbd_ini; 8042421Syokotastatic keyboard_switch_t *kbdsw_ini; 8142421Syokota keyboard_switch_t **kbdsw = &kbdsw_ini; 8242421Syokota 83112050Sdwmalonestatic int keymap_restrict_change; 84248085Smariusstatic SYSCTL_NODE(_hw, OID_AUTO, kbd, CTLFLAG_RD, 0, "kbd"); 85112050SdwmaloneSYSCTL_INT(_hw_kbd, OID_AUTO, keymap_restrict_change, CTLFLAG_RW, 86112050Sdwmalone &keymap_restrict_change, 0, "restrict ability to change keymap"); 87112050Sdwmalone 8842421Syokota#define ARRAY_DELTA 4 8942421Syokota 9044628Syokotastatic int 9142421Syokotakbd_realloc_array(void) 9242421Syokota{ 9342421Syokota keyboard_t **new_kbd; 9442421Syokota keyboard_switch_t **new_kbdsw; 9542421Syokota int newsize; 9642421Syokota int s; 9742421Syokota 9842421Syokota s = spltty(); 9942421Syokota newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA; 10069781Sdwmalone new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT|M_ZERO); 10144628Syokota if (new_kbd == NULL) { 10244628Syokota splx(s); 103127752Sdes return (ENOMEM); 10444628Syokota } 10569781Sdwmalone new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF, 10669781Sdwmalone M_NOWAIT|M_ZERO); 10744628Syokota if (new_kbdsw == NULL) { 10844628Syokota free(new_kbd, M_DEVBUF); 10944628Syokota splx(s); 110127752Sdes return (ENOMEM); 11144628Syokota } 11242421Syokota bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards); 11342421Syokota bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards); 11442421Syokota if (keyboards > 1) { 11542421Syokota free(keyboard, M_DEVBUF); 11642421Syokota free(kbdsw, M_DEVBUF); 11742421Syokota } 11842421Syokota keyboard = new_kbd; 11942421Syokota kbdsw = new_kbdsw; 12042421Syokota keyboards = newsize; 12142421Syokota splx(s); 12242421Syokota 12342421Syokota if (bootverbose) 12442421Syokota printf("kbd: new array size %d\n", keyboards); 12544628Syokota 126127752Sdes return (0); 12742421Syokota} 12842421Syokota 12942421Syokota/* 13042421Syokota * Low-level keyboard driver functions 13142421Syokota * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard 13242421Syokota * driver, call these functions to initialize the keyboard_t structure 13342421Syokota * and register it to the virtual keyboard driver `kbd'. 13442421Syokota */ 13542421Syokota 13642421Syokota/* initialize the keyboard_t structure */ 13742421Syokotavoid 13842421Syokotakbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config, 13942421Syokota int port, int port_size) 14042421Syokota{ 14142421Syokota kbd->kb_flags = KB_NO_DEVICE; /* device has not been found */ 14242421Syokota kbd->kb_name = name; 14342421Syokota kbd->kb_type = type; 14442421Syokota kbd->kb_unit = unit; 14544628Syokota kbd->kb_config = config & ~KB_CONF_PROBE_ONLY; 14642421Syokota kbd->kb_led = 0; /* unknown */ 14742421Syokota kbd->kb_io_base = port; 14842421Syokota kbd->kb_io_size = port_size; 14942421Syokota kbd->kb_data = NULL; 15042421Syokota kbd->kb_keymap = NULL; 15142421Syokota kbd->kb_accentmap = NULL; 15242421Syokota kbd->kb_fkeytab = NULL; 15342421Syokota kbd->kb_fkeytab_size = 0; 15444628Syokota kbd->kb_delay1 = KB_DELAY1; /* these values are advisory only */ 15544628Syokota kbd->kb_delay2 = KB_DELAY2; 15654382Syokota kbd->kb_count = 0L; 15780040Syokota bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact)); 15842421Syokota} 15942421Syokota 16042421Syokotavoid 16142421Syokotakbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap, 16242421Syokota fkeytab_t *fkeymap, int fkeymap_size) 16342421Syokota{ 16442421Syokota kbd->kb_keymap = keymap; 16542421Syokota kbd->kb_accentmap = accmap; 16642421Syokota kbd->kb_fkeytab = fkeymap; 16742421Syokota kbd->kb_fkeytab_size = fkeymap_size; 16842421Syokota} 16942421Syokota 17054545Syokota/* declare a new keyboard driver */ 17154545Syokotaint 17254545Syokotakbd_add_driver(keyboard_driver_t *driver) 17354545Syokota{ 17454545Syokota if (SLIST_NEXT(driver, link)) 175127752Sdes return (EINVAL); 17654545Syokota SLIST_INSERT_HEAD(&keyboard_drivers, driver, link); 177127752Sdes return (0); 17854545Syokota} 17954545Syokota 18054545Syokotaint 18154545Syokotakbd_delete_driver(keyboard_driver_t *driver) 18254545Syokota{ 18360938Sjake SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link); 18454545Syokota SLIST_NEXT(driver, link) = NULL; 185127752Sdes return (0); 18654545Syokota} 18754545Syokota 18842421Syokota/* register a keyboard and associate it with a function table */ 18942421Syokotaint 19042421Syokotakbd_register(keyboard_t *kbd) 19142421Syokota{ 19247295Syokota const keyboard_driver_t **list; 19347295Syokota const keyboard_driver_t *p; 194156126Semax keyboard_t *mux; 195156126Semax keyboard_info_t ki; 19642421Syokota int index; 19742421Syokota 198156126Semax mux = kbd_get_keyboard(kbd_find_keyboard("kbdmux", -1)); 199156126Semax 20042421Syokota for (index = 0; index < keyboards; ++index) { 20142421Syokota if (keyboard[index] == NULL) 20242421Syokota break; 20342421Syokota } 20444628Syokota if (index >= keyboards) { 20544628Syokota if (kbd_realloc_array()) 206127752Sdes return (-1); 20744628Syokota } 20842421Syokota 20942421Syokota kbd->kb_index = index; 21042421Syokota KBD_UNBUSY(kbd); 21142421Syokota KBD_VALID(kbd); 21242421Syokota kbd->kb_active = 0; /* disabled until someone calls kbd_enable() */ 21342421Syokota kbd->kb_token = NULL; 21442421Syokota kbd->kb_callback.kc_func = NULL; 21542421Syokota kbd->kb_callback.kc_arg = NULL; 21642421Syokota 21754545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 21854545Syokota if (strcmp(p->name, kbd->kb_name) == 0) { 21954545Syokota keyboard[index] = kbd; 22054545Syokota kbdsw[index] = p->kbdsw; 221156126Semax 222156126Semax if (mux != NULL) { 223156126Semax bzero(&ki, sizeof(ki)); 224156126Semax strcpy(ki.kb_name, kbd->kb_name); 225156126Semax ki.kb_unit = kbd->kb_unit; 226156126Semax 227213770Srpaulo (void)kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki); 228156126Semax } 229156126Semax 230127752Sdes return (index); 23154545Syokota } 23254545Syokota } 23378161Speter SET_FOREACH(list, kbddriver_set) { 23478161Speter p = *list; 23542421Syokota if (strcmp(p->name, kbd->kb_name) == 0) { 23642421Syokota keyboard[index] = kbd; 23742421Syokota kbdsw[index] = p->kbdsw; 238156126Semax 239156126Semax if (mux != NULL) { 240156126Semax bzero(&ki, sizeof(ki)); 241156126Semax strcpy(ki.kb_name, kbd->kb_name); 242156126Semax ki.kb_unit = kbd->kb_unit; 243156126Semax 244213770Srpaulo (void)kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki); 245156126Semax } 246156126Semax 247127752Sdes return (index); 24842421Syokota } 24942421Syokota } 25042421Syokota 251127752Sdes return (-1); 25242421Syokota} 25342421Syokota 25442421Syokotaint 25542421Syokotakbd_unregister(keyboard_t *kbd) 25642421Syokota{ 25742421Syokota int error; 25842421Syokota int s; 25942421Syokota 26042421Syokota if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards)) 261127752Sdes return (ENOENT); 26242421Syokota if (keyboard[kbd->kb_index] != kbd) 263127752Sdes return (ENOENT); 26442421Syokota 26542421Syokota s = spltty(); 26642421Syokota if (KBD_IS_BUSY(kbd)) { 26742421Syokota error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING, 268127752Sdes kbd->kb_callback.kc_arg); 26942421Syokota if (error) { 27042421Syokota splx(s); 271127752Sdes return (error); 27242421Syokota } 27342421Syokota if (KBD_IS_BUSY(kbd)) { 27442421Syokota splx(s); 275127752Sdes return (EBUSY); 27642421Syokota } 27742421Syokota } 27842421Syokota KBD_INVALID(kbd); 27942421Syokota keyboard[kbd->kb_index] = NULL; 28042421Syokota kbdsw[kbd->kb_index] = NULL; 28142421Syokota 28242421Syokota splx(s); 283127752Sdes return (0); 28442421Syokota} 28542421Syokota 28642421Syokota/* find a funciton table by the driver name */ 28742421Syokotakeyboard_switch_t 28842421Syokota*kbd_get_switch(char *driver) 28942421Syokota{ 29047295Syokota const keyboard_driver_t **list; 29147295Syokota const keyboard_driver_t *p; 29242421Syokota 29354545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 29454545Syokota if (strcmp(p->name, driver) == 0) 295127752Sdes return (p->kbdsw); 29654545Syokota } 29778161Speter SET_FOREACH(list, kbddriver_set) { 29878161Speter p = *list; 29942421Syokota if (strcmp(p->name, driver) == 0) 300127752Sdes return (p->kbdsw); 30142421Syokota } 30242421Syokota 303127752Sdes return (NULL); 30442421Syokota} 30542421Syokota 30642421Syokota/* 30742421Syokota * Keyboard client functions 30842421Syokota * Keyboard clients, such as the console driver `syscons' and the keyboard 30942421Syokota * cdev driver, use these functions to claim and release a keyboard for 31042421Syokota * exclusive use. 31142421Syokota */ 31242421Syokota 313147980Semax/* 314147980Semax * find the keyboard specified by a driver name and a unit number 315147980Semax * starting at given index 316147980Semax */ 31742421Syokotaint 318147980Semaxkbd_find_keyboard2(char *driver, int unit, int index) 31942421Syokota{ 32042421Syokota int i; 32142421Syokota 322147980Semax if ((index < 0) || (index >= keyboards)) 323147980Semax return (-1); 324147980Semax 325147980Semax for (i = index; i < keyboards; ++i) { 32642421Syokota if (keyboard[i] == NULL) 32742421Syokota continue; 32842421Syokota if (!KBD_IS_VALID(keyboard[i])) 32942421Syokota continue; 33042421Syokota if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver)) 33142421Syokota continue; 33242421Syokota if ((unit != -1) && (keyboard[i]->kb_unit != unit)) 33342421Syokota continue; 334127752Sdes return (i); 33542421Syokota } 336147980Semax 337127752Sdes return (-1); 33842421Syokota} 33942421Syokota 340147980Semax/* find the keyboard specified by a driver name and a unit number */ 341147980Semaxint 342147980Semaxkbd_find_keyboard(char *driver, int unit) 343147980Semax{ 344147980Semax return (kbd_find_keyboard2(driver, unit, 0)); 345147980Semax} 346147980Semax 34742421Syokota/* allocate a keyboard */ 34842421Syokotaint 34942421Syokotakbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func, 35042421Syokota void *arg) 35142421Syokota{ 35242421Syokota int index; 35342421Syokota int s; 35442421Syokota 35542421Syokota if (func == NULL) 356127752Sdes return (-1); 35742421Syokota 35842421Syokota s = spltty(); 35942421Syokota index = kbd_find_keyboard(driver, unit); 36042421Syokota if (index >= 0) { 36142421Syokota if (KBD_IS_BUSY(keyboard[index])) { 36242421Syokota splx(s); 363127752Sdes return (-1); 36442421Syokota } 36542421Syokota keyboard[index]->kb_token = id; 36642421Syokota KBD_BUSY(keyboard[index]); 36742421Syokota keyboard[index]->kb_callback.kc_func = func; 36842421Syokota keyboard[index]->kb_callback.kc_arg = arg; 369174984Swkoszek kbdd_clear_state(keyboard[index]); 37042421Syokota } 37142421Syokota splx(s); 372127752Sdes return (index); 37342421Syokota} 37442421Syokota 37542421Syokotaint 37642421Syokotakbd_release(keyboard_t *kbd, void *id) 37742421Syokota{ 37842421Syokota int error; 37942421Syokota int s; 38042421Syokota 38142421Syokota s = spltty(); 38242421Syokota if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 38342421Syokota error = EINVAL; 38442421Syokota } else if (kbd->kb_token != id) { 38542421Syokota error = EPERM; 38642421Syokota } else { 38742421Syokota kbd->kb_token = NULL; 38842421Syokota KBD_UNBUSY(kbd); 38942421Syokota kbd->kb_callback.kc_func = NULL; 39042421Syokota kbd->kb_callback.kc_arg = NULL; 391174984Swkoszek kbdd_clear_state(kbd); 39242421Syokota error = 0; 39342421Syokota } 39442421Syokota splx(s); 395127752Sdes return (error); 39642421Syokota} 39742421Syokota 39842421Syokotaint 39942421Syokotakbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func, 40042421Syokota void *arg) 40142421Syokota{ 40242421Syokota int error; 40342421Syokota int s; 40442421Syokota 40542421Syokota s = spltty(); 40642421Syokota if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 40742421Syokota error = EINVAL; 40842421Syokota } else if (kbd->kb_token != id) { 40942421Syokota error = EPERM; 41042421Syokota } else if (func == NULL) { 41142421Syokota error = EINVAL; 41242421Syokota } else { 41342421Syokota kbd->kb_callback.kc_func = func; 41442421Syokota kbd->kb_callback.kc_arg = arg; 41542421Syokota error = 0; 41642421Syokota } 41742421Syokota splx(s); 418127752Sdes return (error); 41942421Syokota} 42042421Syokota 42142421Syokota/* get a keyboard structure */ 42242421Syokotakeyboard_t 42342421Syokota*kbd_get_keyboard(int index) 42442421Syokota{ 42542421Syokota if ((index < 0) || (index >= keyboards)) 426127752Sdes return (NULL); 42750154Syokota if (keyboard[index] == NULL) 428127752Sdes return (NULL); 42942421Syokota if (!KBD_IS_VALID(keyboard[index])) 430127752Sdes return (NULL); 431127752Sdes return (keyboard[index]); 43242421Syokota} 43342421Syokota 43442421Syokota/* 43542421Syokota * The back door for the console driver; configure keyboards 43642421Syokota * This function is for the kernel console to initialize keyboards 43742421Syokota * at very early stage. 43842421Syokota */ 43942421Syokota 44042421Syokotaint 44142421Syokotakbd_configure(int flags) 44242421Syokota{ 44347295Syokota const keyboard_driver_t **list; 44447295Syokota const keyboard_driver_t *p; 44542421Syokota 44654545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 44754545Syokota if (p->configure != NULL) 44854545Syokota (*p->configure)(flags); 44954545Syokota } 45078161Speter SET_FOREACH(list, kbddriver_set) { 45178161Speter p = *list; 45242421Syokota if (p->configure != NULL) 45342421Syokota (*p->configure)(flags); 45442421Syokota } 45542421Syokota 456127752Sdes return (0); 45742421Syokota} 45842421Syokota 45942421Syokota#ifdef KBD_INSTALL_CDEV 46042421Syokota 46142421Syokota/* 46242421Syokota * Virtual keyboard cdev driver functions 46342421Syokota * The virtual keyboard driver dispatches driver functions to 46442421Syokota * appropriate subdrivers. 46542421Syokota */ 46642421Syokota 467183397Sed#define KBD_UNIT(dev) dev2unit(dev) 46842421Syokota 46950154Syokotastatic d_open_t genkbdopen; 47050154Syokotastatic d_close_t genkbdclose; 47150154Syokotastatic d_read_t genkbdread; 47250154Syokotastatic d_write_t genkbdwrite; 47350154Syokotastatic d_ioctl_t genkbdioctl; 47450154Syokotastatic d_poll_t genkbdpoll; 47542421Syokota 47642421Syokota 47742421Syokotastatic struct cdevsw kbd_cdevsw = { 478126080Sphk .d_version = D_VERSION, 479126080Sphk .d_flags = D_NEEDGIANT, 480111815Sphk .d_open = genkbdopen, 481111815Sphk .d_close = genkbdclose, 482111815Sphk .d_read = genkbdread, 483111815Sphk .d_write = genkbdwrite, 484111815Sphk .d_ioctl = genkbdioctl, 485111815Sphk .d_poll = genkbdpoll, 486111815Sphk .d_name = "kbd", 48742421Syokota}; 48842421Syokota 48942421Syokotaint 49050154Syokotakbd_attach(keyboard_t *kbd) 49142421Syokota{ 49242421Syokota 49342421Syokota if (kbd->kb_index >= keyboards) 494127752Sdes return (EINVAL); 49542421Syokota if (keyboard[kbd->kb_index] != kbd) 496127752Sdes return (EINVAL); 49742421Syokota 498127751Sdes kbd->kb_dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 499127751Sdes 0600, "%s%r", kbd->kb_name, kbd->kb_unit); 500125087Sdes make_dev_alias(kbd->kb_dev, "kbd%r", kbd->kb_index); 501120502Sphk kbd->kb_dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF, 502127751Sdes M_WAITOK | M_ZERO); 50342421Syokota printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit); 504127752Sdes return (0); 50542421Syokota} 50642421Syokota 50742421Syokotaint 50850154Syokotakbd_detach(keyboard_t *kbd) 50942421Syokota{ 51054545Syokota 51142421Syokota if (kbd->kb_index >= keyboards) 512127752Sdes return (EINVAL); 51342421Syokota if (keyboard[kbd->kb_index] != kbd) 514127752Sdes return (EINVAL); 51542421Syokota 516120502Sphk free(kbd->kb_dev->si_drv1, M_DEVBUF); 517120502Sphk destroy_dev(kbd->kb_dev); 51854545Syokota 519127752Sdes return (0); 52042421Syokota} 52142421Syokota 52242421Syokota/* 52342421Syokota * Generic keyboard cdev driver functions 52442421Syokota * Keyboard subdrivers may call these functions to implement common 52542421Syokota * driver functions. 52642421Syokota */ 52742421Syokota 528193512Sedstatic void 529193512Sedgenkbd_putc(genkbd_softc_t *sc, char c) 530193512Sed{ 531193512Sed unsigned int p; 53242421Syokota 533193512Sed if (sc->gkb_q_length == KB_QSIZE) 534193512Sed return; 535193512Sed 536193512Sed p = (sc->gkb_q_start + sc->gkb_q_length) % KB_QSIZE; 537193512Sed sc->gkb_q[p] = c; 538193512Sed sc->gkb_q_length++; 539193512Sed} 540193512Sed 541193512Sedstatic size_t 542193512Sedgenkbd_getc(genkbd_softc_t *sc, char *buf, size_t len) 543193512Sed{ 544193512Sed 545193512Sed /* Determine copy size. */ 546193512Sed if (sc->gkb_q_length == 0) 547193512Sed return (0); 548193512Sed if (len >= sc->gkb_q_length) 549193512Sed len = sc->gkb_q_length; 550193512Sed if (len >= KB_QSIZE - sc->gkb_q_start) 551193512Sed len = KB_QSIZE - sc->gkb_q_start; 552193512Sed 553193512Sed /* Copy out data and progress offset. */ 554193512Sed memcpy(buf, sc->gkb_q + sc->gkb_q_start, len); 555193512Sed sc->gkb_q_start = (sc->gkb_q_start + len) % KB_QSIZE; 556193512Sed sc->gkb_q_length -= len; 557193512Sed 558193512Sed return (len); 559193512Sed} 560193512Sed 56142421Syokotastatic kbd_callback_func_t genkbd_event; 56242421Syokota 56350154Syokotastatic int 564130585Sphkgenkbdopen(struct cdev *dev, int mode, int flag, struct thread *td) 56542421Syokota{ 56650154Syokota keyboard_t *kbd; 56750154Syokota genkbd_softc_t *sc; 56842421Syokota int s; 56942421Syokota int i; 57042421Syokota 57142421Syokota s = spltty(); 57250154Syokota sc = dev->si_drv1; 57350154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 57450154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 57542421Syokota splx(s); 576127752Sdes return (ENXIO); 57742421Syokota } 57842421Syokota i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc, 579127751Sdes genkbd_event, (void *)sc); 58042421Syokota if (i < 0) { 58142421Syokota splx(s); 582127752Sdes return (EBUSY); 58342421Syokota } 58442421Syokota /* assert(i == kbd->kb_index) */ 58542421Syokota /* assert(kbd == kbd_get_keyboard(i)) */ 58642421Syokota 58742421Syokota /* 58842421Syokota * NOTE: even when we have successfully claimed a keyboard, 58942421Syokota * the device may still be missing (!KBD_HAS_DEVICE(kbd)). 59042421Syokota */ 59142421Syokota 592193512Sed sc->gkb_q_length = 0; 59342421Syokota splx(s); 59442421Syokota 595127752Sdes return (0); 59642421Syokota} 59742421Syokota 59850154Syokotastatic int 599130585Sphkgenkbdclose(struct cdev *dev, int mode, int flag, struct thread *td) 60042421Syokota{ 60150154Syokota keyboard_t *kbd; 60250154Syokota genkbd_softc_t *sc; 60342421Syokota int s; 60442421Syokota 60542421Syokota /* 60642421Syokota * NOTE: the device may have already become invalid. 60750154Syokota * kbd == NULL || !KBD_IS_VALID(kbd) 60842421Syokota */ 60942421Syokota s = spltty(); 61050154Syokota sc = dev->si_drv1; 61150154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 61250154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 61350154Syokota /* XXX: we shall be forgiving and don't report error... */ 61450154Syokota } else { 61550154Syokota kbd_release(kbd, (void *)sc); 61650154Syokota } 61742421Syokota splx(s); 618127752Sdes return (0); 61942421Syokota} 62042421Syokota 62150154Syokotastatic int 622130585Sphkgenkbdread(struct cdev *dev, struct uio *uio, int flag) 62342421Syokota{ 62450154Syokota keyboard_t *kbd; 62550154Syokota genkbd_softc_t *sc; 62642421Syokota u_char buffer[KB_BUFSIZE]; 62742421Syokota int len; 62842421Syokota int error; 62942421Syokota int s; 63042421Syokota 63142421Syokota /* wait for input */ 63242421Syokota s = spltty(); 63350154Syokota sc = dev->si_drv1; 63450154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 63550154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 63650154Syokota splx(s); 637127752Sdes return (ENXIO); 63850154Syokota } 639193512Sed while (sc->gkb_q_length == 0) { 640139193Sphk if (flag & O_NONBLOCK) { 64142421Syokota splx(s); 642127752Sdes return (EWOULDBLOCK); 64342421Syokota } 64442421Syokota sc->gkb_flags |= KB_ASLEEP; 645111748Sdes error = tsleep(sc, PZERO | PCATCH, "kbdrea", 0); 64650154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 64750154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) { 64850154Syokota splx(s); 649127752Sdes return (ENXIO); /* our keyboard has gone... */ 65050154Syokota } 65142421Syokota if (error) { 65242421Syokota sc->gkb_flags &= ~KB_ASLEEP; 65342421Syokota splx(s); 654127752Sdes return (error); 65542421Syokota } 65642421Syokota } 65742421Syokota splx(s); 65842421Syokota 65942421Syokota /* copy as much input as possible */ 66042421Syokota error = 0; 66142421Syokota while (uio->uio_resid > 0) { 66242421Syokota len = imin(uio->uio_resid, sizeof(buffer)); 663193512Sed len = genkbd_getc(sc, buffer, len); 66442421Syokota if (len <= 0) 66542421Syokota break; 66642421Syokota error = uiomove(buffer, len, uio); 66742421Syokota if (error) 66842421Syokota break; 66942421Syokota } 67042421Syokota 671127752Sdes return (error); 67242421Syokota} 67342421Syokota 67450154Syokotastatic int 675130585Sphkgenkbdwrite(struct cdev *dev, struct uio *uio, int flag) 67642421Syokota{ 67750154Syokota keyboard_t *kbd; 67850154Syokota 67950154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 68050154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) 681127752Sdes return (ENXIO); 682127752Sdes return (ENODEV); 68342421Syokota} 68442421Syokota 68550154Syokotastatic int 686130585Sphkgenkbdioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 68742421Syokota{ 68850154Syokota keyboard_t *kbd; 68942421Syokota int error; 69042421Syokota 69150154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 69250154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) 693127752Sdes return (ENXIO); 694174984Swkoszek error = kbdd_ioctl(kbd, cmd, arg); 69542421Syokota if (error == ENOIOCTL) 69642421Syokota error = ENODEV; 697127752Sdes return (error); 69842421Syokota} 69942421Syokota 70050154Syokotastatic int 701130585Sphkgenkbdpoll(struct cdev *dev, int events, struct thread *td) 70242421Syokota{ 70350154Syokota keyboard_t *kbd; 70450154Syokota genkbd_softc_t *sc; 70542421Syokota int revents; 70642421Syokota int s; 70742421Syokota 70842421Syokota revents = 0; 70942421Syokota s = spltty(); 71050154Syokota sc = dev->si_drv1; 71150154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 71250154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 71350154Syokota revents = POLLHUP; /* the keyboard has gone */ 71450154Syokota } else if (events & (POLLIN | POLLRDNORM)) { 715193512Sed if (sc->gkb_q_length > 0) 71650154Syokota revents = events & (POLLIN | POLLRDNORM); 71742421Syokota else 71883366Sjulian selrecord(td, &sc->gkb_rsel); 71942421Syokota } 72042421Syokota splx(s); 721127752Sdes return (revents); 72242421Syokota} 72342421Syokota 72442421Syokotastatic int 72542421Syokotagenkbd_event(keyboard_t *kbd, int event, void *arg) 72642421Syokota{ 72742421Syokota genkbd_softc_t *sc; 72842421Syokota size_t len; 72942421Syokota u_char *cp; 73042421Syokota int mode; 731197400Sed u_int c; 73242421Syokota 73342421Syokota /* assert(KBD_IS_VALID(kbd)) */ 73442421Syokota sc = (genkbd_softc_t *)arg; 73542421Syokota 73642421Syokota switch (event) { 73742421Syokota case KBDIO_KEYINPUT: 73842421Syokota break; 73942421Syokota case KBDIO_UNLOADING: 74042421Syokota /* the keyboard is going... */ 74142421Syokota kbd_release(kbd, (void *)sc); 74250154Syokota if (sc->gkb_flags & KB_ASLEEP) { 74350154Syokota sc->gkb_flags &= ~KB_ASLEEP; 744111748Sdes wakeup(sc); 74550154Syokota } 746122352Stanimura selwakeuppri(&sc->gkb_rsel, PZERO); 747127752Sdes return (0); 74842421Syokota default: 749127752Sdes return (EINVAL); 75042421Syokota } 75142421Syokota 75242421Syokota /* obtain the current key input mode */ 753174984Swkoszek if (kbdd_ioctl(kbd, KDGKBMODE, (caddr_t)&mode)) 75442421Syokota mode = K_XLATE; 75542421Syokota 75642421Syokota /* read all pending input */ 757174984Swkoszek while (kbdd_check_char(kbd)) { 758174984Swkoszek c = kbdd_read_char(kbd, FALSE); 75942421Syokota if (c == NOKEY) 76042421Syokota continue; 76142421Syokota if (c == ERRKEY) /* XXX: ring bell? */ 76242421Syokota continue; 76342421Syokota if (!KBD_IS_BUSY(kbd)) 76442421Syokota /* the device is not open, discard the input */ 76542421Syokota continue; 76642421Syokota 76742421Syokota /* store the byte as is for K_RAW and K_CODE modes */ 76842421Syokota if (mode != K_XLATE) { 769193512Sed genkbd_putc(sc, KEYCHAR(c)); 77042421Syokota continue; 77142421Syokota } 77242421Syokota 77342421Syokota /* K_XLATE */ 77442421Syokota if (c & RELKEY) /* key release is ignored */ 77542421Syokota continue; 77642421Syokota 77742421Syokota /* process special keys; most of them are just ignored... */ 77842421Syokota if (c & SPCLKEY) { 77942421Syokota switch (KEYCHAR(c)) { 78054382Syokota default: 78142421Syokota /* ignore them... */ 78242421Syokota continue; 78342421Syokota case BTAB: /* a backtab: ESC [ Z */ 784193512Sed genkbd_putc(sc, 0x1b); 785193512Sed genkbd_putc(sc, '['); 786193512Sed genkbd_putc(sc, 'Z'); 78742421Syokota continue; 78842421Syokota } 78942421Syokota } 79042421Syokota 79142421Syokota /* normal chars, normal chars with the META, function keys */ 79242421Syokota switch (KEYFLAGS(c)) { 79342421Syokota case 0: /* a normal char */ 794193512Sed genkbd_putc(sc, KEYCHAR(c)); 79542421Syokota break; 79642421Syokota case MKEY: /* the META flag: prepend ESC */ 797193512Sed genkbd_putc(sc, 0x1b); 798193512Sed genkbd_putc(sc, KEYCHAR(c)); 79942421Syokota break; 80042421Syokota case FKEY | SPCLKEY: /* a function key, return string */ 801174984Swkoszek cp = kbdd_get_fkeystr(kbd, KEYCHAR(c), &len); 80242421Syokota if (cp != NULL) { 80342421Syokota while (len-- > 0) 804193512Sed genkbd_putc(sc, *cp++); 80542421Syokota } 80642421Syokota break; 80742421Syokota } 80842421Syokota } 80942421Syokota 81042421Syokota /* wake up sleeping/polling processes */ 811193512Sed if (sc->gkb_q_length > 0) { 81242421Syokota if (sc->gkb_flags & KB_ASLEEP) { 81342421Syokota sc->gkb_flags &= ~KB_ASLEEP; 814111748Sdes wakeup(sc); 81542421Syokota } 816122352Stanimura selwakeuppri(&sc->gkb_rsel, PZERO); 81742421Syokota } 81842421Syokota 819127752Sdes return (0); 82042421Syokota} 82142421Syokota 82242421Syokota#endif /* KBD_INSTALL_CDEV */ 82342421Syokota 82442421Syokota/* 82542421Syokota * Generic low-level keyboard functions 82642421Syokota * The low-level functions in the keyboard subdriver may use these 82742421Syokota * functions. 82842421Syokota */ 82942421Syokota 830112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 831112050Sdwmalonestatic int key_change_ok(struct keyent_t *, struct keyent_t *, struct thread *); 832112050Sdwmalonestatic int keymap_change_ok(keymap_t *, keymap_t *, struct thread *); 833112050Sdwmalonestatic int accent_change_ok(accentmap_t *, accentmap_t *, struct thread *); 834112050Sdwmalonestatic int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct thread *); 835112050Sdwmalone#endif 836112050Sdwmalone 83742421Syokotaint 83842421Syokotagenkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 83942421Syokota{ 840197330Sed keymap_t *mapp; 841224126Sed okeymap_t *omapp; 84242421Syokota keyarg_t *keyp; 84342421Syokota fkeyarg_t *fkeyp; 84442421Syokota int s; 845224126Sed int i, j; 846112050Sdwmalone int error; 84742421Syokota 84842421Syokota s = spltty(); 84942421Syokota switch (cmd) { 85042421Syokota 85142421Syokota case KDGKBINFO: /* get keyboard information */ 85242421Syokota ((keyboard_info_t *)arg)->kb_index = kbd->kb_index; 85342421Syokota i = imin(strlen(kbd->kb_name) + 1, 854127751Sdes sizeof(((keyboard_info_t *)arg)->kb_name)); 85542421Syokota bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i); 85642421Syokota ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit; 85742421Syokota ((keyboard_info_t *)arg)->kb_type = kbd->kb_type; 85842421Syokota ((keyboard_info_t *)arg)->kb_config = kbd->kb_config; 85942421Syokota ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags; 86042421Syokota break; 86142421Syokota 86242421Syokota case KDGKBTYPE: /* get keyboard type */ 86342421Syokota *(int *)arg = kbd->kb_type; 86442421Syokota break; 86542421Syokota 86654543Syokota case KDGETREPEAT: /* get keyboard repeat rate */ 86754543Syokota ((int *)arg)[0] = kbd->kb_delay1; 868127751Sdes ((int *)arg)[1] = kbd->kb_delay2; 86954543Syokota break; 87054543Syokota 87142421Syokota case GIO_KEYMAP: /* get keyboard translation table */ 872197330Sed error = copyout(kbd->kb_keymap, *(void **)arg, 873197330Sed sizeof(keymap_t)); 874197330Sed splx(s); 875197330Sed return (error); 876224126Sed case OGIO_KEYMAP: /* get keyboard translation table (compat) */ 877224126Sed mapp = kbd->kb_keymap; 878224126Sed omapp = (okeymap_t *)arg; 879224126Sed omapp->n_keys = mapp->n_keys; 880224126Sed for (i = 0; i < NUM_KEYS; i++) { 881224126Sed for (j = 0; j < NUM_STATES; j++) 882224126Sed omapp->key[i].map[j] = 883224126Sed mapp->key[i].map[j]; 884224126Sed omapp->key[i].spcl = mapp->key[i].spcl; 885224126Sed omapp->key[i].flgs = mapp->key[i].flgs; 886224126Sed } 887224126Sed return (0); 88842421Syokota case PIO_KEYMAP: /* set keyboard translation table */ 889224126Sed case OPIO_KEYMAP: /* set keyboard translation table (compat) */ 89044628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 891197330Sed mapp = malloc(sizeof *mapp, M_TEMP, M_NOWAIT); 892224126Sed if (cmd == OPIO_KEYMAP) { 893224126Sed omapp = (okeymap_t *)arg; 894224126Sed mapp->n_keys = omapp->n_keys; 895224126Sed for (i = 0; i < NUM_KEYS; i++) { 896224126Sed for (j = 0; j < NUM_STATES; j++) 897224126Sed mapp->key[i].map[j] = 898224126Sed omapp->key[i].map[j]; 899224126Sed mapp->key[i].spcl = omapp->key[i].spcl; 900224126Sed mapp->key[i].flgs = omapp->key[i].flgs; 901224126Sed } 902224126Sed } else { 903224126Sed error = copyin(*(void **)arg, mapp, sizeof *mapp); 904224126Sed if (error != 0) { 905224126Sed splx(s); 906224126Sed free(mapp, M_TEMP); 907224126Sed return (error); 908224126Sed } 909112050Sdwmalone } 910197330Sed 911197330Sed error = keymap_change_ok(kbd->kb_keymap, mapp, curthread); 912197330Sed if (error != 0) { 913197330Sed splx(s); 914197330Sed free(mapp, M_TEMP); 915197330Sed return (error); 916197330Sed } 91742421Syokota bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 918197330Sed bcopy(mapp, kbd->kb_keymap, sizeof(*kbd->kb_keymap)); 919197330Sed free(mapp, M_TEMP); 92042421Syokota break; 92144628Syokota#else 92244628Syokota splx(s); 923127752Sdes return (ENODEV); 92444628Syokota#endif 92542421Syokota 92642421Syokota case GIO_KEYMAPENT: /* get keyboard translation table entry */ 92742421Syokota keyp = (keyarg_t *)arg; 928127751Sdes if (keyp->keynum >= sizeof(kbd->kb_keymap->key) / 929127751Sdes sizeof(kbd->kb_keymap->key[0])) { 93042421Syokota splx(s); 931127752Sdes return (EINVAL); 93242421Syokota } 93342573Syokota bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key, 934127751Sdes sizeof(keyp->key)); 93542421Syokota break; 93642421Syokota case PIO_KEYMAPENT: /* set keyboard translation table entry */ 93744628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 93842421Syokota keyp = (keyarg_t *)arg; 939127751Sdes if (keyp->keynum >= sizeof(kbd->kb_keymap->key) / 940127751Sdes sizeof(kbd->kb_keymap->key[0])) { 94142421Syokota splx(s); 942127752Sdes return (EINVAL); 94342421Syokota } 944112050Sdwmalone error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum], 945112050Sdwmalone &keyp->key, curthread); 946112050Sdwmalone if (error != 0) { 947112050Sdwmalone splx(s); 948127752Sdes return (error); 949112050Sdwmalone } 95042573Syokota bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum], 951127751Sdes sizeof(keyp->key)); 95242421Syokota break; 95344628Syokota#else 95444628Syokota splx(s); 955127752Sdes return (ENODEV); 95644628Syokota#endif 95742421Syokota 95842421Syokota case GIO_DEADKEYMAP: /* get accent key translation table */ 95942421Syokota bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap)); 96042421Syokota break; 96142421Syokota case PIO_DEADKEYMAP: /* set accent key translation table */ 96244628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 963112050Sdwmalone error = accent_change_ok(kbd->kb_accentmap, 964112050Sdwmalone (accentmap_t *)arg, curthread); 965112050Sdwmalone if (error != 0) { 966112050Sdwmalone splx(s); 967127752Sdes return (error); 968112050Sdwmalone } 96942421Syokota bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 97042421Syokota break; 97144628Syokota#else 97244628Syokota splx(s); 973127752Sdes return (ENODEV); 97444628Syokota#endif 97542421Syokota 97642421Syokota case GETFKEY: /* get functionkey string */ 97742421Syokota fkeyp = (fkeyarg_t *)arg; 97842421Syokota if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 97942421Syokota splx(s); 980127752Sdes return (EINVAL); 98142421Syokota } 98242421Syokota bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef, 983127751Sdes kbd->kb_fkeytab[fkeyp->keynum].len); 98442421Syokota fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len; 98542421Syokota break; 98642421Syokota case SETFKEY: /* set functionkey string */ 98744628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 98842421Syokota fkeyp = (fkeyarg_t *)arg; 98942421Syokota if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 99042421Syokota splx(s); 991127752Sdes return (EINVAL); 99242421Syokota } 993112050Sdwmalone error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum], 994112050Sdwmalone fkeyp, curthread); 995112050Sdwmalone if (error != 0) { 996112050Sdwmalone splx(s); 997127752Sdes return (error); 998112050Sdwmalone } 999300088Sglebius kbd->kb_fkeytab[fkeyp->keynum].len = min(fkeyp->flen, MAXFK); 100042421Syokota bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str, 1001127751Sdes kbd->kb_fkeytab[fkeyp->keynum].len); 100242421Syokota break; 100344628Syokota#else 100444628Syokota splx(s); 1005127752Sdes return (ENODEV); 100644628Syokota#endif 100742421Syokota 100842421Syokota default: 100942421Syokota splx(s); 1010127752Sdes return (ENOIOCTL); 101142421Syokota } 101242421Syokota 101342421Syokota splx(s); 1014127752Sdes return (0); 101542421Syokota} 101642421Syokota 1017112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 1018112050Sdwmalone#define RESTRICTED_KEY(key, i) \ 1019112050Sdwmalone ((key->spcl & (0x80 >> i)) && \ 1020112050Sdwmalone (key->map[i] == RBT || key->map[i] == SUSP || \ 1021112050Sdwmalone key->map[i] == STBY || key->map[i] == DBG || \ 1022112050Sdwmalone key->map[i] == PNC || key->map[i] == HALT || \ 1023112050Sdwmalone key->map[i] == PDWN)) 1024112050Sdwmalone 1025112050Sdwmalonestatic int 1026112050Sdwmalonekey_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct thread *td) 1027112050Sdwmalone{ 1028112050Sdwmalone int i; 1029112050Sdwmalone 1030112050Sdwmalone /* Low keymap_restrict_change means any changes are OK. */ 1031112050Sdwmalone if (keymap_restrict_change <= 0) 1032127752Sdes return (0); 1033112050Sdwmalone 1034112050Sdwmalone /* High keymap_restrict_change means only root can change the keymap. */ 1035112050Sdwmalone if (keymap_restrict_change >= 2) { 1036112050Sdwmalone for (i = 0; i < NUM_STATES; i++) 1037112050Sdwmalone if (oldkey->map[i] != newkey->map[i]) 1038164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1039112050Sdwmalone if (oldkey->spcl != newkey->spcl) 1040164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1041112050Sdwmalone if (oldkey->flgs != newkey->flgs) 1042164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1043127752Sdes return (0); 1044112050Sdwmalone } 1045112050Sdwmalone 1046112050Sdwmalone /* Otherwise we have to see if any special keys are being changed. */ 1047112050Sdwmalone for (i = 0; i < NUM_STATES; i++) { 1048112050Sdwmalone /* 1049112050Sdwmalone * If either the oldkey or the newkey action is restricted 1050112050Sdwmalone * then we must make sure that the action doesn't change. 1051112050Sdwmalone */ 1052112050Sdwmalone if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i)) 1053112050Sdwmalone continue; 1054112050Sdwmalone if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i)) 1055112050Sdwmalone && oldkey->map[i] == newkey->map[i]) 1056112050Sdwmalone continue; 1057164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1058112050Sdwmalone } 1059112050Sdwmalone 1060127752Sdes return (0); 1061112050Sdwmalone} 1062112050Sdwmalone 1063112050Sdwmalonestatic int 1064112050Sdwmalonekeymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct thread *td) 1065112050Sdwmalone{ 1066112050Sdwmalone int keycode, error; 1067112050Sdwmalone 1068112050Sdwmalone for (keycode = 0; keycode < NUM_KEYS; keycode++) { 1069112050Sdwmalone if ((error = key_change_ok(&oldmap->key[keycode], 1070112050Sdwmalone &newmap->key[keycode], td)) != 0) 1071127752Sdes return (error); 1072112050Sdwmalone } 1073127752Sdes return (0); 1074112050Sdwmalone} 1075112050Sdwmalone 1076112050Sdwmalonestatic int 1077112050Sdwmaloneaccent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct thread *td) 1078112050Sdwmalone{ 1079112050Sdwmalone struct acc_t *oldacc, *newacc; 1080112050Sdwmalone int accent, i; 1081112050Sdwmalone 1082112050Sdwmalone if (keymap_restrict_change <= 2) 1083127752Sdes return (0); 1084112050Sdwmalone 1085112050Sdwmalone if (oldmap->n_accs != newmap->n_accs) 1086164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1087112050Sdwmalone 1088112050Sdwmalone for (accent = 0; accent < oldmap->n_accs; accent++) { 1089112050Sdwmalone oldacc = &oldmap->acc[accent]; 1090112050Sdwmalone newacc = &newmap->acc[accent]; 1091112050Sdwmalone if (oldacc->accchar != newacc->accchar) 1092164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1093112050Sdwmalone for (i = 0; i < NUM_ACCENTCHARS; ++i) { 1094112050Sdwmalone if (oldacc->map[i][0] != newacc->map[i][0]) 1095164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1096112050Sdwmalone if (oldacc->map[i][0] == 0) /* end of table */ 1097112050Sdwmalone break; 1098112050Sdwmalone if (oldacc->map[i][1] != newacc->map[i][1]) 1099164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1100112050Sdwmalone } 1101112050Sdwmalone } 1102112050Sdwmalone 1103127752Sdes return (0); 1104112050Sdwmalone} 1105112050Sdwmalone 1106112050Sdwmalonestatic int 1107112050Sdwmalonefkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct thread *td) 1108112050Sdwmalone{ 1109112050Sdwmalone if (keymap_restrict_change <= 3) 1110127752Sdes return (0); 1111112050Sdwmalone 1112112050Sdwmalone if (oldkey->len != newkey->flen || 1113112050Sdwmalone bcmp(oldkey->str, newkey->keydef, oldkey->len) != 0) 1114164033Srwatson return priv_check(td, PRIV_KEYBOARD); 1115112050Sdwmalone 1116127752Sdes return (0); 1117112050Sdwmalone} 1118112050Sdwmalone#endif 1119112050Sdwmalone 112042421Syokota/* get a pointer to the string associated with the given function key */ 112142421Syokotau_char 112242421Syokota*genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len) 112342421Syokota{ 112442421Syokota if (kbd == NULL) 1125127752Sdes return (NULL); 112642421Syokota fkey -= F_FN; 112742421Syokota if (fkey > kbd->kb_fkeytab_size) 1128127752Sdes return (NULL); 112942421Syokota *len = kbd->kb_fkeytab[fkey].len; 1130127752Sdes return (kbd->kb_fkeytab[fkey].str); 113142421Syokota} 113242421Syokota 113342421Syokota/* diagnostic dump */ 113442421Syokotastatic char 113542421Syokota*get_kbd_type_name(int type) 113642421Syokota{ 113742421Syokota static struct { 113842421Syokota int type; 113942421Syokota char *name; 114042421Syokota } name_table[] = { 114142421Syokota { KB_84, "AT 84" }, 114242421Syokota { KB_101, "AT 101/102" }, 114342421Syokota { KB_OTHER, "generic" }, 114442421Syokota }; 114542421Syokota int i; 114642421Syokota 114742421Syokota for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) { 114842421Syokota if (type == name_table[i].type) 1149127752Sdes return (name_table[i].name); 115042421Syokota } 1151127752Sdes return ("unknown"); 115242421Syokota} 115342421Syokota 115442421Syokotavoid 115542421Syokotagenkbd_diag(keyboard_t *kbd, int level) 115642421Syokota{ 115742421Syokota if (level > 0) { 1158127751Sdes printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x", 1159127751Sdes kbd->kb_index, kbd->kb_name, kbd->kb_unit, 1160127751Sdes get_kbd_type_name(kbd->kb_type), kbd->kb_type, 1161127751Sdes kbd->kb_config, kbd->kb_flags); 116242421Syokota if (kbd->kb_io_base > 0) 1163127751Sdes printf(", port:0x%x-0x%x", kbd->kb_io_base, 1164127751Sdes kbd->kb_io_base + kbd->kb_io_size - 1); 116542421Syokota printf("\n"); 116642421Syokota } 116742421Syokota} 116842421Syokota 116942421Syokota#define set_lockkey_state(k, s, l) \ 117042421Syokota if (!((s) & l ## DOWN)) { \ 117142421Syokota int i; \ 117242421Syokota (s) |= l ## DOWN; \ 117342421Syokota (s) ^= l ## ED; \ 117442421Syokota i = (s) & LOCK_MASK; \ 1175213770Srpaulo (void)kbdd_ioctl((k), KDSETLED, (caddr_t)&i); \ 117642421Syokota } 117742421Syokota 117842421Syokotastatic u_int 117942421Syokotasave_accent_key(keyboard_t *kbd, u_int key, int *accents) 118042421Syokota{ 118142421Syokota int i; 118242421Syokota 118342421Syokota /* make an index into the accent map */ 118442421Syokota i = key - F_ACC + 1; 118542421Syokota if ((i > kbd->kb_accentmap->n_accs) 118642421Syokota || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) { 118742421Syokota /* the index is out of range or pointing to an empty entry */ 118842421Syokota *accents = 0; 1189127752Sdes return (ERRKEY); 119042421Syokota } 119142421Syokota 1192127751Sdes /* 1193127751Sdes * If the same accent key has been hit twice, produce the accent 1194127751Sdes * char itself. 119542421Syokota */ 119642421Syokota if (i == *accents) { 119742421Syokota key = kbd->kb_accentmap->acc[i - 1].accchar; 119842421Syokota *accents = 0; 1199127752Sdes return (key); 120042421Syokota } 120142421Syokota 120242421Syokota /* remember the index and wait for the next key */ 1203127751Sdes *accents = i; 1204127752Sdes return (NOKEY); 120542421Syokota} 120642421Syokota 120742421Syokotastatic u_int 120842421Syokotamake_accent_char(keyboard_t *kbd, u_int ch, int *accents) 120942421Syokota{ 121042421Syokota struct acc_t *acc; 121142421Syokota int i; 121242421Syokota 121342421Syokota acc = &kbd->kb_accentmap->acc[*accents - 1]; 121442421Syokota *accents = 0; 121542421Syokota 1216127751Sdes /* 121742421Syokota * If the accent key is followed by the space key, 121842421Syokota * produce the accent char itself. 121942421Syokota */ 122042421Syokota if (ch == ' ') 1221127752Sdes return (acc->accchar); 122242421Syokota 122342421Syokota /* scan the accent map */ 122442421Syokota for (i = 0; i < NUM_ACCENTCHARS; ++i) { 122542421Syokota if (acc->map[i][0] == 0) /* end of table */ 122642421Syokota break; 122742421Syokota if (acc->map[i][0] == ch) 1228127752Sdes return (acc->map[i][1]); 122942421Syokota } 123042421Syokota /* this char cannot be accented... */ 1231127752Sdes return (ERRKEY); 123242421Syokota} 123342421Syokota 123442421Syokotaint 123542421Syokotagenkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate, 123642421Syokota int *accents) 123742421Syokota{ 123842421Syokota struct keyent_t *key; 123942421Syokota int state = *shiftstate; 124042421Syokota int action; 124142421Syokota int f; 124242421Syokota int i; 124342421Syokota 124454382Syokota i = keycode; 124542421Syokota f = state & (AGRS | ALKED); 124642421Syokota if ((f == AGRS1) || (f == AGRS2) || (f == ALKED)) 124754382Syokota i += ALTGR_OFFSET; 124854382Syokota key = &kbd->kb_keymap->key[i]; 124942421Syokota i = ((state & SHIFTS) ? 1 : 0) 125042421Syokota | ((state & CTLS) ? 2 : 0) 125142421Syokota | ((state & ALTS) ? 4 : 0); 125242421Syokota if (((key->flgs & FLAG_LOCK_C) && (state & CLKED)) 125342421Syokota || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) ) 125442421Syokota i ^= 1; 125542421Syokota 125642421Syokota if (up) { /* break: key released */ 125780040Syokota action = kbd->kb_lastact[keycode]; 125880040Syokota kbd->kb_lastact[keycode] = NOP; 125980040Syokota switch (action) { 126080040Syokota case LSHA: 126180040Syokota if (state & SHIFTAON) { 126280040Syokota set_lockkey_state(kbd, state, ALK); 126380040Syokota state &= ~ALKDOWN; 126480040Syokota } 126580040Syokota action = LSH; 126680040Syokota /* FALL THROUGH */ 126780040Syokota case LSH: 126880040Syokota state &= ~SHIFTS1; 126980040Syokota break; 127080040Syokota case RSHA: 127180040Syokota if (state & SHIFTAON) { 127280040Syokota set_lockkey_state(kbd, state, ALK); 127380040Syokota state &= ~ALKDOWN; 127480040Syokota } 127580040Syokota action = RSH; 127680040Syokota /* FALL THROUGH */ 127780040Syokota case RSH: 127880040Syokota state &= ~SHIFTS2; 127980040Syokota break; 128080040Syokota case LCTRA: 128180040Syokota if (state & SHIFTAON) { 128280040Syokota set_lockkey_state(kbd, state, ALK); 128380040Syokota state &= ~ALKDOWN; 128480040Syokota } 128580040Syokota action = LCTR; 128680040Syokota /* FALL THROUGH */ 128780040Syokota case LCTR: 128880040Syokota state &= ~CTLS1; 128980040Syokota break; 129080040Syokota case RCTRA: 129180040Syokota if (state & SHIFTAON) { 129280040Syokota set_lockkey_state(kbd, state, ALK); 129380040Syokota state &= ~ALKDOWN; 129480040Syokota } 129580040Syokota action = RCTR; 129680040Syokota /* FALL THROUGH */ 129780040Syokota case RCTR: 129880040Syokota state &= ~CTLS2; 129980040Syokota break; 130080040Syokota case LALTA: 130180040Syokota if (state & SHIFTAON) { 130280040Syokota set_lockkey_state(kbd, state, ALK); 130380040Syokota state &= ~ALKDOWN; 130480040Syokota } 130580040Syokota action = LALT; 130680040Syokota /* FALL THROUGH */ 130780040Syokota case LALT: 130880040Syokota state &= ~ALTS1; 130980040Syokota break; 131080040Syokota case RALTA: 131180040Syokota if (state & SHIFTAON) { 131280040Syokota set_lockkey_state(kbd, state, ALK); 131380040Syokota state &= ~ALKDOWN; 131480040Syokota } 131580040Syokota action = RALT; 131680040Syokota /* FALL THROUGH */ 131780040Syokota case RALT: 131880040Syokota state &= ~ALTS2; 131980040Syokota break; 132080040Syokota case ASH: 132180040Syokota state &= ~AGRS1; 132280040Syokota break; 132380040Syokota case META: 132480040Syokota state &= ~METAS1; 132580040Syokota break; 132680040Syokota case NLK: 132780040Syokota state &= ~NLKDOWN; 132880040Syokota break; 132980040Syokota case CLK: 133042421Syokota#ifndef PC98 133180040Syokota state &= ~CLKDOWN; 133242421Syokota#else 133380040Syokota state &= ~CLKED; 133480040Syokota i = state & LOCK_MASK; 1335213770Srpaulo (void)kbdd_ioctl(kbd, KDSETLED, (caddr_t)&i); 133642421Syokota#endif 133780040Syokota break; 133880040Syokota case SLK: 133980040Syokota state &= ~SLKDOWN; 134080040Syokota break; 134180040Syokota case ALK: 134280040Syokota state &= ~ALKDOWN; 134380040Syokota break; 134480040Syokota case NOP: 134580040Syokota /* release events of regular keys are not reported */ 134680040Syokota *shiftstate &= ~SHIFTAON; 1347127752Sdes return (NOKEY); 134842421Syokota } 134980040Syokota *shiftstate = state & ~SHIFTAON; 135080040Syokota return (SPCLKEY | RELKEY | action); 135142421Syokota } else { /* make: key pressed */ 135280040Syokota action = key->map[i]; 135355820Syokota state &= ~SHIFTAON; 135442421Syokota if (key->spcl & (0x80 >> i)) { 135542421Syokota /* special keys */ 135680040Syokota if (kbd->kb_lastact[keycode] == NOP) 135780040Syokota kbd->kb_lastact[keycode] = action; 135880040Syokota if (kbd->kb_lastact[keycode] != action) 135980040Syokota action = NOP; 136042421Syokota switch (action) { 136142421Syokota /* LOCKING KEYS */ 136242421Syokota case NLK: 136342421Syokota set_lockkey_state(kbd, state, NLK); 136442421Syokota break; 136542421Syokota case CLK: 136642421Syokota#ifndef PC98 136742421Syokota set_lockkey_state(kbd, state, CLK); 136842421Syokota#else 136942421Syokota state |= CLKED; 137042421Syokota i = state & LOCK_MASK; 1371213770Srpaulo (void)kbdd_ioctl(kbd, KDSETLED, (caddr_t)&i); 137242421Syokota#endif 137342421Syokota break; 137442421Syokota case SLK: 137542421Syokota set_lockkey_state(kbd, state, SLK); 137642421Syokota break; 137742421Syokota case ALK: 137842421Syokota set_lockkey_state(kbd, state, ALK); 137942421Syokota break; 138042421Syokota /* NON-LOCKING KEYS */ 138142421Syokota case SPSC: case RBT: case SUSP: case STBY: 138254382Syokota case DBG: case NEXT: case PREV: case PNC: 138365759Sdwmalone case HALT: case PDWN: 138442421Syokota *accents = 0; 138542421Syokota break; 138642421Syokota case BTAB: 138742421Syokota *accents = 0; 138842421Syokota action |= BKEY; 138942421Syokota break; 139054382Syokota case LSHA: 139155820Syokota state |= SHIFTAON; 139254382Syokota action = LSH; 139354382Syokota /* FALL THROUGH */ 139442421Syokota case LSH: 139542421Syokota state |= SHIFTS1; 139642421Syokota break; 139754382Syokota case RSHA: 139855820Syokota state |= SHIFTAON; 139954382Syokota action = RSH; 140054382Syokota /* FALL THROUGH */ 140142421Syokota case RSH: 140242421Syokota state |= SHIFTS2; 140342421Syokota break; 140454382Syokota case LCTRA: 140555820Syokota state |= SHIFTAON; 140654382Syokota action = LCTR; 140754382Syokota /* FALL THROUGH */ 140842421Syokota case LCTR: 140942421Syokota state |= CTLS1; 141042421Syokota break; 141154382Syokota case RCTRA: 141255820Syokota state |= SHIFTAON; 141354382Syokota action = RCTR; 141454382Syokota /* FALL THROUGH */ 141542421Syokota case RCTR: 141642421Syokota state |= CTLS2; 141742421Syokota break; 141854382Syokota case LALTA: 141955820Syokota state |= SHIFTAON; 142054382Syokota action = LALT; 142154382Syokota /* FALL THROUGH */ 142242421Syokota case LALT: 142342421Syokota state |= ALTS1; 142442421Syokota break; 142554382Syokota case RALTA: 142655820Syokota state |= SHIFTAON; 142754382Syokota action = RALT; 142854382Syokota /* FALL THROUGH */ 142942421Syokota case RALT: 143042421Syokota state |= ALTS2; 143142421Syokota break; 143242421Syokota case ASH: 143342421Syokota state |= AGRS1; 143442421Syokota break; 143542421Syokota case META: 143642421Syokota state |= METAS1; 143742421Syokota break; 143880040Syokota case NOP: 143980040Syokota *shiftstate = state; 1440127752Sdes return (NOKEY); 144142421Syokota default: 144242421Syokota /* is this an accent (dead) key? */ 144355820Syokota *shiftstate = state; 144442421Syokota if (action >= F_ACC && action <= L_ACC) { 144542421Syokota action = save_accent_key(kbd, action, 144642421Syokota accents); 144742421Syokota switch (action) { 144842421Syokota case NOKEY: 144942421Syokota case ERRKEY: 1450127752Sdes return (action); 145142421Syokota default: 145242421Syokota if (state & METAS) 145342421Syokota return (action | MKEY); 145442421Syokota else 1455127752Sdes return (action); 145642421Syokota } 145742421Syokota /* NOT REACHED */ 145842421Syokota } 145942421Syokota /* other special keys */ 146042421Syokota if (*accents > 0) { 146142421Syokota *accents = 0; 1462127752Sdes return (ERRKEY); 146342421Syokota } 146442421Syokota if (action >= F_FN && action <= L_FN) 146542421Syokota action |= FKEY; 146642421Syokota /* XXX: return fkey string for the FKEY? */ 146755820Syokota return (SPCLKEY | action); 146842421Syokota } 146942421Syokota *shiftstate = state; 147042421Syokota return (SPCLKEY | action); 147142421Syokota } else { 147242421Syokota /* regular keys */ 147380040Syokota kbd->kb_lastact[keycode] = NOP; 147455820Syokota *shiftstate = state; 147542421Syokota if (*accents > 0) { 147642421Syokota /* make an accented char */ 147742421Syokota action = make_accent_char(kbd, action, accents); 147842421Syokota if (action == ERRKEY) 1479127752Sdes return (action); 148042421Syokota } 148142421Syokota if (state & METAS) 148242421Syokota action |= MKEY; 1483127752Sdes return (action); 148442421Syokota } 148542421Syokota } 148642421Syokota /* NOT REACHED */ 148742421Syokota} 1488