kbd.c revision 127752
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 127752 2004-04-02 16:41:16Z des $"); 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> 3842421Syokota#include <sys/tty.h> 3942421Syokota#include <sys/poll.h> 40112050Sdwmalone#include <sys/proc.h> 41112050Sdwmalone#include <sys/sysctl.h> 4242421Syokota#include <sys/vnode.h> 4342421Syokota#include <sys/uio.h> 4442421Syokota 4566834Sphk#include <sys/kbio.h> 4642421Syokota 4742421Syokota#include <dev/kbd/kbdreg.h> 4842421Syokota 4950154Syokota#define KBD_INDEX(dev) minor(dev) 5050154Syokota 5150154Syokotatypedef struct genkbd_softc { 5250154Syokota int gkb_flags; /* flag/status bits */ 5350154Syokota#define KB_ASLEEP (1 << 0) 5450154Syokota struct clist gkb_q; /* input queue */ 5550154Syokota struct selinfo gkb_rsel; 5650154Syokota} genkbd_softc_t; 5750154Syokota 5860938Sjakestatic SLIST_HEAD(, keyboard_driver) keyboard_drivers = 59127751Sdes SLIST_HEAD_INITIALIZER(keyboard_drivers); 6054545Syokota 6178161SpeterSET_DECLARE(kbddriver_set, const keyboard_driver_t); 6278161Speter 6342421Syokota/* local arrays */ 6442421Syokota 6542421Syokota/* 6642421Syokota * We need at least one entry each in order to initialize a keyboard 6742421Syokota * for the kernel console. The arrays will be increased dynamically 6842421Syokota * when necessary. 6942421Syokota */ 7042564Syokota 7142564Syokotastatic int keyboards = 1; 7242421Syokotastatic keyboard_t *kbd_ini; 7342564Syokotastatic keyboard_t **keyboard = &kbd_ini; 7442421Syokotastatic keyboard_switch_t *kbdsw_ini; 7542421Syokota keyboard_switch_t **kbdsw = &kbdsw_ini; 7642421Syokota 77112050Sdwmalonestatic int keymap_restrict_change; 78112050SdwmaloneSYSCTL_NODE(_hw, OID_AUTO, kbd, CTLFLAG_RD, 0, "kbd"); 79112050SdwmaloneSYSCTL_INT(_hw_kbd, OID_AUTO, keymap_restrict_change, CTLFLAG_RW, 80112050Sdwmalone &keymap_restrict_change, 0, "restrict ability to change keymap"); 81112050Sdwmalone 8242421Syokota#define ARRAY_DELTA 4 8342421Syokota 8444628Syokotastatic int 8542421Syokotakbd_realloc_array(void) 8642421Syokota{ 8742421Syokota keyboard_t **new_kbd; 8842421Syokota keyboard_switch_t **new_kbdsw; 8942421Syokota int newsize; 9042421Syokota int s; 9142421Syokota 9242421Syokota s = spltty(); 9342421Syokota newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA; 9469781Sdwmalone new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT|M_ZERO); 9544628Syokota if (new_kbd == NULL) { 9644628Syokota splx(s); 97127752Sdes return (ENOMEM); 9844628Syokota } 9969781Sdwmalone new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF, 10069781Sdwmalone M_NOWAIT|M_ZERO); 10144628Syokota if (new_kbdsw == NULL) { 10244628Syokota free(new_kbd, M_DEVBUF); 10344628Syokota splx(s); 104127752Sdes return (ENOMEM); 10544628Syokota } 10642421Syokota bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards); 10742421Syokota bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards); 10842421Syokota if (keyboards > 1) { 10942421Syokota free(keyboard, M_DEVBUF); 11042421Syokota free(kbdsw, M_DEVBUF); 11142421Syokota } 11242421Syokota keyboard = new_kbd; 11342421Syokota kbdsw = new_kbdsw; 11442421Syokota keyboards = newsize; 11542421Syokota splx(s); 11642421Syokota 11742421Syokota if (bootverbose) 11842421Syokota printf("kbd: new array size %d\n", keyboards); 11944628Syokota 120127752Sdes return (0); 12142421Syokota} 12242421Syokota 12342421Syokota/* 12442421Syokota * Low-level keyboard driver functions 12542421Syokota * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard 12642421Syokota * driver, call these functions to initialize the keyboard_t structure 12742421Syokota * and register it to the virtual keyboard driver `kbd'. 12842421Syokota */ 12942421Syokota 13042421Syokota/* initialize the keyboard_t structure */ 13142421Syokotavoid 13242421Syokotakbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config, 13342421Syokota int port, int port_size) 13442421Syokota{ 13542421Syokota kbd->kb_flags = KB_NO_DEVICE; /* device has not been found */ 13642421Syokota kbd->kb_name = name; 13742421Syokota kbd->kb_type = type; 13842421Syokota kbd->kb_unit = unit; 13944628Syokota kbd->kb_config = config & ~KB_CONF_PROBE_ONLY; 14042421Syokota kbd->kb_led = 0; /* unknown */ 14142421Syokota kbd->kb_io_base = port; 14242421Syokota kbd->kb_io_size = port_size; 14342421Syokota kbd->kb_data = NULL; 14442421Syokota kbd->kb_keymap = NULL; 14542421Syokota kbd->kb_accentmap = NULL; 14642421Syokota kbd->kb_fkeytab = NULL; 14742421Syokota kbd->kb_fkeytab_size = 0; 14844628Syokota kbd->kb_delay1 = KB_DELAY1; /* these values are advisory only */ 14944628Syokota kbd->kb_delay2 = KB_DELAY2; 15054382Syokota kbd->kb_count = 0L; 15180040Syokota bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact)); 15242421Syokota} 15342421Syokota 15442421Syokotavoid 15542421Syokotakbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap, 15642421Syokota fkeytab_t *fkeymap, int fkeymap_size) 15742421Syokota{ 15842421Syokota kbd->kb_keymap = keymap; 15942421Syokota kbd->kb_accentmap = accmap; 16042421Syokota kbd->kb_fkeytab = fkeymap; 16142421Syokota kbd->kb_fkeytab_size = fkeymap_size; 16242421Syokota} 16342421Syokota 16454545Syokota/* declare a new keyboard driver */ 16554545Syokotaint 16654545Syokotakbd_add_driver(keyboard_driver_t *driver) 16754545Syokota{ 16854545Syokota if (SLIST_NEXT(driver, link)) 169127752Sdes return (EINVAL); 17054545Syokota SLIST_INSERT_HEAD(&keyboard_drivers, driver, link); 171127752Sdes return (0); 17254545Syokota} 17354545Syokota 17454545Syokotaint 17554545Syokotakbd_delete_driver(keyboard_driver_t *driver) 17654545Syokota{ 17760938Sjake SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link); 17854545Syokota SLIST_NEXT(driver, link) = NULL; 179127752Sdes return (0); 18054545Syokota} 18154545Syokota 18242421Syokota/* register a keyboard and associate it with a function table */ 18342421Syokotaint 18442421Syokotakbd_register(keyboard_t *kbd) 18542421Syokota{ 18647295Syokota const keyboard_driver_t **list; 18747295Syokota const keyboard_driver_t *p; 18842421Syokota int index; 18942421Syokota 19042421Syokota for (index = 0; index < keyboards; ++index) { 19142421Syokota if (keyboard[index] == NULL) 19242421Syokota break; 19342421Syokota } 19444628Syokota if (index >= keyboards) { 19544628Syokota if (kbd_realloc_array()) 196127752Sdes return (-1); 19744628Syokota } 19842421Syokota 19942421Syokota kbd->kb_index = index; 20042421Syokota KBD_UNBUSY(kbd); 20142421Syokota KBD_VALID(kbd); 20242421Syokota kbd->kb_active = 0; /* disabled until someone calls kbd_enable() */ 20342421Syokota kbd->kb_token = NULL; 20442421Syokota kbd->kb_callback.kc_func = NULL; 20542421Syokota kbd->kb_callback.kc_arg = NULL; 20642421Syokota 20754545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 20854545Syokota if (strcmp(p->name, kbd->kb_name) == 0) { 20954545Syokota keyboard[index] = kbd; 21054545Syokota kbdsw[index] = p->kbdsw; 211127752Sdes return (index); 21254545Syokota } 21354545Syokota } 21478161Speter SET_FOREACH(list, kbddriver_set) { 21578161Speter p = *list; 21642421Syokota if (strcmp(p->name, kbd->kb_name) == 0) { 21742421Syokota keyboard[index] = kbd; 21842421Syokota kbdsw[index] = p->kbdsw; 219127752Sdes return (index); 22042421Syokota } 22142421Syokota } 22242421Syokota 223127752Sdes return (-1); 22442421Syokota} 22542421Syokota 22642421Syokotaint 22742421Syokotakbd_unregister(keyboard_t *kbd) 22842421Syokota{ 22942421Syokota int error; 23042421Syokota int s; 23142421Syokota 23242421Syokota if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards)) 233127752Sdes return (ENOENT); 23442421Syokota if (keyboard[kbd->kb_index] != kbd) 235127752Sdes return (ENOENT); 23642421Syokota 23742421Syokota s = spltty(); 23842421Syokota if (KBD_IS_BUSY(kbd)) { 23942421Syokota error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING, 240127752Sdes kbd->kb_callback.kc_arg); 24142421Syokota if (error) { 24242421Syokota splx(s); 243127752Sdes return (error); 24442421Syokota } 24542421Syokota if (KBD_IS_BUSY(kbd)) { 24642421Syokota splx(s); 247127752Sdes return (EBUSY); 24842421Syokota } 24942421Syokota } 25042421Syokota KBD_INVALID(kbd); 25142421Syokota keyboard[kbd->kb_index] = NULL; 25242421Syokota kbdsw[kbd->kb_index] = NULL; 25342421Syokota 25442421Syokota splx(s); 255127752Sdes return (0); 25642421Syokota} 25742421Syokota 25842421Syokota/* find a funciton table by the driver name */ 25942421Syokotakeyboard_switch_t 26042421Syokota*kbd_get_switch(char *driver) 26142421Syokota{ 26247295Syokota const keyboard_driver_t **list; 26347295Syokota const keyboard_driver_t *p; 26442421Syokota 26554545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 26654545Syokota if (strcmp(p->name, driver) == 0) 267127752Sdes return (p->kbdsw); 26854545Syokota } 26978161Speter SET_FOREACH(list, kbddriver_set) { 27078161Speter p = *list; 27142421Syokota if (strcmp(p->name, driver) == 0) 272127752Sdes return (p->kbdsw); 27342421Syokota } 27442421Syokota 275127752Sdes return (NULL); 27642421Syokota} 27742421Syokota 27842421Syokota/* 27942421Syokota * Keyboard client functions 28042421Syokota * Keyboard clients, such as the console driver `syscons' and the keyboard 28142421Syokota * cdev driver, use these functions to claim and release a keyboard for 28242421Syokota * exclusive use. 28342421Syokota */ 28442421Syokota 28542421Syokota/* find the keyboard specified by a driver name and a unit number */ 28642421Syokotaint 28742421Syokotakbd_find_keyboard(char *driver, int unit) 28842421Syokota{ 28942421Syokota int i; 29042421Syokota 29142421Syokota for (i = 0; i < keyboards; ++i) { 29242421Syokota if (keyboard[i] == NULL) 29342421Syokota continue; 29442421Syokota if (!KBD_IS_VALID(keyboard[i])) 29542421Syokota continue; 29642421Syokota if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver)) 29742421Syokota continue; 29842421Syokota if ((unit != -1) && (keyboard[i]->kb_unit != unit)) 29942421Syokota continue; 300127752Sdes return (i); 30142421Syokota } 302127752Sdes return (-1); 30342421Syokota} 30442421Syokota 30542421Syokota/* allocate a keyboard */ 30642421Syokotaint 30742421Syokotakbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func, 30842421Syokota void *arg) 30942421Syokota{ 31042421Syokota int index; 31142421Syokota int s; 31242421Syokota 31342421Syokota if (func == NULL) 314127752Sdes return (-1); 31542421Syokota 31642421Syokota s = spltty(); 31742421Syokota index = kbd_find_keyboard(driver, unit); 31842421Syokota if (index >= 0) { 31942421Syokota if (KBD_IS_BUSY(keyboard[index])) { 32042421Syokota splx(s); 321127752Sdes return (-1); 32242421Syokota } 32342421Syokota keyboard[index]->kb_token = id; 32442421Syokota KBD_BUSY(keyboard[index]); 32542421Syokota keyboard[index]->kb_callback.kc_func = func; 32642421Syokota keyboard[index]->kb_callback.kc_arg = arg; 32742421Syokota (*kbdsw[index]->clear_state)(keyboard[index]); 32842421Syokota } 32942421Syokota splx(s); 330127752Sdes return (index); 33142421Syokota} 33242421Syokota 33342421Syokotaint 33442421Syokotakbd_release(keyboard_t *kbd, void *id) 33542421Syokota{ 33642421Syokota int error; 33742421Syokota int s; 33842421Syokota 33942421Syokota s = spltty(); 34042421Syokota if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 34142421Syokota error = EINVAL; 34242421Syokota } else if (kbd->kb_token != id) { 34342421Syokota error = EPERM; 34442421Syokota } else { 34542421Syokota kbd->kb_token = NULL; 34642421Syokota KBD_UNBUSY(kbd); 34742421Syokota kbd->kb_callback.kc_func = NULL; 34842421Syokota kbd->kb_callback.kc_arg = NULL; 34942421Syokota (*kbdsw[kbd->kb_index]->clear_state)(kbd); 35042421Syokota error = 0; 35142421Syokota } 35242421Syokota splx(s); 353127752Sdes return (error); 35442421Syokota} 35542421Syokota 35642421Syokotaint 35742421Syokotakbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func, 35842421Syokota void *arg) 35942421Syokota{ 36042421Syokota int error; 36142421Syokota int s; 36242421Syokota 36342421Syokota s = spltty(); 36442421Syokota if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 36542421Syokota error = EINVAL; 36642421Syokota } else if (kbd->kb_token != id) { 36742421Syokota error = EPERM; 36842421Syokota } else if (func == NULL) { 36942421Syokota error = EINVAL; 37042421Syokota } else { 37142421Syokota kbd->kb_callback.kc_func = func; 37242421Syokota kbd->kb_callback.kc_arg = arg; 37342421Syokota error = 0; 37442421Syokota } 37542421Syokota splx(s); 376127752Sdes return (error); 37742421Syokota} 37842421Syokota 37942421Syokota/* get a keyboard structure */ 38042421Syokotakeyboard_t 38142421Syokota*kbd_get_keyboard(int index) 38242421Syokota{ 38342421Syokota if ((index < 0) || (index >= keyboards)) 384127752Sdes return (NULL); 38550154Syokota if (keyboard[index] == NULL) 386127752Sdes return (NULL); 38742421Syokota if (!KBD_IS_VALID(keyboard[index])) 388127752Sdes return (NULL); 389127752Sdes return (keyboard[index]); 39042421Syokota} 39142421Syokota 39242421Syokota/* 39342421Syokota * The back door for the console driver; configure keyboards 39442421Syokota * This function is for the kernel console to initialize keyboards 39542421Syokota * at very early stage. 39642421Syokota */ 39742421Syokota 39842421Syokotaint 39942421Syokotakbd_configure(int flags) 40042421Syokota{ 40147295Syokota const keyboard_driver_t **list; 40247295Syokota const keyboard_driver_t *p; 40342421Syokota 40454545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 40554545Syokota if (p->configure != NULL) 40654545Syokota (*p->configure)(flags); 40754545Syokota } 40878161Speter SET_FOREACH(list, kbddriver_set) { 40978161Speter p = *list; 41042421Syokota if (p->configure != NULL) 41142421Syokota (*p->configure)(flags); 41242421Syokota } 41342421Syokota 414127752Sdes return (0); 41542421Syokota} 41642421Syokota 41742421Syokota#ifdef KBD_INSTALL_CDEV 41842421Syokota 41942421Syokota/* 42042421Syokota * Virtual keyboard cdev driver functions 42142421Syokota * The virtual keyboard driver dispatches driver functions to 42242421Syokota * appropriate subdrivers. 42342421Syokota */ 42442421Syokota 42542421Syokota#define KBD_UNIT(dev) minor(dev) 42642421Syokota 42750154Syokotastatic d_open_t genkbdopen; 42850154Syokotastatic d_close_t genkbdclose; 42950154Syokotastatic d_read_t genkbdread; 43050154Syokotastatic d_write_t genkbdwrite; 43150154Syokotastatic d_ioctl_t genkbdioctl; 43250154Syokotastatic d_poll_t genkbdpoll; 43342421Syokota 43442421Syokota 43542421Syokotastatic struct cdevsw kbd_cdevsw = { 436126080Sphk .d_version = D_VERSION, 437126080Sphk .d_flags = D_NEEDGIANT, 438111815Sphk .d_open = genkbdopen, 439111815Sphk .d_close = genkbdclose, 440111815Sphk .d_read = genkbdread, 441111815Sphk .d_write = genkbdwrite, 442111815Sphk .d_ioctl = genkbdioctl, 443111815Sphk .d_poll = genkbdpoll, 444111815Sphk .d_name = "kbd", 44542421Syokota}; 44642421Syokota 44742421Syokotaint 44850154Syokotakbd_attach(keyboard_t *kbd) 44942421Syokota{ 45042421Syokota 45142421Syokota if (kbd->kb_index >= keyboards) 452127752Sdes return (EINVAL); 45342421Syokota if (keyboard[kbd->kb_index] != kbd) 454127752Sdes return (EINVAL); 45542421Syokota 456127751Sdes kbd->kb_dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 457127751Sdes 0600, "%s%r", kbd->kb_name, kbd->kb_unit); 458125087Sdes make_dev_alias(kbd->kb_dev, "kbd%r", kbd->kb_index); 459120502Sphk kbd->kb_dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF, 460127751Sdes M_WAITOK | M_ZERO); 46142421Syokota printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit); 462127752Sdes return (0); 46342421Syokota} 46442421Syokota 46542421Syokotaint 46650154Syokotakbd_detach(keyboard_t *kbd) 46742421Syokota{ 46854545Syokota 46942421Syokota if (kbd->kb_index >= keyboards) 470127752Sdes return (EINVAL); 47142421Syokota if (keyboard[kbd->kb_index] != kbd) 472127752Sdes return (EINVAL); 47342421Syokota 474120502Sphk free(kbd->kb_dev->si_drv1, M_DEVBUF); 475120502Sphk destroy_dev(kbd->kb_dev); 47654545Syokota 477127752Sdes return (0); 47842421Syokota} 47942421Syokota 48042421Syokota/* 48142421Syokota * Generic keyboard cdev driver functions 48242421Syokota * Keyboard subdrivers may call these functions to implement common 48342421Syokota * driver functions. 48442421Syokota */ 48542421Syokota 48642421Syokota#define KB_QSIZE 512 48742421Syokota#define KB_BUFSIZE 64 48842421Syokota 48942421Syokotastatic kbd_callback_func_t genkbd_event; 49042421Syokota 49150154Syokotastatic int 49283366Sjuliangenkbdopen(dev_t dev, int mode, int flag, struct thread *td) 49342421Syokota{ 49450154Syokota keyboard_t *kbd; 49550154Syokota genkbd_softc_t *sc; 49642421Syokota int s; 49742421Syokota int i; 49842421Syokota 49942421Syokota s = spltty(); 50050154Syokota sc = dev->si_drv1; 50150154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 50250154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 50342421Syokota splx(s); 504127752Sdes return (ENXIO); 50542421Syokota } 50642421Syokota i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc, 507127751Sdes genkbd_event, (void *)sc); 50842421Syokota if (i < 0) { 50942421Syokota splx(s); 510127752Sdes return (EBUSY); 51142421Syokota } 51242421Syokota /* assert(i == kbd->kb_index) */ 51342421Syokota /* assert(kbd == kbd_get_keyboard(i)) */ 51442421Syokota 51542421Syokota /* 51642421Syokota * NOTE: even when we have successfully claimed a keyboard, 51742421Syokota * the device may still be missing (!KBD_HAS_DEVICE(kbd)). 51842421Syokota */ 51942421Syokota 52042421Syokota#if 0 52142421Syokota bzero(&sc->gkb_q, sizeof(sc->gkb_q)); 52242421Syokota#endif 52342421Syokota clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */ 52442421Syokota splx(s); 52542421Syokota 526127752Sdes return (0); 52742421Syokota} 52842421Syokota 52950154Syokotastatic int 53083366Sjuliangenkbdclose(dev_t dev, int mode, int flag, struct thread *td) 53142421Syokota{ 53250154Syokota keyboard_t *kbd; 53350154Syokota genkbd_softc_t *sc; 53442421Syokota int s; 53542421Syokota 53642421Syokota /* 53742421Syokota * NOTE: the device may have already become invalid. 53850154Syokota * kbd == NULL || !KBD_IS_VALID(kbd) 53942421Syokota */ 54042421Syokota s = spltty(); 54150154Syokota sc = dev->si_drv1; 54250154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 54350154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 54450154Syokota /* XXX: we shall be forgiving and don't report error... */ 54550154Syokota } else { 54650154Syokota kbd_release(kbd, (void *)sc); 54742421Syokota#if 0 54850154Syokota clist_free_cblocks(&sc->gkb_q); 54942421Syokota#endif 55050154Syokota } 55142421Syokota splx(s); 552127752Sdes return (0); 55342421Syokota} 55442421Syokota 55550154Syokotastatic int 55650154Syokotagenkbdread(dev_t dev, struct uio *uio, int flag) 55742421Syokota{ 55850154Syokota keyboard_t *kbd; 55950154Syokota genkbd_softc_t *sc; 56042421Syokota u_char buffer[KB_BUFSIZE]; 56142421Syokota int len; 56242421Syokota int error; 56342421Syokota int s; 56442421Syokota 56542421Syokota /* wait for input */ 56642421Syokota s = spltty(); 56750154Syokota sc = dev->si_drv1; 56850154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 56950154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 57050154Syokota splx(s); 571127752Sdes return (ENXIO); 57250154Syokota } 57342421Syokota while (sc->gkb_q.c_cc == 0) { 57442421Syokota if (flag & IO_NDELAY) { 57542421Syokota splx(s); 576127752Sdes return (EWOULDBLOCK); 57742421Syokota } 57842421Syokota sc->gkb_flags |= KB_ASLEEP; 579111748Sdes error = tsleep(sc, PZERO | PCATCH, "kbdrea", 0); 58050154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 58150154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) { 58250154Syokota splx(s); 583127752Sdes return (ENXIO); /* our keyboard has gone... */ 58450154Syokota } 58542421Syokota if (error) { 58642421Syokota sc->gkb_flags &= ~KB_ASLEEP; 58742421Syokota splx(s); 588127752Sdes return (error); 58942421Syokota } 59042421Syokota } 59142421Syokota splx(s); 59242421Syokota 59342421Syokota /* copy as much input as possible */ 59442421Syokota error = 0; 59542421Syokota while (uio->uio_resid > 0) { 59642421Syokota len = imin(uio->uio_resid, sizeof(buffer)); 59742421Syokota len = q_to_b(&sc->gkb_q, buffer, len); 59842421Syokota if (len <= 0) 59942421Syokota break; 60042421Syokota error = uiomove(buffer, len, uio); 60142421Syokota if (error) 60242421Syokota break; 60342421Syokota } 60442421Syokota 605127752Sdes return (error); 60642421Syokota} 60742421Syokota 60850154Syokotastatic int 60950154Syokotagenkbdwrite(dev_t dev, struct uio *uio, int flag) 61042421Syokota{ 61150154Syokota keyboard_t *kbd; 61250154Syokota 61350154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 61450154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) 615127752Sdes return (ENXIO); 616127752Sdes return (ENODEV); 61742421Syokota} 61842421Syokota 61950154Syokotastatic int 62083366Sjuliangenkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 62142421Syokota{ 62250154Syokota keyboard_t *kbd; 62342421Syokota int error; 62442421Syokota 62550154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 62650154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) 627127752Sdes return (ENXIO); 62842421Syokota error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg); 62942421Syokota if (error == ENOIOCTL) 63042421Syokota error = ENODEV; 631127752Sdes return (error); 63242421Syokota} 63342421Syokota 63450154Syokotastatic int 63583366Sjuliangenkbdpoll(dev_t dev, int events, struct thread *td) 63642421Syokota{ 63750154Syokota keyboard_t *kbd; 63850154Syokota genkbd_softc_t *sc; 63942421Syokota int revents; 64042421Syokota int s; 64142421Syokota 64242421Syokota revents = 0; 64342421Syokota s = spltty(); 64450154Syokota sc = dev->si_drv1; 64550154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 64650154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 64750154Syokota revents = POLLHUP; /* the keyboard has gone */ 64850154Syokota } else if (events & (POLLIN | POLLRDNORM)) { 64950154Syokota if (sc->gkb_q.c_cc > 0) 65050154Syokota revents = events & (POLLIN | POLLRDNORM); 65142421Syokota else 65283366Sjulian selrecord(td, &sc->gkb_rsel); 65342421Syokota } 65442421Syokota splx(s); 655127752Sdes return (revents); 65642421Syokota} 65742421Syokota 65842421Syokotastatic int 65942421Syokotagenkbd_event(keyboard_t *kbd, int event, void *arg) 66042421Syokota{ 66142421Syokota genkbd_softc_t *sc; 66242421Syokota size_t len; 66342421Syokota u_char *cp; 66442421Syokota int mode; 66542421Syokota int c; 66642421Syokota 66742421Syokota /* assert(KBD_IS_VALID(kbd)) */ 66842421Syokota sc = (genkbd_softc_t *)arg; 66942421Syokota 67042421Syokota switch (event) { 67142421Syokota case KBDIO_KEYINPUT: 67242421Syokota break; 67342421Syokota case KBDIO_UNLOADING: 67442421Syokota /* the keyboard is going... */ 67542421Syokota kbd_release(kbd, (void *)sc); 67650154Syokota if (sc->gkb_flags & KB_ASLEEP) { 67750154Syokota sc->gkb_flags &= ~KB_ASLEEP; 678111748Sdes wakeup(sc); 67950154Syokota } 680122352Stanimura selwakeuppri(&sc->gkb_rsel, PZERO); 681127752Sdes return (0); 68242421Syokota default: 683127752Sdes return (EINVAL); 68442421Syokota } 68542421Syokota 68642421Syokota /* obtain the current key input mode */ 68742421Syokota if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode)) 68842421Syokota mode = K_XLATE; 68942421Syokota 69042421Syokota /* read all pending input */ 69142421Syokota while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) { 69242421Syokota c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE); 69342421Syokota if (c == NOKEY) 69442421Syokota continue; 69542421Syokota if (c == ERRKEY) /* XXX: ring bell? */ 69642421Syokota continue; 69742421Syokota if (!KBD_IS_BUSY(kbd)) 69842421Syokota /* the device is not open, discard the input */ 69942421Syokota continue; 70042421Syokota 70142421Syokota /* store the byte as is for K_RAW and K_CODE modes */ 70242421Syokota if (mode != K_XLATE) { 70342421Syokota putc(KEYCHAR(c), &sc->gkb_q); 70442421Syokota continue; 70542421Syokota } 70642421Syokota 70742421Syokota /* K_XLATE */ 70842421Syokota if (c & RELKEY) /* key release is ignored */ 70942421Syokota continue; 71042421Syokota 71142421Syokota /* process special keys; most of them are just ignored... */ 71242421Syokota if (c & SPCLKEY) { 71342421Syokota switch (KEYCHAR(c)) { 71454382Syokota default: 71542421Syokota /* ignore them... */ 71642421Syokota continue; 71742421Syokota case BTAB: /* a backtab: ESC [ Z */ 71842421Syokota putc(0x1b, &sc->gkb_q); 71942421Syokota putc('[', &sc->gkb_q); 72042421Syokota putc('Z', &sc->gkb_q); 72142421Syokota continue; 72242421Syokota } 72342421Syokota } 72442421Syokota 72542421Syokota /* normal chars, normal chars with the META, function keys */ 72642421Syokota switch (KEYFLAGS(c)) { 72742421Syokota case 0: /* a normal char */ 72842421Syokota putc(KEYCHAR(c), &sc->gkb_q); 72942421Syokota break; 73042421Syokota case MKEY: /* the META flag: prepend ESC */ 73142421Syokota putc(0x1b, &sc->gkb_q); 73242421Syokota putc(KEYCHAR(c), &sc->gkb_q); 73342421Syokota break; 73442421Syokota case FKEY | SPCLKEY: /* a function key, return string */ 73542421Syokota cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd, 736127751Sdes KEYCHAR(c), &len); 73742421Syokota if (cp != NULL) { 73842421Syokota while (len-- > 0) 73942421Syokota putc(*cp++, &sc->gkb_q); 74042421Syokota } 74142421Syokota break; 74242421Syokota } 74342421Syokota } 74442421Syokota 74542421Syokota /* wake up sleeping/polling processes */ 74642421Syokota if (sc->gkb_q.c_cc > 0) { 74742421Syokota if (sc->gkb_flags & KB_ASLEEP) { 74842421Syokota sc->gkb_flags &= ~KB_ASLEEP; 749111748Sdes wakeup(sc); 75042421Syokota } 751122352Stanimura selwakeuppri(&sc->gkb_rsel, PZERO); 75242421Syokota } 75342421Syokota 754127752Sdes return (0); 75542421Syokota} 75642421Syokota 75742421Syokota#endif /* KBD_INSTALL_CDEV */ 75842421Syokota 75942421Syokota/* 76042421Syokota * Generic low-level keyboard functions 76142421Syokota * The low-level functions in the keyboard subdriver may use these 76242421Syokota * functions. 76342421Syokota */ 76442421Syokota 765112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 766112050Sdwmalonestatic int key_change_ok(struct keyent_t *, struct keyent_t *, struct thread *); 767112050Sdwmalonestatic int keymap_change_ok(keymap_t *, keymap_t *, struct thread *); 768112050Sdwmalonestatic int accent_change_ok(accentmap_t *, accentmap_t *, struct thread *); 769112050Sdwmalonestatic int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct thread *); 770112050Sdwmalone#endif 771112050Sdwmalone 77242421Syokotaint 77342421Syokotagenkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 77442421Syokota{ 77542421Syokota keyarg_t *keyp; 77642421Syokota fkeyarg_t *fkeyp; 77742421Syokota int s; 77842421Syokota int i; 779112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 780112050Sdwmalone int error; 781112050Sdwmalone#endif 78242421Syokota 78342421Syokota s = spltty(); 78442421Syokota switch (cmd) { 78542421Syokota 78642421Syokota case KDGKBINFO: /* get keyboard information */ 78742421Syokota ((keyboard_info_t *)arg)->kb_index = kbd->kb_index; 78842421Syokota i = imin(strlen(kbd->kb_name) + 1, 789127751Sdes sizeof(((keyboard_info_t *)arg)->kb_name)); 79042421Syokota bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i); 79142421Syokota ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit; 79242421Syokota ((keyboard_info_t *)arg)->kb_type = kbd->kb_type; 79342421Syokota ((keyboard_info_t *)arg)->kb_config = kbd->kb_config; 79442421Syokota ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags; 79542421Syokota break; 79642421Syokota 79742421Syokota case KDGKBTYPE: /* get keyboard type */ 79842421Syokota *(int *)arg = kbd->kb_type; 79942421Syokota break; 80042421Syokota 80154543Syokota case KDGETREPEAT: /* get keyboard repeat rate */ 80254543Syokota ((int *)arg)[0] = kbd->kb_delay1; 803127751Sdes ((int *)arg)[1] = kbd->kb_delay2; 80454543Syokota break; 80554543Syokota 80642421Syokota case GIO_KEYMAP: /* get keyboard translation table */ 80742421Syokota bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap)); 80842421Syokota break; 80942421Syokota case PIO_KEYMAP: /* set keyboard translation table */ 81044628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 811112050Sdwmalone error = keymap_change_ok(kbd->kb_keymap, (keymap_t *)arg, 812112050Sdwmalone curthread); 813112050Sdwmalone if (error != 0) { 814112050Sdwmalone splx(s); 815127752Sdes return (error); 816112050Sdwmalone } 81742421Syokota bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 81842421Syokota bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap)); 81942421Syokota break; 82044628Syokota#else 82144628Syokota splx(s); 822127752Sdes return (ENODEV); 82344628Syokota#endif 82442421Syokota 82542421Syokota case GIO_KEYMAPENT: /* get keyboard translation table entry */ 82642421Syokota keyp = (keyarg_t *)arg; 827127751Sdes if (keyp->keynum >= sizeof(kbd->kb_keymap->key) / 828127751Sdes sizeof(kbd->kb_keymap->key[0])) { 82942421Syokota splx(s); 830127752Sdes return (EINVAL); 83142421Syokota } 83242573Syokota bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key, 833127751Sdes sizeof(keyp->key)); 83442421Syokota break; 83542421Syokota case PIO_KEYMAPENT: /* set keyboard translation table entry */ 83644628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 83742421Syokota keyp = (keyarg_t *)arg; 838127751Sdes if (keyp->keynum >= sizeof(kbd->kb_keymap->key) / 839127751Sdes sizeof(kbd->kb_keymap->key[0])) { 84042421Syokota splx(s); 841127752Sdes return (EINVAL); 84242421Syokota } 843112050Sdwmalone error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum], 844112050Sdwmalone &keyp->key, curthread); 845112050Sdwmalone if (error != 0) { 846112050Sdwmalone splx(s); 847127752Sdes return (error); 848112050Sdwmalone } 84942573Syokota bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum], 850127751Sdes sizeof(keyp->key)); 85142421Syokota break; 85244628Syokota#else 85344628Syokota splx(s); 854127752Sdes return (ENODEV); 85544628Syokota#endif 85642421Syokota 85742421Syokota case GIO_DEADKEYMAP: /* get accent key translation table */ 85842421Syokota bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap)); 85942421Syokota break; 86042421Syokota case PIO_DEADKEYMAP: /* set accent key translation table */ 86144628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 862112050Sdwmalone error = accent_change_ok(kbd->kb_accentmap, 863112050Sdwmalone (accentmap_t *)arg, curthread); 864112050Sdwmalone if (error != 0) { 865112050Sdwmalone splx(s); 866127752Sdes return (error); 867112050Sdwmalone } 86842421Syokota bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 86942421Syokota break; 87044628Syokota#else 87144628Syokota splx(s); 872127752Sdes return (ENODEV); 87344628Syokota#endif 87442421Syokota 87542421Syokota case GETFKEY: /* get functionkey string */ 87642421Syokota fkeyp = (fkeyarg_t *)arg; 87742421Syokota if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 87842421Syokota splx(s); 879127752Sdes return (EINVAL); 88042421Syokota } 88142421Syokota bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef, 882127751Sdes kbd->kb_fkeytab[fkeyp->keynum].len); 88342421Syokota fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len; 88442421Syokota break; 88542421Syokota case SETFKEY: /* set functionkey string */ 88644628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 88742421Syokota fkeyp = (fkeyarg_t *)arg; 88842421Syokota if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 88942421Syokota splx(s); 890127752Sdes return (EINVAL); 89142421Syokota } 892112050Sdwmalone error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum], 893112050Sdwmalone fkeyp, curthread); 894112050Sdwmalone if (error != 0) { 895112050Sdwmalone splx(s); 896127752Sdes return (error); 897112050Sdwmalone } 89842421Syokota kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK); 89942421Syokota bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str, 900127751Sdes kbd->kb_fkeytab[fkeyp->keynum].len); 90142421Syokota break; 90244628Syokota#else 90344628Syokota splx(s); 904127752Sdes return (ENODEV); 90544628Syokota#endif 90642421Syokota 90742421Syokota default: 90842421Syokota splx(s); 909127752Sdes return (ENOIOCTL); 91042421Syokota } 91142421Syokota 91242421Syokota splx(s); 913127752Sdes return (0); 91442421Syokota} 91542421Syokota 916112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 917112050Sdwmalone#define RESTRICTED_KEY(key, i) \ 918112050Sdwmalone ((key->spcl & (0x80 >> i)) && \ 919112050Sdwmalone (key->map[i] == RBT || key->map[i] == SUSP || \ 920112050Sdwmalone key->map[i] == STBY || key->map[i] == DBG || \ 921112050Sdwmalone key->map[i] == PNC || key->map[i] == HALT || \ 922112050Sdwmalone key->map[i] == PDWN)) 923112050Sdwmalone 924112050Sdwmalonestatic int 925112050Sdwmalonekey_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct thread *td) 926112050Sdwmalone{ 927112050Sdwmalone int i; 928112050Sdwmalone 929112050Sdwmalone /* Low keymap_restrict_change means any changes are OK. */ 930112050Sdwmalone if (keymap_restrict_change <= 0) 931127752Sdes return (0); 932112050Sdwmalone 933112050Sdwmalone /* High keymap_restrict_change means only root can change the keymap. */ 934112050Sdwmalone if (keymap_restrict_change >= 2) { 935112050Sdwmalone for (i = 0; i < NUM_STATES; i++) 936112050Sdwmalone if (oldkey->map[i] != newkey->map[i]) 937112050Sdwmalone return suser(td); 938112050Sdwmalone if (oldkey->spcl != newkey->spcl) 939112050Sdwmalone return suser(td); 940112050Sdwmalone if (oldkey->flgs != newkey->flgs) 941112050Sdwmalone return suser(td); 942127752Sdes return (0); 943112050Sdwmalone } 944112050Sdwmalone 945112050Sdwmalone /* Otherwise we have to see if any special keys are being changed. */ 946112050Sdwmalone for (i = 0; i < NUM_STATES; i++) { 947112050Sdwmalone /* 948112050Sdwmalone * If either the oldkey or the newkey action is restricted 949112050Sdwmalone * then we must make sure that the action doesn't change. 950112050Sdwmalone */ 951112050Sdwmalone if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i)) 952112050Sdwmalone continue; 953112050Sdwmalone if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i)) 954112050Sdwmalone && oldkey->map[i] == newkey->map[i]) 955112050Sdwmalone continue; 956112050Sdwmalone return suser(td); 957112050Sdwmalone } 958112050Sdwmalone 959127752Sdes return (0); 960112050Sdwmalone} 961112050Sdwmalone 962112050Sdwmalonestatic int 963112050Sdwmalonekeymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct thread *td) 964112050Sdwmalone{ 965112050Sdwmalone int keycode, error; 966112050Sdwmalone 967112050Sdwmalone for (keycode = 0; keycode < NUM_KEYS; keycode++) { 968112050Sdwmalone if ((error = key_change_ok(&oldmap->key[keycode], 969112050Sdwmalone &newmap->key[keycode], td)) != 0) 970127752Sdes return (error); 971112050Sdwmalone } 972127752Sdes return (0); 973112050Sdwmalone} 974112050Sdwmalone 975112050Sdwmalonestatic int 976112050Sdwmaloneaccent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct thread *td) 977112050Sdwmalone{ 978112050Sdwmalone struct acc_t *oldacc, *newacc; 979112050Sdwmalone int accent, i; 980112050Sdwmalone 981112050Sdwmalone if (keymap_restrict_change <= 2) 982127752Sdes return (0); 983112050Sdwmalone 984112050Sdwmalone if (oldmap->n_accs != newmap->n_accs) 985112050Sdwmalone return suser(td); 986112050Sdwmalone 987112050Sdwmalone for (accent = 0; accent < oldmap->n_accs; accent++) { 988112050Sdwmalone oldacc = &oldmap->acc[accent]; 989112050Sdwmalone newacc = &newmap->acc[accent]; 990112050Sdwmalone if (oldacc->accchar != newacc->accchar) 991112050Sdwmalone return suser(td); 992112050Sdwmalone for (i = 0; i < NUM_ACCENTCHARS; ++i) { 993112050Sdwmalone if (oldacc->map[i][0] != newacc->map[i][0]) 994112050Sdwmalone return suser(td); 995112050Sdwmalone if (oldacc->map[i][0] == 0) /* end of table */ 996112050Sdwmalone break; 997112050Sdwmalone if (oldacc->map[i][1] != newacc->map[i][1]) 998112050Sdwmalone return suser(td); 999112050Sdwmalone } 1000112050Sdwmalone } 1001112050Sdwmalone 1002127752Sdes return (0); 1003112050Sdwmalone} 1004112050Sdwmalone 1005112050Sdwmalonestatic int 1006112050Sdwmalonefkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct thread *td) 1007112050Sdwmalone{ 1008112050Sdwmalone if (keymap_restrict_change <= 3) 1009127752Sdes return (0); 1010112050Sdwmalone 1011112050Sdwmalone if (oldkey->len != newkey->flen || 1012112050Sdwmalone bcmp(oldkey->str, newkey->keydef, oldkey->len) != 0) 1013112050Sdwmalone return suser(td); 1014112050Sdwmalone 1015127752Sdes return (0); 1016112050Sdwmalone} 1017112050Sdwmalone#endif 1018112050Sdwmalone 101942421Syokota/* get a pointer to the string associated with the given function key */ 102042421Syokotau_char 102142421Syokota*genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len) 102242421Syokota{ 102342421Syokota if (kbd == NULL) 1024127752Sdes return (NULL); 102542421Syokota fkey -= F_FN; 102642421Syokota if (fkey > kbd->kb_fkeytab_size) 1027127752Sdes return (NULL); 102842421Syokota *len = kbd->kb_fkeytab[fkey].len; 1029127752Sdes return (kbd->kb_fkeytab[fkey].str); 103042421Syokota} 103142421Syokota 103242421Syokota/* diagnostic dump */ 103342421Syokotastatic char 103442421Syokota*get_kbd_type_name(int type) 103542421Syokota{ 103642421Syokota static struct { 103742421Syokota int type; 103842421Syokota char *name; 103942421Syokota } name_table[] = { 104042421Syokota { KB_84, "AT 84" }, 104142421Syokota { KB_101, "AT 101/102" }, 104242421Syokota { KB_OTHER, "generic" }, 104342421Syokota }; 104442421Syokota int i; 104542421Syokota 104642421Syokota for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) { 104742421Syokota if (type == name_table[i].type) 1048127752Sdes return (name_table[i].name); 104942421Syokota } 1050127752Sdes return ("unknown"); 105142421Syokota} 105242421Syokota 105342421Syokotavoid 105442421Syokotagenkbd_diag(keyboard_t *kbd, int level) 105542421Syokota{ 105642421Syokota if (level > 0) { 1057127751Sdes printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x", 1058127751Sdes kbd->kb_index, kbd->kb_name, kbd->kb_unit, 1059127751Sdes get_kbd_type_name(kbd->kb_type), kbd->kb_type, 1060127751Sdes kbd->kb_config, kbd->kb_flags); 106142421Syokota if (kbd->kb_io_base > 0) 1062127751Sdes printf(", port:0x%x-0x%x", kbd->kb_io_base, 1063127751Sdes kbd->kb_io_base + kbd->kb_io_size - 1); 106442421Syokota printf("\n"); 106542421Syokota } 106642421Syokota} 106742421Syokota 106842421Syokota#define set_lockkey_state(k, s, l) \ 106942421Syokota if (!((s) & l ## DOWN)) { \ 107042421Syokota int i; \ 107142421Syokota (s) |= l ## DOWN; \ 107242421Syokota (s) ^= l ## ED; \ 107342421Syokota i = (s) & LOCK_MASK; \ 107442421Syokota (*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \ 107542421Syokota } 107642421Syokota 107742421Syokotastatic u_int 107842421Syokotasave_accent_key(keyboard_t *kbd, u_int key, int *accents) 107942421Syokota{ 108042421Syokota int i; 108142421Syokota 108242421Syokota /* make an index into the accent map */ 108342421Syokota i = key - F_ACC + 1; 108442421Syokota if ((i > kbd->kb_accentmap->n_accs) 108542421Syokota || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) { 108642421Syokota /* the index is out of range or pointing to an empty entry */ 108742421Syokota *accents = 0; 1088127752Sdes return (ERRKEY); 108942421Syokota } 109042421Syokota 1091127751Sdes /* 1092127751Sdes * If the same accent key has been hit twice, produce the accent 1093127751Sdes * char itself. 109442421Syokota */ 109542421Syokota if (i == *accents) { 109642421Syokota key = kbd->kb_accentmap->acc[i - 1].accchar; 109742421Syokota *accents = 0; 1098127752Sdes return (key); 109942421Syokota } 110042421Syokota 110142421Syokota /* remember the index and wait for the next key */ 1102127751Sdes *accents = i; 1103127752Sdes return (NOKEY); 110442421Syokota} 110542421Syokota 110642421Syokotastatic u_int 110742421Syokotamake_accent_char(keyboard_t *kbd, u_int ch, int *accents) 110842421Syokota{ 110942421Syokota struct acc_t *acc; 111042421Syokota int i; 111142421Syokota 111242421Syokota acc = &kbd->kb_accentmap->acc[*accents - 1]; 111342421Syokota *accents = 0; 111442421Syokota 1115127751Sdes /* 111642421Syokota * If the accent key is followed by the space key, 111742421Syokota * produce the accent char itself. 111842421Syokota */ 111942421Syokota if (ch == ' ') 1120127752Sdes return (acc->accchar); 112142421Syokota 112242421Syokota /* scan the accent map */ 112342421Syokota for (i = 0; i < NUM_ACCENTCHARS; ++i) { 112442421Syokota if (acc->map[i][0] == 0) /* end of table */ 112542421Syokota break; 112642421Syokota if (acc->map[i][0] == ch) 1127127752Sdes return (acc->map[i][1]); 112842421Syokota } 112942421Syokota /* this char cannot be accented... */ 1130127752Sdes return (ERRKEY); 113142421Syokota} 113242421Syokota 113342421Syokotaint 113442421Syokotagenkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate, 113542421Syokota int *accents) 113642421Syokota{ 113742421Syokota struct keyent_t *key; 113842421Syokota int state = *shiftstate; 113942421Syokota int action; 114042421Syokota int f; 114142421Syokota int i; 114242421Syokota 114354382Syokota i = keycode; 114442421Syokota f = state & (AGRS | ALKED); 114542421Syokota if ((f == AGRS1) || (f == AGRS2) || (f == ALKED)) 114654382Syokota i += ALTGR_OFFSET; 114754382Syokota key = &kbd->kb_keymap->key[i]; 114842421Syokota i = ((state & SHIFTS) ? 1 : 0) 114942421Syokota | ((state & CTLS) ? 2 : 0) 115042421Syokota | ((state & ALTS) ? 4 : 0); 115142421Syokota if (((key->flgs & FLAG_LOCK_C) && (state & CLKED)) 115242421Syokota || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) ) 115342421Syokota i ^= 1; 115442421Syokota 115542421Syokota if (up) { /* break: key released */ 115680040Syokota action = kbd->kb_lastact[keycode]; 115780040Syokota kbd->kb_lastact[keycode] = NOP; 115880040Syokota switch (action) { 115980040Syokota case LSHA: 116080040Syokota if (state & SHIFTAON) { 116180040Syokota set_lockkey_state(kbd, state, ALK); 116280040Syokota state &= ~ALKDOWN; 116380040Syokota } 116480040Syokota action = LSH; 116580040Syokota /* FALL THROUGH */ 116680040Syokota case LSH: 116780040Syokota state &= ~SHIFTS1; 116880040Syokota break; 116980040Syokota case RSHA: 117080040Syokota if (state & SHIFTAON) { 117180040Syokota set_lockkey_state(kbd, state, ALK); 117280040Syokota state &= ~ALKDOWN; 117380040Syokota } 117480040Syokota action = RSH; 117580040Syokota /* FALL THROUGH */ 117680040Syokota case RSH: 117780040Syokota state &= ~SHIFTS2; 117880040Syokota break; 117980040Syokota case LCTRA: 118080040Syokota if (state & SHIFTAON) { 118180040Syokota set_lockkey_state(kbd, state, ALK); 118280040Syokota state &= ~ALKDOWN; 118380040Syokota } 118480040Syokota action = LCTR; 118580040Syokota /* FALL THROUGH */ 118680040Syokota case LCTR: 118780040Syokota state &= ~CTLS1; 118880040Syokota break; 118980040Syokota case RCTRA: 119080040Syokota if (state & SHIFTAON) { 119180040Syokota set_lockkey_state(kbd, state, ALK); 119280040Syokota state &= ~ALKDOWN; 119380040Syokota } 119480040Syokota action = RCTR; 119580040Syokota /* FALL THROUGH */ 119680040Syokota case RCTR: 119780040Syokota state &= ~CTLS2; 119880040Syokota break; 119980040Syokota case LALTA: 120080040Syokota if (state & SHIFTAON) { 120180040Syokota set_lockkey_state(kbd, state, ALK); 120280040Syokota state &= ~ALKDOWN; 120380040Syokota } 120480040Syokota action = LALT; 120580040Syokota /* FALL THROUGH */ 120680040Syokota case LALT: 120780040Syokota state &= ~ALTS1; 120880040Syokota break; 120980040Syokota case RALTA: 121080040Syokota if (state & SHIFTAON) { 121180040Syokota set_lockkey_state(kbd, state, ALK); 121280040Syokota state &= ~ALKDOWN; 121380040Syokota } 121480040Syokota action = RALT; 121580040Syokota /* FALL THROUGH */ 121680040Syokota case RALT: 121780040Syokota state &= ~ALTS2; 121880040Syokota break; 121980040Syokota case ASH: 122080040Syokota state &= ~AGRS1; 122180040Syokota break; 122280040Syokota case META: 122380040Syokota state &= ~METAS1; 122480040Syokota break; 122580040Syokota case NLK: 122680040Syokota state &= ~NLKDOWN; 122780040Syokota break; 122880040Syokota case CLK: 122942421Syokota#ifndef PC98 123080040Syokota state &= ~CLKDOWN; 123142421Syokota#else 123280040Syokota state &= ~CLKED; 123380040Syokota i = state & LOCK_MASK; 123480040Syokota (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED, 123580040Syokota (caddr_t)&i); 123642421Syokota#endif 123780040Syokota break; 123880040Syokota case SLK: 123980040Syokota state &= ~SLKDOWN; 124080040Syokota break; 124180040Syokota case ALK: 124280040Syokota state &= ~ALKDOWN; 124380040Syokota break; 124480040Syokota case NOP: 124580040Syokota /* release events of regular keys are not reported */ 124680040Syokota *shiftstate &= ~SHIFTAON; 1247127752Sdes return (NOKEY); 124842421Syokota } 124980040Syokota *shiftstate = state & ~SHIFTAON; 125080040Syokota return (SPCLKEY | RELKEY | action); 125142421Syokota } else { /* make: key pressed */ 125280040Syokota action = key->map[i]; 125355820Syokota state &= ~SHIFTAON; 125442421Syokota if (key->spcl & (0x80 >> i)) { 125542421Syokota /* special keys */ 125680040Syokota if (kbd->kb_lastact[keycode] == NOP) 125780040Syokota kbd->kb_lastact[keycode] = action; 125880040Syokota if (kbd->kb_lastact[keycode] != action) 125980040Syokota action = NOP; 126042421Syokota switch (action) { 126142421Syokota /* LOCKING KEYS */ 126242421Syokota case NLK: 126342421Syokota set_lockkey_state(kbd, state, NLK); 126442421Syokota break; 126542421Syokota case CLK: 126642421Syokota#ifndef PC98 126742421Syokota set_lockkey_state(kbd, state, CLK); 126842421Syokota#else 126942421Syokota state |= CLKED; 127042421Syokota i = state & LOCK_MASK; 127142421Syokota (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED, 127242421Syokota (caddr_t)&i); 127342421Syokota#endif 127442421Syokota break; 127542421Syokota case SLK: 127642421Syokota set_lockkey_state(kbd, state, SLK); 127742421Syokota break; 127842421Syokota case ALK: 127942421Syokota set_lockkey_state(kbd, state, ALK); 128042421Syokota break; 128142421Syokota /* NON-LOCKING KEYS */ 128242421Syokota case SPSC: case RBT: case SUSP: case STBY: 128354382Syokota case DBG: case NEXT: case PREV: case PNC: 128465759Sdwmalone case HALT: case PDWN: 128542421Syokota *accents = 0; 128642421Syokota break; 128742421Syokota case BTAB: 128842421Syokota *accents = 0; 128942421Syokota action |= BKEY; 129042421Syokota break; 129154382Syokota case LSHA: 129255820Syokota state |= SHIFTAON; 129354382Syokota action = LSH; 129454382Syokota /* FALL THROUGH */ 129542421Syokota case LSH: 129642421Syokota state |= SHIFTS1; 129742421Syokota break; 129854382Syokota case RSHA: 129955820Syokota state |= SHIFTAON; 130054382Syokota action = RSH; 130154382Syokota /* FALL THROUGH */ 130242421Syokota case RSH: 130342421Syokota state |= SHIFTS2; 130442421Syokota break; 130554382Syokota case LCTRA: 130655820Syokota state |= SHIFTAON; 130754382Syokota action = LCTR; 130854382Syokota /* FALL THROUGH */ 130942421Syokota case LCTR: 131042421Syokota state |= CTLS1; 131142421Syokota break; 131254382Syokota case RCTRA: 131355820Syokota state |= SHIFTAON; 131454382Syokota action = RCTR; 131554382Syokota /* FALL THROUGH */ 131642421Syokota case RCTR: 131742421Syokota state |= CTLS2; 131842421Syokota break; 131954382Syokota case LALTA: 132055820Syokota state |= SHIFTAON; 132154382Syokota action = LALT; 132254382Syokota /* FALL THROUGH */ 132342421Syokota case LALT: 132442421Syokota state |= ALTS1; 132542421Syokota break; 132654382Syokota case RALTA: 132755820Syokota state |= SHIFTAON; 132854382Syokota action = RALT; 132954382Syokota /* FALL THROUGH */ 133042421Syokota case RALT: 133142421Syokota state |= ALTS2; 133242421Syokota break; 133342421Syokota case ASH: 133442421Syokota state |= AGRS1; 133542421Syokota break; 133642421Syokota case META: 133742421Syokota state |= METAS1; 133842421Syokota break; 133980040Syokota case NOP: 134080040Syokota *shiftstate = state; 1341127752Sdes return (NOKEY); 134242421Syokota default: 134342421Syokota /* is this an accent (dead) key? */ 134455820Syokota *shiftstate = state; 134542421Syokota if (action >= F_ACC && action <= L_ACC) { 134642421Syokota action = save_accent_key(kbd, action, 134742421Syokota accents); 134842421Syokota switch (action) { 134942421Syokota case NOKEY: 135042421Syokota case ERRKEY: 1351127752Sdes return (action); 135242421Syokota default: 135342421Syokota if (state & METAS) 135442421Syokota return (action | MKEY); 135542421Syokota else 1356127752Sdes return (action); 135742421Syokota } 135842421Syokota /* NOT REACHED */ 135942421Syokota } 136042421Syokota /* other special keys */ 136142421Syokota if (*accents > 0) { 136242421Syokota *accents = 0; 1363127752Sdes return (ERRKEY); 136442421Syokota } 136542421Syokota if (action >= F_FN && action <= L_FN) 136642421Syokota action |= FKEY; 136742421Syokota /* XXX: return fkey string for the FKEY? */ 136855820Syokota return (SPCLKEY | action); 136942421Syokota } 137042421Syokota *shiftstate = state; 137142421Syokota return (SPCLKEY | action); 137242421Syokota } else { 137342421Syokota /* regular keys */ 137480040Syokota kbd->kb_lastact[keycode] = NOP; 137555820Syokota *shiftstate = state; 137642421Syokota if (*accents > 0) { 137742421Syokota /* make an accented char */ 137842421Syokota action = make_accent_char(kbd, action, accents); 137942421Syokota if (action == ERRKEY) 1380127752Sdes return (action); 138142421Syokota } 138242421Syokota if (state & METAS) 138342421Syokota action |= MKEY; 1384127752Sdes return (action); 138542421Syokota } 138642421Syokota } 138742421Syokota /* NOT REACHED */ 138842421Syokota} 1389