kbd.c revision 112050
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 * 2650477Speter * $FreeBSD: head/sys/dev/kbd/kbd.c 112050 2003-03-09 22:49:48Z dwmalone $ 2742421Syokota */ 2842421Syokota 2942421Syokota#include "opt_kbd.h" 3042421Syokota 3142421Syokota#include <sys/param.h> 3242421Syokota#include <sys/systm.h> 3342421Syokota#include <sys/kernel.h> 3442421Syokota#include <sys/malloc.h> 3542421Syokota#include <sys/conf.h> 3642421Syokota#include <sys/tty.h> 3742421Syokota#include <sys/poll.h> 38112050Sdwmalone#include <sys/proc.h> 39112050Sdwmalone#include <sys/sysctl.h> 4042421Syokota#include <sys/vnode.h> 4142421Syokota#include <sys/uio.h> 4242421Syokota 4366834Sphk#include <sys/kbio.h> 4442421Syokota 4542421Syokota#include <dev/kbd/kbdreg.h> 4642421Syokota 4750154Syokota#define KBD_INDEX(dev) minor(dev) 4850154Syokota 4950154Syokotatypedef struct genkbd_softc { 5050154Syokota int gkb_flags; /* flag/status bits */ 5150154Syokota#define KB_ASLEEP (1 << 0) 5250154Syokota struct clist gkb_q; /* input queue */ 5350154Syokota struct selinfo gkb_rsel; 5450154Syokota} genkbd_softc_t; 5550154Syokota 5660938Sjakestatic SLIST_HEAD(, keyboard_driver) keyboard_drivers = 5754545Syokota SLIST_HEAD_INITIALIZER(keyboard_drivers); 5854545Syokota 5978161SpeterSET_DECLARE(kbddriver_set, const keyboard_driver_t); 6078161Speter 6142421Syokota/* local arrays */ 6242421Syokota 6342421Syokota/* 6442421Syokota * We need at least one entry each in order to initialize a keyboard 6542421Syokota * for the kernel console. The arrays will be increased dynamically 6642421Syokota * when necessary. 6742421Syokota */ 6842564Syokota 6942564Syokotastatic int keyboards = 1; 7042421Syokotastatic keyboard_t *kbd_ini; 7142564Syokotastatic keyboard_t **keyboard = &kbd_ini; 7242421Syokotastatic keyboard_switch_t *kbdsw_ini; 7342421Syokota keyboard_switch_t **kbdsw = &kbdsw_ini; 7442421Syokota 75112050Sdwmalonestatic int keymap_restrict_change; 76112050SdwmaloneSYSCTL_NODE(_hw, OID_AUTO, kbd, CTLFLAG_RD, 0, "kbd"); 77112050SdwmaloneSYSCTL_INT(_hw_kbd, OID_AUTO, keymap_restrict_change, CTLFLAG_RW, 78112050Sdwmalone &keymap_restrict_change, 0, "restrict ability to change keymap"); 79112050Sdwmalone 8042421Syokota#define ARRAY_DELTA 4 8142421Syokota 8244628Syokotastatic int 8342421Syokotakbd_realloc_array(void) 8442421Syokota{ 8542421Syokota keyboard_t **new_kbd; 8642421Syokota keyboard_switch_t **new_kbdsw; 8742421Syokota int newsize; 8842421Syokota int s; 8942421Syokota 9042421Syokota s = spltty(); 9142421Syokota newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA; 9269781Sdwmalone new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT|M_ZERO); 9344628Syokota if (new_kbd == NULL) { 9444628Syokota splx(s); 9544628Syokota return ENOMEM; 9644628Syokota } 9769781Sdwmalone new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF, 9869781Sdwmalone M_NOWAIT|M_ZERO); 9944628Syokota if (new_kbdsw == NULL) { 10044628Syokota free(new_kbd, M_DEVBUF); 10144628Syokota splx(s); 10244628Syokota return ENOMEM; 10344628Syokota } 10442421Syokota bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards); 10542421Syokota bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards); 10642421Syokota if (keyboards > 1) { 10742421Syokota free(keyboard, M_DEVBUF); 10842421Syokota free(kbdsw, M_DEVBUF); 10942421Syokota } 11042421Syokota keyboard = new_kbd; 11142421Syokota kbdsw = new_kbdsw; 11242421Syokota keyboards = newsize; 11342421Syokota splx(s); 11442421Syokota 11542421Syokota if (bootverbose) 11642421Syokota printf("kbd: new array size %d\n", keyboards); 11744628Syokota 11844628Syokota return 0; 11942421Syokota} 12042421Syokota 12142421Syokota/* 12242421Syokota * Low-level keyboard driver functions 12342421Syokota * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard 12442421Syokota * driver, call these functions to initialize the keyboard_t structure 12542421Syokota * and register it to the virtual keyboard driver `kbd'. 12642421Syokota */ 12742421Syokota 12842421Syokota/* initialize the keyboard_t structure */ 12942421Syokotavoid 13042421Syokotakbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config, 13142421Syokota int port, int port_size) 13242421Syokota{ 13342421Syokota kbd->kb_flags = KB_NO_DEVICE; /* device has not been found */ 13442421Syokota kbd->kb_name = name; 13542421Syokota kbd->kb_type = type; 13642421Syokota kbd->kb_unit = unit; 13744628Syokota kbd->kb_config = config & ~KB_CONF_PROBE_ONLY; 13842421Syokota kbd->kb_led = 0; /* unknown */ 13942421Syokota kbd->kb_io_base = port; 14042421Syokota kbd->kb_io_size = port_size; 14142421Syokota kbd->kb_data = NULL; 14242421Syokota kbd->kb_keymap = NULL; 14342421Syokota kbd->kb_accentmap = NULL; 14442421Syokota kbd->kb_fkeytab = NULL; 14542421Syokota kbd->kb_fkeytab_size = 0; 14644628Syokota kbd->kb_delay1 = KB_DELAY1; /* these values are advisory only */ 14744628Syokota kbd->kb_delay2 = KB_DELAY2; 14854382Syokota kbd->kb_count = 0L; 14980040Syokota bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact)); 15042421Syokota} 15142421Syokota 15242421Syokotavoid 15342421Syokotakbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap, 15442421Syokota fkeytab_t *fkeymap, int fkeymap_size) 15542421Syokota{ 15642421Syokota kbd->kb_keymap = keymap; 15742421Syokota kbd->kb_accentmap = accmap; 15842421Syokota kbd->kb_fkeytab = fkeymap; 15942421Syokota kbd->kb_fkeytab_size = fkeymap_size; 16042421Syokota} 16142421Syokota 16254545Syokota/* declare a new keyboard driver */ 16354545Syokotaint 16454545Syokotakbd_add_driver(keyboard_driver_t *driver) 16554545Syokota{ 16654545Syokota if (SLIST_NEXT(driver, link)) 16754545Syokota return EINVAL; 16854545Syokota SLIST_INSERT_HEAD(&keyboard_drivers, driver, link); 16954545Syokota return 0; 17054545Syokota} 17154545Syokota 17254545Syokotaint 17354545Syokotakbd_delete_driver(keyboard_driver_t *driver) 17454545Syokota{ 17560938Sjake SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link); 17654545Syokota SLIST_NEXT(driver, link) = NULL; 17754545Syokota return 0; 17854545Syokota} 17954545Syokota 18042421Syokota/* register a keyboard and associate it with a function table */ 18142421Syokotaint 18242421Syokotakbd_register(keyboard_t *kbd) 18342421Syokota{ 18447295Syokota const keyboard_driver_t **list; 18547295Syokota const keyboard_driver_t *p; 18642421Syokota int index; 18742421Syokota 18842421Syokota for (index = 0; index < keyboards; ++index) { 18942421Syokota if (keyboard[index] == NULL) 19042421Syokota break; 19142421Syokota } 19244628Syokota if (index >= keyboards) { 19344628Syokota if (kbd_realloc_array()) 19444628Syokota return -1; 19544628Syokota } 19642421Syokota 19742421Syokota kbd->kb_index = index; 19842421Syokota KBD_UNBUSY(kbd); 19942421Syokota KBD_VALID(kbd); 20042421Syokota kbd->kb_active = 0; /* disabled until someone calls kbd_enable() */ 20142421Syokota kbd->kb_token = NULL; 20242421Syokota kbd->kb_callback.kc_func = NULL; 20342421Syokota kbd->kb_callback.kc_arg = NULL; 20442421Syokota 20554545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 20654545Syokota if (strcmp(p->name, kbd->kb_name) == 0) { 20754545Syokota keyboard[index] = kbd; 20854545Syokota kbdsw[index] = p->kbdsw; 20954545Syokota return index; 21054545Syokota } 21154545Syokota } 21278161Speter SET_FOREACH(list, kbddriver_set) { 21378161Speter p = *list; 21442421Syokota if (strcmp(p->name, kbd->kb_name) == 0) { 21542421Syokota keyboard[index] = kbd; 21642421Syokota kbdsw[index] = p->kbdsw; 21742421Syokota return index; 21842421Syokota } 21942421Syokota } 22042421Syokota 22142421Syokota return -1; 22242421Syokota} 22342421Syokota 22442421Syokotaint 22542421Syokotakbd_unregister(keyboard_t *kbd) 22642421Syokota{ 22742421Syokota int error; 22842421Syokota int s; 22942421Syokota 23042421Syokota if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards)) 23142421Syokota return ENOENT; 23242421Syokota if (keyboard[kbd->kb_index] != kbd) 23342421Syokota return ENOENT; 23442421Syokota 23542421Syokota s = spltty(); 23642421Syokota if (KBD_IS_BUSY(kbd)) { 23742421Syokota error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING, 23842421Syokota kbd->kb_callback.kc_arg); 23942421Syokota if (error) { 24042421Syokota splx(s); 24142421Syokota return error; 24242421Syokota } 24342421Syokota if (KBD_IS_BUSY(kbd)) { 24442421Syokota splx(s); 24542421Syokota return EBUSY; 24642421Syokota } 24742421Syokota } 24842421Syokota KBD_INVALID(kbd); 24942421Syokota keyboard[kbd->kb_index] = NULL; 25042421Syokota kbdsw[kbd->kb_index] = NULL; 25142421Syokota 25242421Syokota splx(s); 25342421Syokota return 0; 25442421Syokota} 25542421Syokota 25642421Syokota/* find a funciton table by the driver name */ 25742421Syokotakeyboard_switch_t 25842421Syokota*kbd_get_switch(char *driver) 25942421Syokota{ 26047295Syokota const keyboard_driver_t **list; 26147295Syokota const keyboard_driver_t *p; 26242421Syokota 26354545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 26454545Syokota if (strcmp(p->name, driver) == 0) 26554545Syokota return p->kbdsw; 26654545Syokota } 26778161Speter SET_FOREACH(list, kbddriver_set) { 26878161Speter p = *list; 26942421Syokota if (strcmp(p->name, driver) == 0) 27042421Syokota return p->kbdsw; 27142421Syokota } 27242421Syokota 27342421Syokota return NULL; 27442421Syokota} 27542421Syokota 27642421Syokota/* 27742421Syokota * Keyboard client functions 27842421Syokota * Keyboard clients, such as the console driver `syscons' and the keyboard 27942421Syokota * cdev driver, use these functions to claim and release a keyboard for 28042421Syokota * exclusive use. 28142421Syokota */ 28242421Syokota 28342421Syokota/* find the keyboard specified by a driver name and a unit number */ 28442421Syokotaint 28542421Syokotakbd_find_keyboard(char *driver, int unit) 28642421Syokota{ 28742421Syokota int i; 28842421Syokota 28942421Syokota for (i = 0; i < keyboards; ++i) { 29042421Syokota if (keyboard[i] == NULL) 29142421Syokota continue; 29242421Syokota if (!KBD_IS_VALID(keyboard[i])) 29342421Syokota continue; 29442421Syokota if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver)) 29542421Syokota continue; 29642421Syokota if ((unit != -1) && (keyboard[i]->kb_unit != unit)) 29742421Syokota continue; 29842421Syokota return i; 29942421Syokota } 30042421Syokota return -1; 30142421Syokota} 30242421Syokota 30342421Syokota/* allocate a keyboard */ 30442421Syokotaint 30542421Syokotakbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func, 30642421Syokota void *arg) 30742421Syokota{ 30842421Syokota int index; 30942421Syokota int s; 31042421Syokota 31142421Syokota if (func == NULL) 31242421Syokota return -1; 31342421Syokota 31442421Syokota s = spltty(); 31542421Syokota index = kbd_find_keyboard(driver, unit); 31642421Syokota if (index >= 0) { 31742421Syokota if (KBD_IS_BUSY(keyboard[index])) { 31842421Syokota splx(s); 31942421Syokota return -1; 32042421Syokota } 32142421Syokota keyboard[index]->kb_token = id; 32242421Syokota KBD_BUSY(keyboard[index]); 32342421Syokota keyboard[index]->kb_callback.kc_func = func; 32442421Syokota keyboard[index]->kb_callback.kc_arg = arg; 32542421Syokota (*kbdsw[index]->clear_state)(keyboard[index]); 32642421Syokota } 32742421Syokota splx(s); 32842421Syokota return index; 32942421Syokota} 33042421Syokota 33142421Syokotaint 33242421Syokotakbd_release(keyboard_t *kbd, void *id) 33342421Syokota{ 33442421Syokota int error; 33542421Syokota int s; 33642421Syokota 33742421Syokota s = spltty(); 33842421Syokota if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 33942421Syokota error = EINVAL; 34042421Syokota } else if (kbd->kb_token != id) { 34142421Syokota error = EPERM; 34242421Syokota } else { 34342421Syokota kbd->kb_token = NULL; 34442421Syokota KBD_UNBUSY(kbd); 34542421Syokota kbd->kb_callback.kc_func = NULL; 34642421Syokota kbd->kb_callback.kc_arg = NULL; 34742421Syokota (*kbdsw[kbd->kb_index]->clear_state)(kbd); 34842421Syokota error = 0; 34942421Syokota } 35042421Syokota splx(s); 35142421Syokota return error; 35242421Syokota} 35342421Syokota 35442421Syokotaint 35542421Syokotakbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func, 35642421Syokota void *arg) 35742421Syokota{ 35842421Syokota int error; 35942421Syokota int s; 36042421Syokota 36142421Syokota s = spltty(); 36242421Syokota if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 36342421Syokota error = EINVAL; 36442421Syokota } else if (kbd->kb_token != id) { 36542421Syokota error = EPERM; 36642421Syokota } else if (func == NULL) { 36742421Syokota error = EINVAL; 36842421Syokota } else { 36942421Syokota kbd->kb_callback.kc_func = func; 37042421Syokota kbd->kb_callback.kc_arg = arg; 37142421Syokota error = 0; 37242421Syokota } 37342421Syokota splx(s); 37442421Syokota return error; 37542421Syokota} 37642421Syokota 37742421Syokota/* get a keyboard structure */ 37842421Syokotakeyboard_t 37942421Syokota*kbd_get_keyboard(int index) 38042421Syokota{ 38142421Syokota if ((index < 0) || (index >= keyboards)) 38242421Syokota return NULL; 38350154Syokota if (keyboard[index] == NULL) 38450154Syokota return NULL; 38542421Syokota if (!KBD_IS_VALID(keyboard[index])) 38642421Syokota return NULL; 38742421Syokota return keyboard[index]; 38842421Syokota} 38942421Syokota 39042421Syokota/* 39142421Syokota * The back door for the console driver; configure keyboards 39242421Syokota * This function is for the kernel console to initialize keyboards 39342421Syokota * at very early stage. 39442421Syokota */ 39542421Syokota 39642421Syokotaint 39742421Syokotakbd_configure(int flags) 39842421Syokota{ 39947295Syokota const keyboard_driver_t **list; 40047295Syokota const keyboard_driver_t *p; 40142421Syokota 40254545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 40354545Syokota if (p->configure != NULL) 40454545Syokota (*p->configure)(flags); 40554545Syokota } 40678161Speter SET_FOREACH(list, kbddriver_set) { 40778161Speter p = *list; 40842421Syokota if (p->configure != NULL) 40942421Syokota (*p->configure)(flags); 41042421Syokota } 41142421Syokota 41242421Syokota return 0; 41342421Syokota} 41442421Syokota 41542421Syokota#ifdef KBD_INSTALL_CDEV 41642421Syokota 41742421Syokota/* 41842421Syokota * Virtual keyboard cdev driver functions 41942421Syokota * The virtual keyboard driver dispatches driver functions to 42042421Syokota * appropriate subdrivers. 42142421Syokota */ 42242421Syokota 42342421Syokota#define KBD_UNIT(dev) minor(dev) 42442421Syokota 42550154Syokotastatic d_open_t genkbdopen; 42650154Syokotastatic d_close_t genkbdclose; 42750154Syokotastatic d_read_t genkbdread; 42850154Syokotastatic d_write_t genkbdwrite; 42950154Syokotastatic d_ioctl_t genkbdioctl; 43050154Syokotastatic d_poll_t genkbdpoll; 43142421Syokota 43242421Syokota#define CDEV_MAJOR 112 43342421Syokota 43442421Syokotastatic struct cdevsw kbd_cdevsw = { 435111815Sphk .d_open = genkbdopen, 436111815Sphk .d_close = genkbdclose, 437111815Sphk .d_read = genkbdread, 438111815Sphk .d_write = genkbdwrite, 439111815Sphk .d_ioctl = genkbdioctl, 440111815Sphk .d_poll = genkbdpoll, 441111815Sphk .d_name = "kbd", 442111815Sphk .d_maj = CDEV_MAJOR, 44342421Syokota}; 44442421Syokota 44542421Syokotaint 44650154Syokotakbd_attach(keyboard_t *kbd) 44742421Syokota{ 44850154Syokota dev_t dev; 44942421Syokota 45042421Syokota if (kbd->kb_index >= keyboards) 45142421Syokota return EINVAL; 45242421Syokota if (keyboard[kbd->kb_index] != kbd) 45342421Syokota return EINVAL; 45442421Syokota 45550154Syokota dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 0600, 45650154Syokota "kbd%r", kbd->kb_index); 45750154Syokota if (dev->si_drv1 == NULL) 45850154Syokota dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF, 459111119Simp M_WAITOK); 46050154Syokota bzero(dev->si_drv1, sizeof(genkbd_softc_t)); 46142421Syokota 46242421Syokota printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit); 46342421Syokota return 0; 46442421Syokota} 46542421Syokota 46642421Syokotaint 46750154Syokotakbd_detach(keyboard_t *kbd) 46842421Syokota{ 46954545Syokota dev_t dev; 47054545Syokota 47142421Syokota if (kbd->kb_index >= keyboards) 47242421Syokota return EINVAL; 47342421Syokota if (keyboard[kbd->kb_index] != kbd) 47442421Syokota return EINVAL; 47542421Syokota 47654545Syokota dev = makedev(kbd_cdevsw.d_maj, kbd->kb_index); 47754545Syokota if (dev->si_drv1) 47854545Syokota free(dev->si_drv1, M_DEVBUF); 47954545Syokota destroy_dev(dev); 48054545Syokota 48142421Syokota return 0; 48242421Syokota} 48342421Syokota 48442421Syokota/* 48542421Syokota * Generic keyboard cdev driver functions 48642421Syokota * Keyboard subdrivers may call these functions to implement common 48742421Syokota * driver functions. 48842421Syokota */ 48942421Syokota 49042421Syokota#define KB_QSIZE 512 49142421Syokota#define KB_BUFSIZE 64 49242421Syokota 49342421Syokotastatic kbd_callback_func_t genkbd_event; 49442421Syokota 49550154Syokotastatic int 49683366Sjuliangenkbdopen(dev_t dev, int mode, int flag, struct thread *td) 49742421Syokota{ 49850154Syokota keyboard_t *kbd; 49950154Syokota genkbd_softc_t *sc; 50042421Syokota int s; 50142421Syokota int i; 50242421Syokota 50342421Syokota s = spltty(); 50450154Syokota sc = dev->si_drv1; 50550154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 50650154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 50742421Syokota splx(s); 50842421Syokota return ENXIO; 50942421Syokota } 51042421Syokota i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc, 51142421Syokota genkbd_event, (void *)sc); 51242421Syokota if (i < 0) { 51342421Syokota splx(s); 51442421Syokota return EBUSY; 51542421Syokota } 51642421Syokota /* assert(i == kbd->kb_index) */ 51742421Syokota /* assert(kbd == kbd_get_keyboard(i)) */ 51842421Syokota 51942421Syokota /* 52042421Syokota * NOTE: even when we have successfully claimed a keyboard, 52142421Syokota * the device may still be missing (!KBD_HAS_DEVICE(kbd)). 52242421Syokota */ 52342421Syokota 52442421Syokota#if 0 52542421Syokota bzero(&sc->gkb_q, sizeof(sc->gkb_q)); 52642421Syokota#endif 52742421Syokota clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */ 52842421Syokota splx(s); 52942421Syokota 53042421Syokota return 0; 53142421Syokota} 53242421Syokota 53350154Syokotastatic int 53483366Sjuliangenkbdclose(dev_t dev, int mode, int flag, struct thread *td) 53542421Syokota{ 53650154Syokota keyboard_t *kbd; 53750154Syokota genkbd_softc_t *sc; 53842421Syokota int s; 53942421Syokota 54042421Syokota /* 54142421Syokota * NOTE: the device may have already become invalid. 54250154Syokota * kbd == NULL || !KBD_IS_VALID(kbd) 54342421Syokota */ 54442421Syokota s = spltty(); 54550154Syokota sc = dev->si_drv1; 54650154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 54750154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 54850154Syokota /* XXX: we shall be forgiving and don't report error... */ 54950154Syokota } else { 55050154Syokota kbd_release(kbd, (void *)sc); 55142421Syokota#if 0 55250154Syokota clist_free_cblocks(&sc->gkb_q); 55342421Syokota#endif 55450154Syokota } 55542421Syokota splx(s); 55642421Syokota return 0; 55742421Syokota} 55842421Syokota 55950154Syokotastatic int 56050154Syokotagenkbdread(dev_t dev, struct uio *uio, int flag) 56142421Syokota{ 56250154Syokota keyboard_t *kbd; 56350154Syokota genkbd_softc_t *sc; 56442421Syokota u_char buffer[KB_BUFSIZE]; 56542421Syokota int len; 56642421Syokota int error; 56742421Syokota int s; 56842421Syokota 56942421Syokota /* wait for input */ 57042421Syokota s = spltty(); 57150154Syokota sc = dev->si_drv1; 57250154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 57350154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 57450154Syokota splx(s); 57550154Syokota return ENXIO; 57650154Syokota } 57742421Syokota while (sc->gkb_q.c_cc == 0) { 57842421Syokota if (flag & IO_NDELAY) { 57942421Syokota splx(s); 58042421Syokota return EWOULDBLOCK; 58142421Syokota } 58242421Syokota sc->gkb_flags |= KB_ASLEEP; 583111748Sdes error = tsleep(sc, PZERO | PCATCH, "kbdrea", 0); 58450154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 58550154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) { 58650154Syokota splx(s); 58750154Syokota return ENXIO; /* our keyboard has gone... */ 58850154Syokota } 58942421Syokota if (error) { 59042421Syokota sc->gkb_flags &= ~KB_ASLEEP; 59142421Syokota splx(s); 59242421Syokota return error; 59342421Syokota } 59442421Syokota } 59542421Syokota splx(s); 59642421Syokota 59742421Syokota /* copy as much input as possible */ 59842421Syokota error = 0; 59942421Syokota while (uio->uio_resid > 0) { 60042421Syokota len = imin(uio->uio_resid, sizeof(buffer)); 60142421Syokota len = q_to_b(&sc->gkb_q, buffer, len); 60242421Syokota if (len <= 0) 60342421Syokota break; 60442421Syokota error = uiomove(buffer, len, uio); 60542421Syokota if (error) 60642421Syokota break; 60742421Syokota } 60842421Syokota 60942421Syokota return error; 61042421Syokota} 61142421Syokota 61250154Syokotastatic int 61350154Syokotagenkbdwrite(dev_t dev, struct uio *uio, int flag) 61442421Syokota{ 61550154Syokota keyboard_t *kbd; 61650154Syokota 61750154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 61850154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) 61942421Syokota return ENXIO; 62042421Syokota return ENODEV; 62142421Syokota} 62242421Syokota 62350154Syokotastatic int 62483366Sjuliangenkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 62542421Syokota{ 62650154Syokota keyboard_t *kbd; 62742421Syokota int error; 62842421Syokota 62950154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 63050154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) 63142421Syokota return ENXIO; 63242421Syokota error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg); 63342421Syokota if (error == ENOIOCTL) 63442421Syokota error = ENODEV; 63542421Syokota return error; 63642421Syokota} 63742421Syokota 63850154Syokotastatic int 63983366Sjuliangenkbdpoll(dev_t dev, int events, struct thread *td) 64042421Syokota{ 64150154Syokota keyboard_t *kbd; 64250154Syokota genkbd_softc_t *sc; 64342421Syokota int revents; 64442421Syokota int s; 64542421Syokota 64642421Syokota revents = 0; 64742421Syokota s = spltty(); 64850154Syokota sc = dev->si_drv1; 64950154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 65050154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 65150154Syokota revents = POLLHUP; /* the keyboard has gone */ 65250154Syokota } else if (events & (POLLIN | POLLRDNORM)) { 65350154Syokota if (sc->gkb_q.c_cc > 0) 65450154Syokota revents = events & (POLLIN | POLLRDNORM); 65542421Syokota else 65683366Sjulian selrecord(td, &sc->gkb_rsel); 65742421Syokota } 65842421Syokota splx(s); 65942421Syokota return revents; 66042421Syokota} 66142421Syokota 66242421Syokotastatic int 66342421Syokotagenkbd_event(keyboard_t *kbd, int event, void *arg) 66442421Syokota{ 66542421Syokota genkbd_softc_t *sc; 66642421Syokota size_t len; 66742421Syokota u_char *cp; 66842421Syokota int mode; 66942421Syokota int c; 67042421Syokota 67142421Syokota /* assert(KBD_IS_VALID(kbd)) */ 67242421Syokota sc = (genkbd_softc_t *)arg; 67342421Syokota 67442421Syokota switch (event) { 67542421Syokota case KBDIO_KEYINPUT: 67642421Syokota break; 67742421Syokota case KBDIO_UNLOADING: 67842421Syokota /* the keyboard is going... */ 67942421Syokota kbd_release(kbd, (void *)sc); 68050154Syokota if (sc->gkb_flags & KB_ASLEEP) { 68150154Syokota sc->gkb_flags &= ~KB_ASLEEP; 682111748Sdes wakeup(sc); 68350154Syokota } 68450154Syokota selwakeup(&sc->gkb_rsel); 68542421Syokota return 0; 68642421Syokota default: 68742421Syokota return EINVAL; 68842421Syokota } 68942421Syokota 69042421Syokota /* obtain the current key input mode */ 69142421Syokota if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode)) 69242421Syokota mode = K_XLATE; 69342421Syokota 69442421Syokota /* read all pending input */ 69542421Syokota while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) { 69642421Syokota c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE); 69742421Syokota if (c == NOKEY) 69842421Syokota continue; 69942421Syokota if (c == ERRKEY) /* XXX: ring bell? */ 70042421Syokota continue; 70142421Syokota if (!KBD_IS_BUSY(kbd)) 70242421Syokota /* the device is not open, discard the input */ 70342421Syokota continue; 70442421Syokota 70542421Syokota /* store the byte as is for K_RAW and K_CODE modes */ 70642421Syokota if (mode != K_XLATE) { 70742421Syokota putc(KEYCHAR(c), &sc->gkb_q); 70842421Syokota continue; 70942421Syokota } 71042421Syokota 71142421Syokota /* K_XLATE */ 71242421Syokota if (c & RELKEY) /* key release is ignored */ 71342421Syokota continue; 71442421Syokota 71542421Syokota /* process special keys; most of them are just ignored... */ 71642421Syokota if (c & SPCLKEY) { 71742421Syokota switch (KEYCHAR(c)) { 71854382Syokota default: 71942421Syokota /* ignore them... */ 72042421Syokota continue; 72142421Syokota case BTAB: /* a backtab: ESC [ Z */ 72242421Syokota putc(0x1b, &sc->gkb_q); 72342421Syokota putc('[', &sc->gkb_q); 72442421Syokota putc('Z', &sc->gkb_q); 72542421Syokota continue; 72642421Syokota } 72742421Syokota } 72842421Syokota 72942421Syokota /* normal chars, normal chars with the META, function keys */ 73042421Syokota switch (KEYFLAGS(c)) { 73142421Syokota case 0: /* a normal char */ 73242421Syokota putc(KEYCHAR(c), &sc->gkb_q); 73342421Syokota break; 73442421Syokota case MKEY: /* the META flag: prepend ESC */ 73542421Syokota putc(0x1b, &sc->gkb_q); 73642421Syokota putc(KEYCHAR(c), &sc->gkb_q); 73742421Syokota break; 73842421Syokota case FKEY | SPCLKEY: /* a function key, return string */ 73942421Syokota cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd, 74042421Syokota KEYCHAR(c), &len); 74142421Syokota if (cp != NULL) { 74242421Syokota while (len-- > 0) 74342421Syokota putc(*cp++, &sc->gkb_q); 74442421Syokota } 74542421Syokota break; 74642421Syokota } 74742421Syokota } 74842421Syokota 74942421Syokota /* wake up sleeping/polling processes */ 75042421Syokota if (sc->gkb_q.c_cc > 0) { 75142421Syokota if (sc->gkb_flags & KB_ASLEEP) { 75242421Syokota sc->gkb_flags &= ~KB_ASLEEP; 753111748Sdes wakeup(sc); 75442421Syokota } 75542421Syokota selwakeup(&sc->gkb_rsel); 75642421Syokota } 75742421Syokota 75842421Syokota return 0; 75942421Syokota} 76042421Syokota 76142421Syokota#endif /* KBD_INSTALL_CDEV */ 76242421Syokota 76342421Syokota/* 76442421Syokota * Generic low-level keyboard functions 76542421Syokota * The low-level functions in the keyboard subdriver may use these 76642421Syokota * functions. 76742421Syokota */ 76842421Syokota 769112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 770112050Sdwmalonestatic int key_change_ok(struct keyent_t *, struct keyent_t *, struct thread *); 771112050Sdwmalonestatic int keymap_change_ok(keymap_t *, keymap_t *, struct thread *); 772112050Sdwmalonestatic int accent_change_ok(accentmap_t *, accentmap_t *, struct thread *); 773112050Sdwmalonestatic int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct thread *); 774112050Sdwmalone#endif 775112050Sdwmalone 77642421Syokotaint 77742421Syokotagenkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 77842421Syokota{ 77942421Syokota keyarg_t *keyp; 78042421Syokota fkeyarg_t *fkeyp; 78142421Syokota int s; 78242421Syokota int i; 783112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 784112050Sdwmalone int error; 785112050Sdwmalone#endif 78642421Syokota 78742421Syokota s = spltty(); 78842421Syokota switch (cmd) { 78942421Syokota 79042421Syokota case KDGKBINFO: /* get keyboard information */ 79142421Syokota ((keyboard_info_t *)arg)->kb_index = kbd->kb_index; 79242421Syokota i = imin(strlen(kbd->kb_name) + 1, 79342421Syokota sizeof(((keyboard_info_t *)arg)->kb_name)); 79442421Syokota bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i); 79542421Syokota ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit; 79642421Syokota ((keyboard_info_t *)arg)->kb_type = kbd->kb_type; 79742421Syokota ((keyboard_info_t *)arg)->kb_config = kbd->kb_config; 79842421Syokota ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags; 79942421Syokota break; 80042421Syokota 80142421Syokota case KDGKBTYPE: /* get keyboard type */ 80242421Syokota *(int *)arg = kbd->kb_type; 80342421Syokota break; 80442421Syokota 80554543Syokota case KDGETREPEAT: /* get keyboard repeat rate */ 80654543Syokota ((int *)arg)[0] = kbd->kb_delay1; 80754543Syokota ((int *)arg)[1] = kbd->kb_delay2; 80854543Syokota break; 80954543Syokota 81042421Syokota case GIO_KEYMAP: /* get keyboard translation table */ 81142421Syokota bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap)); 81242421Syokota break; 81342421Syokota case PIO_KEYMAP: /* set keyboard translation table */ 81444628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 815112050Sdwmalone error = keymap_change_ok(kbd->kb_keymap, (keymap_t *)arg, 816112050Sdwmalone curthread); 817112050Sdwmalone if (error != 0) { 818112050Sdwmalone splx(s); 819112050Sdwmalone return error; 820112050Sdwmalone } 82142421Syokota bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 82242421Syokota bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap)); 82342421Syokota break; 82444628Syokota#else 82544628Syokota splx(s); 82644628Syokota return ENODEV; 82744628Syokota#endif 82842421Syokota 82942421Syokota case GIO_KEYMAPENT: /* get keyboard translation table entry */ 83042421Syokota keyp = (keyarg_t *)arg; 83142421Syokota if (keyp->keynum >= sizeof(kbd->kb_keymap->key) 83242421Syokota /sizeof(kbd->kb_keymap->key[0])) { 83342421Syokota splx(s); 83442421Syokota return EINVAL; 83542421Syokota } 83642573Syokota bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key, 83742421Syokota sizeof(keyp->key)); 83842421Syokota break; 83942421Syokota case PIO_KEYMAPENT: /* set keyboard translation table entry */ 84044628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 84142421Syokota keyp = (keyarg_t *)arg; 84242421Syokota if (keyp->keynum >= sizeof(kbd->kb_keymap->key) 84342421Syokota /sizeof(kbd->kb_keymap->key[0])) { 84442421Syokota splx(s); 84542421Syokota return EINVAL; 84642421Syokota } 847112050Sdwmalone error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum], 848112050Sdwmalone &keyp->key, curthread); 849112050Sdwmalone if (error != 0) { 850112050Sdwmalone splx(s); 851112050Sdwmalone return error; 852112050Sdwmalone } 85342573Syokota bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum], 85442421Syokota sizeof(keyp->key)); 85542421Syokota break; 85644628Syokota#else 85744628Syokota splx(s); 85844628Syokota return ENODEV; 85944628Syokota#endif 86042421Syokota 86142421Syokota case GIO_DEADKEYMAP: /* get accent key translation table */ 86242421Syokota bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap)); 86342421Syokota break; 86442421Syokota case PIO_DEADKEYMAP: /* set accent key translation table */ 86544628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 866112050Sdwmalone error = accent_change_ok(kbd->kb_accentmap, 867112050Sdwmalone (accentmap_t *)arg, curthread); 868112050Sdwmalone if (error != 0) { 869112050Sdwmalone splx(s); 870112050Sdwmalone return error; 871112050Sdwmalone } 87242421Syokota bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 87342421Syokota break; 87444628Syokota#else 87544628Syokota splx(s); 87644628Syokota return ENODEV; 87744628Syokota#endif 87842421Syokota 87942421Syokota case GETFKEY: /* get functionkey string */ 88042421Syokota fkeyp = (fkeyarg_t *)arg; 88142421Syokota if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 88242421Syokota splx(s); 88342421Syokota return EINVAL; 88442421Syokota } 88542421Syokota bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef, 88642421Syokota kbd->kb_fkeytab[fkeyp->keynum].len); 88742421Syokota fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len; 88842421Syokota break; 88942421Syokota case SETFKEY: /* set functionkey string */ 89044628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 89142421Syokota fkeyp = (fkeyarg_t *)arg; 89242421Syokota if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 89342421Syokota splx(s); 89442421Syokota return EINVAL; 89542421Syokota } 896112050Sdwmalone error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum], 897112050Sdwmalone fkeyp, curthread); 898112050Sdwmalone if (error != 0) { 899112050Sdwmalone splx(s); 900112050Sdwmalone return error; 901112050Sdwmalone } 90242421Syokota kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK); 90342421Syokota bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str, 90442421Syokota kbd->kb_fkeytab[fkeyp->keynum].len); 90542421Syokota break; 90644628Syokota#else 90744628Syokota splx(s); 90844628Syokota return ENODEV; 90944628Syokota#endif 91042421Syokota 91142421Syokota default: 91242421Syokota splx(s); 91342421Syokota return ENOIOCTL; 91442421Syokota } 91542421Syokota 91642421Syokota splx(s); 91742421Syokota return 0; 91842421Syokota} 91942421Syokota 920112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 921112050Sdwmalone#define RESTRICTED_KEY(key, i) \ 922112050Sdwmalone ((key->spcl & (0x80 >> i)) && \ 923112050Sdwmalone (key->map[i] == RBT || key->map[i] == SUSP || \ 924112050Sdwmalone key->map[i] == STBY || key->map[i] == DBG || \ 925112050Sdwmalone key->map[i] == PNC || key->map[i] == HALT || \ 926112050Sdwmalone key->map[i] == PDWN)) 927112050Sdwmalone 928112050Sdwmalonestatic int 929112050Sdwmalonekey_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct thread *td) 930112050Sdwmalone{ 931112050Sdwmalone int i; 932112050Sdwmalone 933112050Sdwmalone /* Low keymap_restrict_change means any changes are OK. */ 934112050Sdwmalone if (keymap_restrict_change <= 0) 935112050Sdwmalone return 0; 936112050Sdwmalone 937112050Sdwmalone /* High keymap_restrict_change means only root can change the keymap. */ 938112050Sdwmalone if (keymap_restrict_change >= 2) { 939112050Sdwmalone for (i = 0; i < NUM_STATES; i++) 940112050Sdwmalone if (oldkey->map[i] != newkey->map[i]) 941112050Sdwmalone return suser(td); 942112050Sdwmalone if (oldkey->spcl != newkey->spcl) 943112050Sdwmalone return suser(td); 944112050Sdwmalone if (oldkey->flgs != newkey->flgs) 945112050Sdwmalone return suser(td); 946112050Sdwmalone return 0; 947112050Sdwmalone } 948112050Sdwmalone 949112050Sdwmalone /* Otherwise we have to see if any special keys are being changed. */ 950112050Sdwmalone for (i = 0; i < NUM_STATES; i++) { 951112050Sdwmalone /* 952112050Sdwmalone * If either the oldkey or the newkey action is restricted 953112050Sdwmalone * then we must make sure that the action doesn't change. 954112050Sdwmalone */ 955112050Sdwmalone if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i)) 956112050Sdwmalone continue; 957112050Sdwmalone if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i)) 958112050Sdwmalone && oldkey->map[i] == newkey->map[i]) 959112050Sdwmalone continue; 960112050Sdwmalone return suser(td); 961112050Sdwmalone } 962112050Sdwmalone 963112050Sdwmalone return 0; 964112050Sdwmalone} 965112050Sdwmalone 966112050Sdwmalonestatic int 967112050Sdwmalonekeymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct thread *td) 968112050Sdwmalone{ 969112050Sdwmalone int keycode, error; 970112050Sdwmalone 971112050Sdwmalone for (keycode = 0; keycode < NUM_KEYS; keycode++) { 972112050Sdwmalone if ((error = key_change_ok(&oldmap->key[keycode], 973112050Sdwmalone &newmap->key[keycode], td)) != 0) 974112050Sdwmalone return error; 975112050Sdwmalone } 976112050Sdwmalone return 0; 977112050Sdwmalone} 978112050Sdwmalone 979112050Sdwmalonestatic int 980112050Sdwmaloneaccent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct thread *td) 981112050Sdwmalone{ 982112050Sdwmalone struct acc_t *oldacc, *newacc; 983112050Sdwmalone int accent, i; 984112050Sdwmalone 985112050Sdwmalone if (keymap_restrict_change <= 2) 986112050Sdwmalone return 0; 987112050Sdwmalone 988112050Sdwmalone if (oldmap->n_accs != newmap->n_accs) 989112050Sdwmalone return suser(td); 990112050Sdwmalone 991112050Sdwmalone for (accent = 0; accent < oldmap->n_accs; accent++) { 992112050Sdwmalone oldacc = &oldmap->acc[accent]; 993112050Sdwmalone newacc = &newmap->acc[accent]; 994112050Sdwmalone if (oldacc->accchar != newacc->accchar) 995112050Sdwmalone return suser(td); 996112050Sdwmalone for (i = 0; i < NUM_ACCENTCHARS; ++i) { 997112050Sdwmalone if (oldacc->map[i][0] != newacc->map[i][0]) 998112050Sdwmalone return suser(td); 999112050Sdwmalone if (oldacc->map[i][0] == 0) /* end of table */ 1000112050Sdwmalone break; 1001112050Sdwmalone if (oldacc->map[i][1] != newacc->map[i][1]) 1002112050Sdwmalone return suser(td); 1003112050Sdwmalone } 1004112050Sdwmalone } 1005112050Sdwmalone 1006112050Sdwmalone return 0; 1007112050Sdwmalone} 1008112050Sdwmalone 1009112050Sdwmalonestatic int 1010112050Sdwmalonefkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct thread *td) 1011112050Sdwmalone{ 1012112050Sdwmalone if (keymap_restrict_change <= 3) 1013112050Sdwmalone return 0; 1014112050Sdwmalone 1015112050Sdwmalone if (oldkey->len != newkey->flen || 1016112050Sdwmalone bcmp(oldkey->str, newkey->keydef, oldkey->len) != 0) 1017112050Sdwmalone return suser(td); 1018112050Sdwmalone 1019112050Sdwmalone return 0; 1020112050Sdwmalone} 1021112050Sdwmalone#endif 1022112050Sdwmalone 102342421Syokota/* get a pointer to the string associated with the given function key */ 102442421Syokotau_char 102542421Syokota*genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len) 102642421Syokota{ 102742421Syokota if (kbd == NULL) 102842421Syokota return NULL; 102942421Syokota fkey -= F_FN; 103042421Syokota if (fkey > kbd->kb_fkeytab_size) 103142421Syokota return NULL; 103242421Syokota *len = kbd->kb_fkeytab[fkey].len; 103342421Syokota return kbd->kb_fkeytab[fkey].str; 103442421Syokota} 103542421Syokota 103642421Syokota/* diagnostic dump */ 103742421Syokotastatic char 103842421Syokota*get_kbd_type_name(int type) 103942421Syokota{ 104042421Syokota static struct { 104142421Syokota int type; 104242421Syokota char *name; 104342421Syokota } name_table[] = { 104442421Syokota { KB_84, "AT 84" }, 104542421Syokota { KB_101, "AT 101/102" }, 104642421Syokota { KB_OTHER, "generic" }, 104742421Syokota }; 104842421Syokota int i; 104942421Syokota 105042421Syokota for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) { 105142421Syokota if (type == name_table[i].type) 105242421Syokota return name_table[i].name; 105342421Syokota } 105442421Syokota return "unknown"; 105542421Syokota} 105642421Syokota 105742421Syokotavoid 105842421Syokotagenkbd_diag(keyboard_t *kbd, int level) 105942421Syokota{ 106042421Syokota if (level > 0) { 106142421Syokota printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x", 106242421Syokota kbd->kb_index, kbd->kb_name, kbd->kb_unit, 106342421Syokota get_kbd_type_name(kbd->kb_type), kbd->kb_type, 106442421Syokota kbd->kb_config, kbd->kb_flags); 106542421Syokota if (kbd->kb_io_base > 0) 106642421Syokota printf(", port:0x%x-0x%x", kbd->kb_io_base, 106742421Syokota kbd->kb_io_base + kbd->kb_io_size - 1); 106842421Syokota printf("\n"); 106942421Syokota } 107042421Syokota} 107142421Syokota 107242421Syokota#define set_lockkey_state(k, s, l) \ 107342421Syokota if (!((s) & l ## DOWN)) { \ 107442421Syokota int i; \ 107542421Syokota (s) |= l ## DOWN; \ 107642421Syokota (s) ^= l ## ED; \ 107742421Syokota i = (s) & LOCK_MASK; \ 107842421Syokota (*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \ 107942421Syokota } 108042421Syokota 108142421Syokotastatic u_int 108242421Syokotasave_accent_key(keyboard_t *kbd, u_int key, int *accents) 108342421Syokota{ 108442421Syokota int i; 108542421Syokota 108642421Syokota /* make an index into the accent map */ 108742421Syokota i = key - F_ACC + 1; 108842421Syokota if ((i > kbd->kb_accentmap->n_accs) 108942421Syokota || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) { 109042421Syokota /* the index is out of range or pointing to an empty entry */ 109142421Syokota *accents = 0; 109242421Syokota return ERRKEY; 109342421Syokota } 109442421Syokota 109542421Syokota /* 109642421Syokota * If the same accent key has been hit twice, produce the accent char 109742421Syokota * itself. 109842421Syokota */ 109942421Syokota if (i == *accents) { 110042421Syokota key = kbd->kb_accentmap->acc[i - 1].accchar; 110142421Syokota *accents = 0; 110242421Syokota return key; 110342421Syokota } 110442421Syokota 110542421Syokota /* remember the index and wait for the next key */ 110642421Syokota *accents = i; 110742421Syokota return NOKEY; 110842421Syokota} 110942421Syokota 111042421Syokotastatic u_int 111142421Syokotamake_accent_char(keyboard_t *kbd, u_int ch, int *accents) 111242421Syokota{ 111342421Syokota struct acc_t *acc; 111442421Syokota int i; 111542421Syokota 111642421Syokota acc = &kbd->kb_accentmap->acc[*accents - 1]; 111742421Syokota *accents = 0; 111842421Syokota 111942421Syokota /* 112042421Syokota * If the accent key is followed by the space key, 112142421Syokota * produce the accent char itself. 112242421Syokota */ 112342421Syokota if (ch == ' ') 112442421Syokota return acc->accchar; 112542421Syokota 112642421Syokota /* scan the accent map */ 112742421Syokota for (i = 0; i < NUM_ACCENTCHARS; ++i) { 112842421Syokota if (acc->map[i][0] == 0) /* end of table */ 112942421Syokota break; 113042421Syokota if (acc->map[i][0] == ch) 113142421Syokota return acc->map[i][1]; 113242421Syokota } 113342421Syokota /* this char cannot be accented... */ 113442421Syokota return ERRKEY; 113542421Syokota} 113642421Syokota 113742421Syokotaint 113842421Syokotagenkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate, 113942421Syokota int *accents) 114042421Syokota{ 114142421Syokota struct keyent_t *key; 114242421Syokota int state = *shiftstate; 114342421Syokota int action; 114442421Syokota int f; 114542421Syokota int i; 114642421Syokota 114754382Syokota i = keycode; 114842421Syokota f = state & (AGRS | ALKED); 114942421Syokota if ((f == AGRS1) || (f == AGRS2) || (f == ALKED)) 115054382Syokota i += ALTGR_OFFSET; 115154382Syokota key = &kbd->kb_keymap->key[i]; 115242421Syokota i = ((state & SHIFTS) ? 1 : 0) 115342421Syokota | ((state & CTLS) ? 2 : 0) 115442421Syokota | ((state & ALTS) ? 4 : 0); 115542421Syokota if (((key->flgs & FLAG_LOCK_C) && (state & CLKED)) 115642421Syokota || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) ) 115742421Syokota i ^= 1; 115842421Syokota 115942421Syokota if (up) { /* break: key released */ 116080040Syokota action = kbd->kb_lastact[keycode]; 116180040Syokota kbd->kb_lastact[keycode] = NOP; 116280040Syokota switch (action) { 116380040Syokota case LSHA: 116480040Syokota if (state & SHIFTAON) { 116580040Syokota set_lockkey_state(kbd, state, ALK); 116680040Syokota state &= ~ALKDOWN; 116780040Syokota } 116880040Syokota action = LSH; 116980040Syokota /* FALL THROUGH */ 117080040Syokota case LSH: 117180040Syokota state &= ~SHIFTS1; 117280040Syokota break; 117380040Syokota case RSHA: 117480040Syokota if (state & SHIFTAON) { 117580040Syokota set_lockkey_state(kbd, state, ALK); 117680040Syokota state &= ~ALKDOWN; 117780040Syokota } 117880040Syokota action = RSH; 117980040Syokota /* FALL THROUGH */ 118080040Syokota case RSH: 118180040Syokota state &= ~SHIFTS2; 118280040Syokota break; 118380040Syokota case LCTRA: 118480040Syokota if (state & SHIFTAON) { 118580040Syokota set_lockkey_state(kbd, state, ALK); 118680040Syokota state &= ~ALKDOWN; 118780040Syokota } 118880040Syokota action = LCTR; 118980040Syokota /* FALL THROUGH */ 119080040Syokota case LCTR: 119180040Syokota state &= ~CTLS1; 119280040Syokota break; 119380040Syokota case RCTRA: 119480040Syokota if (state & SHIFTAON) { 119580040Syokota set_lockkey_state(kbd, state, ALK); 119680040Syokota state &= ~ALKDOWN; 119780040Syokota } 119880040Syokota action = RCTR; 119980040Syokota /* FALL THROUGH */ 120080040Syokota case RCTR: 120180040Syokota state &= ~CTLS2; 120280040Syokota break; 120380040Syokota case LALTA: 120480040Syokota if (state & SHIFTAON) { 120580040Syokota set_lockkey_state(kbd, state, ALK); 120680040Syokota state &= ~ALKDOWN; 120780040Syokota } 120880040Syokota action = LALT; 120980040Syokota /* FALL THROUGH */ 121080040Syokota case LALT: 121180040Syokota state &= ~ALTS1; 121280040Syokota break; 121380040Syokota case RALTA: 121480040Syokota if (state & SHIFTAON) { 121580040Syokota set_lockkey_state(kbd, state, ALK); 121680040Syokota state &= ~ALKDOWN; 121780040Syokota } 121880040Syokota action = RALT; 121980040Syokota /* FALL THROUGH */ 122080040Syokota case RALT: 122180040Syokota state &= ~ALTS2; 122280040Syokota break; 122380040Syokota case ASH: 122480040Syokota state &= ~AGRS1; 122580040Syokota break; 122680040Syokota case META: 122780040Syokota state &= ~METAS1; 122880040Syokota break; 122980040Syokota case NLK: 123080040Syokota state &= ~NLKDOWN; 123180040Syokota break; 123280040Syokota case CLK: 123342421Syokota#ifndef PC98 123480040Syokota state &= ~CLKDOWN; 123542421Syokota#else 123680040Syokota state &= ~CLKED; 123780040Syokota i = state & LOCK_MASK; 123880040Syokota (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED, 123980040Syokota (caddr_t)&i); 124042421Syokota#endif 124180040Syokota break; 124280040Syokota case SLK: 124380040Syokota state &= ~SLKDOWN; 124480040Syokota break; 124580040Syokota case ALK: 124680040Syokota state &= ~ALKDOWN; 124780040Syokota break; 124880040Syokota case NOP: 124980040Syokota /* release events of regular keys are not reported */ 125080040Syokota *shiftstate &= ~SHIFTAON; 125180040Syokota return NOKEY; 125242421Syokota } 125380040Syokota *shiftstate = state & ~SHIFTAON; 125480040Syokota return (SPCLKEY | RELKEY | action); 125542421Syokota } else { /* make: key pressed */ 125680040Syokota action = key->map[i]; 125755820Syokota state &= ~SHIFTAON; 125842421Syokota if (key->spcl & (0x80 >> i)) { 125942421Syokota /* special keys */ 126080040Syokota if (kbd->kb_lastact[keycode] == NOP) 126180040Syokota kbd->kb_lastact[keycode] = action; 126280040Syokota if (kbd->kb_lastact[keycode] != action) 126380040Syokota action = NOP; 126442421Syokota switch (action) { 126542421Syokota /* LOCKING KEYS */ 126642421Syokota case NLK: 126742421Syokota set_lockkey_state(kbd, state, NLK); 126842421Syokota break; 126942421Syokota case CLK: 127042421Syokota#ifndef PC98 127142421Syokota set_lockkey_state(kbd, state, CLK); 127242421Syokota#else 127342421Syokota state |= CLKED; 127442421Syokota i = state & LOCK_MASK; 127542421Syokota (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED, 127642421Syokota (caddr_t)&i); 127742421Syokota#endif 127842421Syokota break; 127942421Syokota case SLK: 128042421Syokota set_lockkey_state(kbd, state, SLK); 128142421Syokota break; 128242421Syokota case ALK: 128342421Syokota set_lockkey_state(kbd, state, ALK); 128442421Syokota break; 128542421Syokota /* NON-LOCKING KEYS */ 128642421Syokota case SPSC: case RBT: case SUSP: case STBY: 128754382Syokota case DBG: case NEXT: case PREV: case PNC: 128865759Sdwmalone case HALT: case PDWN: 128942421Syokota *accents = 0; 129042421Syokota break; 129142421Syokota case BTAB: 129242421Syokota *accents = 0; 129342421Syokota action |= BKEY; 129442421Syokota break; 129554382Syokota case LSHA: 129655820Syokota state |= SHIFTAON; 129754382Syokota action = LSH; 129854382Syokota /* FALL THROUGH */ 129942421Syokota case LSH: 130042421Syokota state |= SHIFTS1; 130142421Syokota break; 130254382Syokota case RSHA: 130355820Syokota state |= SHIFTAON; 130454382Syokota action = RSH; 130554382Syokota /* FALL THROUGH */ 130642421Syokota case RSH: 130742421Syokota state |= SHIFTS2; 130842421Syokota break; 130954382Syokota case LCTRA: 131055820Syokota state |= SHIFTAON; 131154382Syokota action = LCTR; 131254382Syokota /* FALL THROUGH */ 131342421Syokota case LCTR: 131442421Syokota state |= CTLS1; 131542421Syokota break; 131654382Syokota case RCTRA: 131755820Syokota state |= SHIFTAON; 131854382Syokota action = RCTR; 131954382Syokota /* FALL THROUGH */ 132042421Syokota case RCTR: 132142421Syokota state |= CTLS2; 132242421Syokota break; 132354382Syokota case LALTA: 132455820Syokota state |= SHIFTAON; 132554382Syokota action = LALT; 132654382Syokota /* FALL THROUGH */ 132742421Syokota case LALT: 132842421Syokota state |= ALTS1; 132942421Syokota break; 133054382Syokota case RALTA: 133155820Syokota state |= SHIFTAON; 133254382Syokota action = RALT; 133354382Syokota /* FALL THROUGH */ 133442421Syokota case RALT: 133542421Syokota state |= ALTS2; 133642421Syokota break; 133742421Syokota case ASH: 133842421Syokota state |= AGRS1; 133942421Syokota break; 134042421Syokota case META: 134142421Syokota state |= METAS1; 134242421Syokota break; 134380040Syokota case NOP: 134480040Syokota *shiftstate = state; 134580040Syokota return NOKEY; 134642421Syokota default: 134742421Syokota /* is this an accent (dead) key? */ 134855820Syokota *shiftstate = state; 134942421Syokota if (action >= F_ACC && action <= L_ACC) { 135042421Syokota action = save_accent_key(kbd, action, 135142421Syokota accents); 135242421Syokota switch (action) { 135342421Syokota case NOKEY: 135442421Syokota case ERRKEY: 135542421Syokota return action; 135642421Syokota default: 135742421Syokota if (state & METAS) 135842421Syokota return (action | MKEY); 135942421Syokota else 136042421Syokota return action; 136142421Syokota } 136242421Syokota /* NOT REACHED */ 136342421Syokota } 136442421Syokota /* other special keys */ 136542421Syokota if (*accents > 0) { 136642421Syokota *accents = 0; 136742421Syokota return ERRKEY; 136842421Syokota } 136942421Syokota if (action >= F_FN && action <= L_FN) 137042421Syokota action |= FKEY; 137142421Syokota /* XXX: return fkey string for the FKEY? */ 137255820Syokota return (SPCLKEY | action); 137342421Syokota } 137442421Syokota *shiftstate = state; 137542421Syokota return (SPCLKEY | action); 137642421Syokota } else { 137742421Syokota /* regular keys */ 137880040Syokota kbd->kb_lastact[keycode] = NOP; 137955820Syokota *shiftstate = state; 138042421Syokota if (*accents > 0) { 138142421Syokota /* make an accented char */ 138242421Syokota action = make_accent_char(kbd, action, accents); 138342421Syokota if (action == ERRKEY) 138442421Syokota return action; 138542421Syokota } 138642421Syokota if (state & METAS) 138742421Syokota action |= MKEY; 138842421Syokota return action; 138942421Syokota } 139042421Syokota } 139142421Syokota /* NOT REACHED */ 139242421Syokota} 1393