kbd.c revision 147980
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 147980 2005-07-13 23:58:57Z emax $"); 30119418Sobrien 3142421Syokota#include "opt_kbd.h" 3242421Syokota 3342421Syokota#include <sys/param.h> 3442421Syokota#include <sys/systm.h> 3542421Syokota#include <sys/kernel.h> 3642421Syokota#include <sys/malloc.h> 3742421Syokota#include <sys/conf.h> 38139193Sphk#include <sys/fcntl.h> 3942421Syokota#include <sys/tty.h> 4042421Syokota#include <sys/poll.h> 41112050Sdwmalone#include <sys/proc.h> 42112050Sdwmalone#include <sys/sysctl.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 285147980Semax/* 286147980Semax * find the keyboard specified by a driver name and a unit number 287147980Semax * starting at given index 288147980Semax */ 28942421Syokotaint 290147980Semaxkbd_find_keyboard2(char *driver, int unit, int index) 29142421Syokota{ 29242421Syokota int i; 29342421Syokota 294147980Semax if ((index < 0) || (index >= keyboards)) 295147980Semax return (-1); 296147980Semax 297147980Semax for (i = index; i < keyboards; ++i) { 29842421Syokota if (keyboard[i] == NULL) 29942421Syokota continue; 30042421Syokota if (!KBD_IS_VALID(keyboard[i])) 30142421Syokota continue; 30242421Syokota if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver)) 30342421Syokota continue; 30442421Syokota if ((unit != -1) && (keyboard[i]->kb_unit != unit)) 30542421Syokota continue; 306127752Sdes return (i); 30742421Syokota } 308147980Semax 309127752Sdes return (-1); 31042421Syokota} 31142421Syokota 312147980Semax/* find the keyboard specified by a driver name and a unit number */ 313147980Semaxint 314147980Semaxkbd_find_keyboard(char *driver, int unit) 315147980Semax{ 316147980Semax return (kbd_find_keyboard2(driver, unit, 0)); 317147980Semax} 318147980Semax 31942421Syokota/* allocate a keyboard */ 32042421Syokotaint 32142421Syokotakbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func, 32242421Syokota void *arg) 32342421Syokota{ 32442421Syokota int index; 32542421Syokota int s; 32642421Syokota 32742421Syokota if (func == NULL) 328127752Sdes return (-1); 32942421Syokota 33042421Syokota s = spltty(); 33142421Syokota index = kbd_find_keyboard(driver, unit); 33242421Syokota if (index >= 0) { 33342421Syokota if (KBD_IS_BUSY(keyboard[index])) { 33442421Syokota splx(s); 335127752Sdes return (-1); 33642421Syokota } 33742421Syokota keyboard[index]->kb_token = id; 33842421Syokota KBD_BUSY(keyboard[index]); 33942421Syokota keyboard[index]->kb_callback.kc_func = func; 34042421Syokota keyboard[index]->kb_callback.kc_arg = arg; 34142421Syokota (*kbdsw[index]->clear_state)(keyboard[index]); 34242421Syokota } 34342421Syokota splx(s); 344127752Sdes return (index); 34542421Syokota} 34642421Syokota 34742421Syokotaint 34842421Syokotakbd_release(keyboard_t *kbd, void *id) 34942421Syokota{ 35042421Syokota int error; 35142421Syokota int s; 35242421Syokota 35342421Syokota s = spltty(); 35442421Syokota if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 35542421Syokota error = EINVAL; 35642421Syokota } else if (kbd->kb_token != id) { 35742421Syokota error = EPERM; 35842421Syokota } else { 35942421Syokota kbd->kb_token = NULL; 36042421Syokota KBD_UNBUSY(kbd); 36142421Syokota kbd->kb_callback.kc_func = NULL; 36242421Syokota kbd->kb_callback.kc_arg = NULL; 36342421Syokota (*kbdsw[kbd->kb_index]->clear_state)(kbd); 36442421Syokota error = 0; 36542421Syokota } 36642421Syokota splx(s); 367127752Sdes return (error); 36842421Syokota} 36942421Syokota 37042421Syokotaint 37142421Syokotakbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func, 37242421Syokota void *arg) 37342421Syokota{ 37442421Syokota int error; 37542421Syokota int s; 37642421Syokota 37742421Syokota s = spltty(); 37842421Syokota if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { 37942421Syokota error = EINVAL; 38042421Syokota } else if (kbd->kb_token != id) { 38142421Syokota error = EPERM; 38242421Syokota } else if (func == NULL) { 38342421Syokota error = EINVAL; 38442421Syokota } else { 38542421Syokota kbd->kb_callback.kc_func = func; 38642421Syokota kbd->kb_callback.kc_arg = arg; 38742421Syokota error = 0; 38842421Syokota } 38942421Syokota splx(s); 390127752Sdes return (error); 39142421Syokota} 39242421Syokota 39342421Syokota/* get a keyboard structure */ 39442421Syokotakeyboard_t 39542421Syokota*kbd_get_keyboard(int index) 39642421Syokota{ 39742421Syokota if ((index < 0) || (index >= keyboards)) 398127752Sdes return (NULL); 39950154Syokota if (keyboard[index] == NULL) 400127752Sdes return (NULL); 40142421Syokota if (!KBD_IS_VALID(keyboard[index])) 402127752Sdes return (NULL); 403127752Sdes return (keyboard[index]); 40442421Syokota} 40542421Syokota 40642421Syokota/* 40742421Syokota * The back door for the console driver; configure keyboards 40842421Syokota * This function is for the kernel console to initialize keyboards 40942421Syokota * at very early stage. 41042421Syokota */ 41142421Syokota 41242421Syokotaint 41342421Syokotakbd_configure(int flags) 41442421Syokota{ 41547295Syokota const keyboard_driver_t **list; 41647295Syokota const keyboard_driver_t *p; 41742421Syokota 41854545Syokota SLIST_FOREACH(p, &keyboard_drivers, link) { 41954545Syokota if (p->configure != NULL) 42054545Syokota (*p->configure)(flags); 42154545Syokota } 42278161Speter SET_FOREACH(list, kbddriver_set) { 42378161Speter p = *list; 42442421Syokota if (p->configure != NULL) 42542421Syokota (*p->configure)(flags); 42642421Syokota } 42742421Syokota 428127752Sdes return (0); 42942421Syokota} 43042421Syokota 43142421Syokota#ifdef KBD_INSTALL_CDEV 43242421Syokota 43342421Syokota/* 43442421Syokota * Virtual keyboard cdev driver functions 43542421Syokota * The virtual keyboard driver dispatches driver functions to 43642421Syokota * appropriate subdrivers. 43742421Syokota */ 43842421Syokota 43942421Syokota#define KBD_UNIT(dev) minor(dev) 44042421Syokota 44150154Syokotastatic d_open_t genkbdopen; 44250154Syokotastatic d_close_t genkbdclose; 44350154Syokotastatic d_read_t genkbdread; 44450154Syokotastatic d_write_t genkbdwrite; 44550154Syokotastatic d_ioctl_t genkbdioctl; 44650154Syokotastatic d_poll_t genkbdpoll; 44742421Syokota 44842421Syokota 44942421Syokotastatic struct cdevsw kbd_cdevsw = { 450126080Sphk .d_version = D_VERSION, 451126080Sphk .d_flags = D_NEEDGIANT, 452111815Sphk .d_open = genkbdopen, 453111815Sphk .d_close = genkbdclose, 454111815Sphk .d_read = genkbdread, 455111815Sphk .d_write = genkbdwrite, 456111815Sphk .d_ioctl = genkbdioctl, 457111815Sphk .d_poll = genkbdpoll, 458111815Sphk .d_name = "kbd", 45942421Syokota}; 46042421Syokota 46142421Syokotaint 46250154Syokotakbd_attach(keyboard_t *kbd) 46342421Syokota{ 46442421Syokota 46542421Syokota if (kbd->kb_index >= keyboards) 466127752Sdes return (EINVAL); 46742421Syokota if (keyboard[kbd->kb_index] != kbd) 468127752Sdes return (EINVAL); 46942421Syokota 470127751Sdes kbd->kb_dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, 471127751Sdes 0600, "%s%r", kbd->kb_name, kbd->kb_unit); 472125087Sdes make_dev_alias(kbd->kb_dev, "kbd%r", kbd->kb_index); 473120502Sphk kbd->kb_dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF, 474127751Sdes M_WAITOK | M_ZERO); 47542421Syokota printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit); 476127752Sdes return (0); 47742421Syokota} 47842421Syokota 47942421Syokotaint 48050154Syokotakbd_detach(keyboard_t *kbd) 48142421Syokota{ 48254545Syokota 48342421Syokota if (kbd->kb_index >= keyboards) 484127752Sdes return (EINVAL); 48542421Syokota if (keyboard[kbd->kb_index] != kbd) 486127752Sdes return (EINVAL); 48742421Syokota 488120502Sphk free(kbd->kb_dev->si_drv1, M_DEVBUF); 489120502Sphk destroy_dev(kbd->kb_dev); 49054545Syokota 491127752Sdes return (0); 49242421Syokota} 49342421Syokota 49442421Syokota/* 49542421Syokota * Generic keyboard cdev driver functions 49642421Syokota * Keyboard subdrivers may call these functions to implement common 49742421Syokota * driver functions. 49842421Syokota */ 49942421Syokota 50042421Syokota#define KB_QSIZE 512 50142421Syokota#define KB_BUFSIZE 64 50242421Syokota 50342421Syokotastatic kbd_callback_func_t genkbd_event; 50442421Syokota 50550154Syokotastatic int 506130585Sphkgenkbdopen(struct cdev *dev, int mode, int flag, struct thread *td) 50742421Syokota{ 50850154Syokota keyboard_t *kbd; 50950154Syokota genkbd_softc_t *sc; 51042421Syokota int s; 51142421Syokota int i; 51242421Syokota 51342421Syokota s = spltty(); 51450154Syokota sc = dev->si_drv1; 51550154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 51650154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 51742421Syokota splx(s); 518127752Sdes return (ENXIO); 51942421Syokota } 52042421Syokota i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc, 521127751Sdes genkbd_event, (void *)sc); 52242421Syokota if (i < 0) { 52342421Syokota splx(s); 524127752Sdes return (EBUSY); 52542421Syokota } 52642421Syokota /* assert(i == kbd->kb_index) */ 52742421Syokota /* assert(kbd == kbd_get_keyboard(i)) */ 52842421Syokota 52942421Syokota /* 53042421Syokota * NOTE: even when we have successfully claimed a keyboard, 53142421Syokota * the device may still be missing (!KBD_HAS_DEVICE(kbd)). 53242421Syokota */ 53342421Syokota 53442421Syokota#if 0 53542421Syokota bzero(&sc->gkb_q, sizeof(sc->gkb_q)); 53642421Syokota#endif 53742421Syokota clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */ 53842421Syokota splx(s); 53942421Syokota 540127752Sdes return (0); 54142421Syokota} 54242421Syokota 54350154Syokotastatic int 544130585Sphkgenkbdclose(struct cdev *dev, int mode, int flag, struct thread *td) 54542421Syokota{ 54650154Syokota keyboard_t *kbd; 54750154Syokota genkbd_softc_t *sc; 54842421Syokota int s; 54942421Syokota 55042421Syokota /* 55142421Syokota * NOTE: the device may have already become invalid. 55250154Syokota * kbd == NULL || !KBD_IS_VALID(kbd) 55342421Syokota */ 55442421Syokota s = spltty(); 55550154Syokota sc = dev->si_drv1; 55650154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 55750154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 55850154Syokota /* XXX: we shall be forgiving and don't report error... */ 55950154Syokota } else { 56050154Syokota kbd_release(kbd, (void *)sc); 56142421Syokota#if 0 56250154Syokota clist_free_cblocks(&sc->gkb_q); 56342421Syokota#endif 56450154Syokota } 56542421Syokota splx(s); 566127752Sdes return (0); 56742421Syokota} 56842421Syokota 56950154Syokotastatic int 570130585Sphkgenkbdread(struct cdev *dev, struct uio *uio, int flag) 57142421Syokota{ 57250154Syokota keyboard_t *kbd; 57350154Syokota genkbd_softc_t *sc; 57442421Syokota u_char buffer[KB_BUFSIZE]; 57542421Syokota int len; 57642421Syokota int error; 57742421Syokota int s; 57842421Syokota 57942421Syokota /* wait for input */ 58042421Syokota s = spltty(); 58150154Syokota sc = dev->si_drv1; 58250154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 58350154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 58450154Syokota splx(s); 585127752Sdes return (ENXIO); 58650154Syokota } 58742421Syokota while (sc->gkb_q.c_cc == 0) { 588139193Sphk if (flag & O_NONBLOCK) { 58942421Syokota splx(s); 590127752Sdes return (EWOULDBLOCK); 59142421Syokota } 59242421Syokota sc->gkb_flags |= KB_ASLEEP; 593111748Sdes error = tsleep(sc, PZERO | PCATCH, "kbdrea", 0); 59450154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 59550154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) { 59650154Syokota splx(s); 597127752Sdes return (ENXIO); /* our keyboard has gone... */ 59850154Syokota } 59942421Syokota if (error) { 60042421Syokota sc->gkb_flags &= ~KB_ASLEEP; 60142421Syokota splx(s); 602127752Sdes return (error); 60342421Syokota } 60442421Syokota } 60542421Syokota splx(s); 60642421Syokota 60742421Syokota /* copy as much input as possible */ 60842421Syokota error = 0; 60942421Syokota while (uio->uio_resid > 0) { 61042421Syokota len = imin(uio->uio_resid, sizeof(buffer)); 61142421Syokota len = q_to_b(&sc->gkb_q, buffer, len); 61242421Syokota if (len <= 0) 61342421Syokota break; 61442421Syokota error = uiomove(buffer, len, uio); 61542421Syokota if (error) 61642421Syokota break; 61742421Syokota } 61842421Syokota 619127752Sdes return (error); 62042421Syokota} 62142421Syokota 62250154Syokotastatic int 623130585Sphkgenkbdwrite(struct cdev *dev, struct uio *uio, int flag) 62442421Syokota{ 62550154Syokota keyboard_t *kbd; 62650154Syokota 62750154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 62850154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) 629127752Sdes return (ENXIO); 630127752Sdes return (ENODEV); 63142421Syokota} 63242421Syokota 63350154Syokotastatic int 634130585Sphkgenkbdioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) 63542421Syokota{ 63650154Syokota keyboard_t *kbd; 63742421Syokota int error; 63842421Syokota 63950154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 64050154Syokota if ((kbd == NULL) || !KBD_IS_VALID(kbd)) 641127752Sdes return (ENXIO); 64242421Syokota error = (*kbdsw[kbd->kb_index]->ioctl)(kbd, cmd, arg); 64342421Syokota if (error == ENOIOCTL) 64442421Syokota error = ENODEV; 645127752Sdes return (error); 64642421Syokota} 64742421Syokota 64850154Syokotastatic int 649130585Sphkgenkbdpoll(struct cdev *dev, int events, struct thread *td) 65042421Syokota{ 65150154Syokota keyboard_t *kbd; 65250154Syokota genkbd_softc_t *sc; 65342421Syokota int revents; 65442421Syokota int s; 65542421Syokota 65642421Syokota revents = 0; 65742421Syokota s = spltty(); 65850154Syokota sc = dev->si_drv1; 65950154Syokota kbd = kbd_get_keyboard(KBD_INDEX(dev)); 66050154Syokota if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { 66150154Syokota revents = POLLHUP; /* the keyboard has gone */ 66250154Syokota } else if (events & (POLLIN | POLLRDNORM)) { 66350154Syokota if (sc->gkb_q.c_cc > 0) 66450154Syokota revents = events & (POLLIN | POLLRDNORM); 66542421Syokota else 66683366Sjulian selrecord(td, &sc->gkb_rsel); 66742421Syokota } 66842421Syokota splx(s); 669127752Sdes return (revents); 67042421Syokota} 67142421Syokota 67242421Syokotastatic int 67342421Syokotagenkbd_event(keyboard_t *kbd, int event, void *arg) 67442421Syokota{ 67542421Syokota genkbd_softc_t *sc; 67642421Syokota size_t len; 67742421Syokota u_char *cp; 67842421Syokota int mode; 67942421Syokota int c; 68042421Syokota 68142421Syokota /* assert(KBD_IS_VALID(kbd)) */ 68242421Syokota sc = (genkbd_softc_t *)arg; 68342421Syokota 68442421Syokota switch (event) { 68542421Syokota case KBDIO_KEYINPUT: 68642421Syokota break; 68742421Syokota case KBDIO_UNLOADING: 68842421Syokota /* the keyboard is going... */ 68942421Syokota kbd_release(kbd, (void *)sc); 69050154Syokota if (sc->gkb_flags & KB_ASLEEP) { 69150154Syokota sc->gkb_flags &= ~KB_ASLEEP; 692111748Sdes wakeup(sc); 69350154Syokota } 694122352Stanimura selwakeuppri(&sc->gkb_rsel, PZERO); 695127752Sdes return (0); 69642421Syokota default: 697127752Sdes return (EINVAL); 69842421Syokota } 69942421Syokota 70042421Syokota /* obtain the current key input mode */ 70142421Syokota if ((*kbdsw[kbd->kb_index]->ioctl)(kbd, KDGKBMODE, (caddr_t)&mode)) 70242421Syokota mode = K_XLATE; 70342421Syokota 70442421Syokota /* read all pending input */ 70542421Syokota while ((*kbdsw[kbd->kb_index]->check_char)(kbd)) { 70642421Syokota c = (*kbdsw[kbd->kb_index]->read_char)(kbd, FALSE); 70742421Syokota if (c == NOKEY) 70842421Syokota continue; 70942421Syokota if (c == ERRKEY) /* XXX: ring bell? */ 71042421Syokota continue; 71142421Syokota if (!KBD_IS_BUSY(kbd)) 71242421Syokota /* the device is not open, discard the input */ 71342421Syokota continue; 71442421Syokota 71542421Syokota /* store the byte as is for K_RAW and K_CODE modes */ 71642421Syokota if (mode != K_XLATE) { 71742421Syokota putc(KEYCHAR(c), &sc->gkb_q); 71842421Syokota continue; 71942421Syokota } 72042421Syokota 72142421Syokota /* K_XLATE */ 72242421Syokota if (c & RELKEY) /* key release is ignored */ 72342421Syokota continue; 72442421Syokota 72542421Syokota /* process special keys; most of them are just ignored... */ 72642421Syokota if (c & SPCLKEY) { 72742421Syokota switch (KEYCHAR(c)) { 72854382Syokota default: 72942421Syokota /* ignore them... */ 73042421Syokota continue; 73142421Syokota case BTAB: /* a backtab: ESC [ Z */ 73242421Syokota putc(0x1b, &sc->gkb_q); 73342421Syokota putc('[', &sc->gkb_q); 73442421Syokota putc('Z', &sc->gkb_q); 73542421Syokota continue; 73642421Syokota } 73742421Syokota } 73842421Syokota 73942421Syokota /* normal chars, normal chars with the META, function keys */ 74042421Syokota switch (KEYFLAGS(c)) { 74142421Syokota case 0: /* a normal char */ 74242421Syokota putc(KEYCHAR(c), &sc->gkb_q); 74342421Syokota break; 74442421Syokota case MKEY: /* the META flag: prepend ESC */ 74542421Syokota putc(0x1b, &sc->gkb_q); 74642421Syokota putc(KEYCHAR(c), &sc->gkb_q); 74742421Syokota break; 74842421Syokota case FKEY | SPCLKEY: /* a function key, return string */ 74942421Syokota cp = (*kbdsw[kbd->kb_index]->get_fkeystr)(kbd, 750127751Sdes KEYCHAR(c), &len); 75142421Syokota if (cp != NULL) { 75242421Syokota while (len-- > 0) 75342421Syokota putc(*cp++, &sc->gkb_q); 75442421Syokota } 75542421Syokota break; 75642421Syokota } 75742421Syokota } 75842421Syokota 75942421Syokota /* wake up sleeping/polling processes */ 76042421Syokota if (sc->gkb_q.c_cc > 0) { 76142421Syokota if (sc->gkb_flags & KB_ASLEEP) { 76242421Syokota sc->gkb_flags &= ~KB_ASLEEP; 763111748Sdes wakeup(sc); 76442421Syokota } 765122352Stanimura selwakeuppri(&sc->gkb_rsel, PZERO); 76642421Syokota } 76742421Syokota 768127752Sdes return (0); 76942421Syokota} 77042421Syokota 77142421Syokota#endif /* KBD_INSTALL_CDEV */ 77242421Syokota 77342421Syokota/* 77442421Syokota * Generic low-level keyboard functions 77542421Syokota * The low-level functions in the keyboard subdriver may use these 77642421Syokota * functions. 77742421Syokota */ 77842421Syokota 779112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 780112050Sdwmalonestatic int key_change_ok(struct keyent_t *, struct keyent_t *, struct thread *); 781112050Sdwmalonestatic int keymap_change_ok(keymap_t *, keymap_t *, struct thread *); 782112050Sdwmalonestatic int accent_change_ok(accentmap_t *, accentmap_t *, struct thread *); 783112050Sdwmalonestatic int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct thread *); 784112050Sdwmalone#endif 785112050Sdwmalone 78642421Syokotaint 78742421Syokotagenkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) 78842421Syokota{ 78942421Syokota keyarg_t *keyp; 79042421Syokota fkeyarg_t *fkeyp; 79142421Syokota int s; 79242421Syokota int i; 793112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 794112050Sdwmalone int error; 795112050Sdwmalone#endif 79642421Syokota 79742421Syokota s = spltty(); 79842421Syokota switch (cmd) { 79942421Syokota 80042421Syokota case KDGKBINFO: /* get keyboard information */ 80142421Syokota ((keyboard_info_t *)arg)->kb_index = kbd->kb_index; 80242421Syokota i = imin(strlen(kbd->kb_name) + 1, 803127751Sdes sizeof(((keyboard_info_t *)arg)->kb_name)); 80442421Syokota bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i); 80542421Syokota ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit; 80642421Syokota ((keyboard_info_t *)arg)->kb_type = kbd->kb_type; 80742421Syokota ((keyboard_info_t *)arg)->kb_config = kbd->kb_config; 80842421Syokota ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags; 80942421Syokota break; 81042421Syokota 81142421Syokota case KDGKBTYPE: /* get keyboard type */ 81242421Syokota *(int *)arg = kbd->kb_type; 81342421Syokota break; 81442421Syokota 81554543Syokota case KDGETREPEAT: /* get keyboard repeat rate */ 81654543Syokota ((int *)arg)[0] = kbd->kb_delay1; 817127751Sdes ((int *)arg)[1] = kbd->kb_delay2; 81854543Syokota break; 81954543Syokota 82042421Syokota case GIO_KEYMAP: /* get keyboard translation table */ 82142421Syokota bcopy(kbd->kb_keymap, arg, sizeof(*kbd->kb_keymap)); 82242421Syokota break; 82342421Syokota case PIO_KEYMAP: /* set keyboard translation table */ 82444628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 825112050Sdwmalone error = keymap_change_ok(kbd->kb_keymap, (keymap_t *)arg, 826112050Sdwmalone curthread); 827112050Sdwmalone if (error != 0) { 828112050Sdwmalone splx(s); 829127752Sdes return (error); 830112050Sdwmalone } 83142421Syokota bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 83242421Syokota bcopy(arg, kbd->kb_keymap, sizeof(*kbd->kb_keymap)); 83342421Syokota break; 83444628Syokota#else 83544628Syokota splx(s); 836127752Sdes return (ENODEV); 83744628Syokota#endif 83842421Syokota 83942421Syokota case GIO_KEYMAPENT: /* get keyboard translation table entry */ 84042421Syokota keyp = (keyarg_t *)arg; 841127751Sdes if (keyp->keynum >= sizeof(kbd->kb_keymap->key) / 842127751Sdes sizeof(kbd->kb_keymap->key[0])) { 84342421Syokota splx(s); 844127752Sdes return (EINVAL); 84542421Syokota } 84642573Syokota bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key, 847127751Sdes sizeof(keyp->key)); 84842421Syokota break; 84942421Syokota case PIO_KEYMAPENT: /* set keyboard translation table entry */ 85044628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 85142421Syokota keyp = (keyarg_t *)arg; 852127751Sdes if (keyp->keynum >= sizeof(kbd->kb_keymap->key) / 853127751Sdes sizeof(kbd->kb_keymap->key[0])) { 85442421Syokota splx(s); 855127752Sdes return (EINVAL); 85642421Syokota } 857112050Sdwmalone error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum], 858112050Sdwmalone &keyp->key, curthread); 859112050Sdwmalone if (error != 0) { 860112050Sdwmalone splx(s); 861127752Sdes return (error); 862112050Sdwmalone } 86342573Syokota bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum], 864127751Sdes sizeof(keyp->key)); 86542421Syokota break; 86644628Syokota#else 86744628Syokota splx(s); 868127752Sdes return (ENODEV); 86944628Syokota#endif 87042421Syokota 87142421Syokota case GIO_DEADKEYMAP: /* get accent key translation table */ 87242421Syokota bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap)); 87342421Syokota break; 87442421Syokota case PIO_DEADKEYMAP: /* set accent key translation table */ 87544628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 876112050Sdwmalone error = accent_change_ok(kbd->kb_accentmap, 877112050Sdwmalone (accentmap_t *)arg, curthread); 878112050Sdwmalone if (error != 0) { 879112050Sdwmalone splx(s); 880127752Sdes return (error); 881112050Sdwmalone } 88242421Syokota bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); 88342421Syokota break; 88444628Syokota#else 88544628Syokota splx(s); 886127752Sdes return (ENODEV); 88744628Syokota#endif 88842421Syokota 88942421Syokota case GETFKEY: /* get functionkey string */ 89042421Syokota fkeyp = (fkeyarg_t *)arg; 89142421Syokota if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 89242421Syokota splx(s); 893127752Sdes return (EINVAL); 89442421Syokota } 89542421Syokota bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef, 896127751Sdes kbd->kb_fkeytab[fkeyp->keynum].len); 89742421Syokota fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len; 89842421Syokota break; 89942421Syokota case SETFKEY: /* set functionkey string */ 90044628Syokota#ifndef KBD_DISABLE_KEYMAP_LOAD 90142421Syokota fkeyp = (fkeyarg_t *)arg; 90242421Syokota if (fkeyp->keynum >= kbd->kb_fkeytab_size) { 90342421Syokota splx(s); 904127752Sdes return (EINVAL); 90542421Syokota } 906112050Sdwmalone error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum], 907112050Sdwmalone fkeyp, curthread); 908112050Sdwmalone if (error != 0) { 909112050Sdwmalone splx(s); 910127752Sdes return (error); 911112050Sdwmalone } 91242421Syokota kbd->kb_fkeytab[fkeyp->keynum].len = imin(fkeyp->flen, MAXFK); 91342421Syokota bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str, 914127751Sdes kbd->kb_fkeytab[fkeyp->keynum].len); 91542421Syokota break; 91644628Syokota#else 91744628Syokota splx(s); 918127752Sdes return (ENODEV); 91944628Syokota#endif 92042421Syokota 92142421Syokota default: 92242421Syokota splx(s); 923127752Sdes return (ENOIOCTL); 92442421Syokota } 92542421Syokota 92642421Syokota splx(s); 927127752Sdes return (0); 92842421Syokota} 92942421Syokota 930112050Sdwmalone#ifndef KBD_DISABLE_KEYMAP_LOAD 931112050Sdwmalone#define RESTRICTED_KEY(key, i) \ 932112050Sdwmalone ((key->spcl & (0x80 >> i)) && \ 933112050Sdwmalone (key->map[i] == RBT || key->map[i] == SUSP || \ 934112050Sdwmalone key->map[i] == STBY || key->map[i] == DBG || \ 935112050Sdwmalone key->map[i] == PNC || key->map[i] == HALT || \ 936112050Sdwmalone key->map[i] == PDWN)) 937112050Sdwmalone 938112050Sdwmalonestatic int 939112050Sdwmalonekey_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct thread *td) 940112050Sdwmalone{ 941112050Sdwmalone int i; 942112050Sdwmalone 943112050Sdwmalone /* Low keymap_restrict_change means any changes are OK. */ 944112050Sdwmalone if (keymap_restrict_change <= 0) 945127752Sdes return (0); 946112050Sdwmalone 947112050Sdwmalone /* High keymap_restrict_change means only root can change the keymap. */ 948112050Sdwmalone if (keymap_restrict_change >= 2) { 949112050Sdwmalone for (i = 0; i < NUM_STATES; i++) 950112050Sdwmalone if (oldkey->map[i] != newkey->map[i]) 951112050Sdwmalone return suser(td); 952112050Sdwmalone if (oldkey->spcl != newkey->spcl) 953112050Sdwmalone return suser(td); 954112050Sdwmalone if (oldkey->flgs != newkey->flgs) 955112050Sdwmalone return suser(td); 956127752Sdes return (0); 957112050Sdwmalone } 958112050Sdwmalone 959112050Sdwmalone /* Otherwise we have to see if any special keys are being changed. */ 960112050Sdwmalone for (i = 0; i < NUM_STATES; i++) { 961112050Sdwmalone /* 962112050Sdwmalone * If either the oldkey or the newkey action is restricted 963112050Sdwmalone * then we must make sure that the action doesn't change. 964112050Sdwmalone */ 965112050Sdwmalone if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i)) 966112050Sdwmalone continue; 967112050Sdwmalone if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i)) 968112050Sdwmalone && oldkey->map[i] == newkey->map[i]) 969112050Sdwmalone continue; 970112050Sdwmalone return suser(td); 971112050Sdwmalone } 972112050Sdwmalone 973127752Sdes return (0); 974112050Sdwmalone} 975112050Sdwmalone 976112050Sdwmalonestatic int 977112050Sdwmalonekeymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct thread *td) 978112050Sdwmalone{ 979112050Sdwmalone int keycode, error; 980112050Sdwmalone 981112050Sdwmalone for (keycode = 0; keycode < NUM_KEYS; keycode++) { 982112050Sdwmalone if ((error = key_change_ok(&oldmap->key[keycode], 983112050Sdwmalone &newmap->key[keycode], td)) != 0) 984127752Sdes return (error); 985112050Sdwmalone } 986127752Sdes return (0); 987112050Sdwmalone} 988112050Sdwmalone 989112050Sdwmalonestatic int 990112050Sdwmaloneaccent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct thread *td) 991112050Sdwmalone{ 992112050Sdwmalone struct acc_t *oldacc, *newacc; 993112050Sdwmalone int accent, i; 994112050Sdwmalone 995112050Sdwmalone if (keymap_restrict_change <= 2) 996127752Sdes return (0); 997112050Sdwmalone 998112050Sdwmalone if (oldmap->n_accs != newmap->n_accs) 999112050Sdwmalone return suser(td); 1000112050Sdwmalone 1001112050Sdwmalone for (accent = 0; accent < oldmap->n_accs; accent++) { 1002112050Sdwmalone oldacc = &oldmap->acc[accent]; 1003112050Sdwmalone newacc = &newmap->acc[accent]; 1004112050Sdwmalone if (oldacc->accchar != newacc->accchar) 1005112050Sdwmalone return suser(td); 1006112050Sdwmalone for (i = 0; i < NUM_ACCENTCHARS; ++i) { 1007112050Sdwmalone if (oldacc->map[i][0] != newacc->map[i][0]) 1008112050Sdwmalone return suser(td); 1009112050Sdwmalone if (oldacc->map[i][0] == 0) /* end of table */ 1010112050Sdwmalone break; 1011112050Sdwmalone if (oldacc->map[i][1] != newacc->map[i][1]) 1012112050Sdwmalone return suser(td); 1013112050Sdwmalone } 1014112050Sdwmalone } 1015112050Sdwmalone 1016127752Sdes return (0); 1017112050Sdwmalone} 1018112050Sdwmalone 1019112050Sdwmalonestatic int 1020112050Sdwmalonefkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct thread *td) 1021112050Sdwmalone{ 1022112050Sdwmalone if (keymap_restrict_change <= 3) 1023127752Sdes return (0); 1024112050Sdwmalone 1025112050Sdwmalone if (oldkey->len != newkey->flen || 1026112050Sdwmalone bcmp(oldkey->str, newkey->keydef, oldkey->len) != 0) 1027112050Sdwmalone return suser(td); 1028112050Sdwmalone 1029127752Sdes return (0); 1030112050Sdwmalone} 1031112050Sdwmalone#endif 1032112050Sdwmalone 103342421Syokota/* get a pointer to the string associated with the given function key */ 103442421Syokotau_char 103542421Syokota*genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len) 103642421Syokota{ 103742421Syokota if (kbd == NULL) 1038127752Sdes return (NULL); 103942421Syokota fkey -= F_FN; 104042421Syokota if (fkey > kbd->kb_fkeytab_size) 1041127752Sdes return (NULL); 104242421Syokota *len = kbd->kb_fkeytab[fkey].len; 1043127752Sdes return (kbd->kb_fkeytab[fkey].str); 104442421Syokota} 104542421Syokota 104642421Syokota/* diagnostic dump */ 104742421Syokotastatic char 104842421Syokota*get_kbd_type_name(int type) 104942421Syokota{ 105042421Syokota static struct { 105142421Syokota int type; 105242421Syokota char *name; 105342421Syokota } name_table[] = { 105442421Syokota { KB_84, "AT 84" }, 105542421Syokota { KB_101, "AT 101/102" }, 105642421Syokota { KB_OTHER, "generic" }, 105742421Syokota }; 105842421Syokota int i; 105942421Syokota 106042421Syokota for (i = 0; i < sizeof(name_table)/sizeof(name_table[0]); ++i) { 106142421Syokota if (type == name_table[i].type) 1062127752Sdes return (name_table[i].name); 106342421Syokota } 1064127752Sdes return ("unknown"); 106542421Syokota} 106642421Syokota 106742421Syokotavoid 106842421Syokotagenkbd_diag(keyboard_t *kbd, int level) 106942421Syokota{ 107042421Syokota if (level > 0) { 1071127751Sdes printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x", 1072127751Sdes kbd->kb_index, kbd->kb_name, kbd->kb_unit, 1073127751Sdes get_kbd_type_name(kbd->kb_type), kbd->kb_type, 1074127751Sdes kbd->kb_config, kbd->kb_flags); 107542421Syokota if (kbd->kb_io_base > 0) 1076127751Sdes printf(", port:0x%x-0x%x", kbd->kb_io_base, 1077127751Sdes kbd->kb_io_base + kbd->kb_io_size - 1); 107842421Syokota printf("\n"); 107942421Syokota } 108042421Syokota} 108142421Syokota 108242421Syokota#define set_lockkey_state(k, s, l) \ 108342421Syokota if (!((s) & l ## DOWN)) { \ 108442421Syokota int i; \ 108542421Syokota (s) |= l ## DOWN; \ 108642421Syokota (s) ^= l ## ED; \ 108742421Syokota i = (s) & LOCK_MASK; \ 108842421Syokota (*kbdsw[(k)->kb_index]->ioctl)((k), KDSETLED, (caddr_t)&i); \ 108942421Syokota } 109042421Syokota 109142421Syokotastatic u_int 109242421Syokotasave_accent_key(keyboard_t *kbd, u_int key, int *accents) 109342421Syokota{ 109442421Syokota int i; 109542421Syokota 109642421Syokota /* make an index into the accent map */ 109742421Syokota i = key - F_ACC + 1; 109842421Syokota if ((i > kbd->kb_accentmap->n_accs) 109942421Syokota || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) { 110042421Syokota /* the index is out of range or pointing to an empty entry */ 110142421Syokota *accents = 0; 1102127752Sdes return (ERRKEY); 110342421Syokota } 110442421Syokota 1105127751Sdes /* 1106127751Sdes * If the same accent key has been hit twice, produce the accent 1107127751Sdes * char itself. 110842421Syokota */ 110942421Syokota if (i == *accents) { 111042421Syokota key = kbd->kb_accentmap->acc[i - 1].accchar; 111142421Syokota *accents = 0; 1112127752Sdes return (key); 111342421Syokota } 111442421Syokota 111542421Syokota /* remember the index and wait for the next key */ 1116127751Sdes *accents = i; 1117127752Sdes return (NOKEY); 111842421Syokota} 111942421Syokota 112042421Syokotastatic u_int 112142421Syokotamake_accent_char(keyboard_t *kbd, u_int ch, int *accents) 112242421Syokota{ 112342421Syokota struct acc_t *acc; 112442421Syokota int i; 112542421Syokota 112642421Syokota acc = &kbd->kb_accentmap->acc[*accents - 1]; 112742421Syokota *accents = 0; 112842421Syokota 1129127751Sdes /* 113042421Syokota * If the accent key is followed by the space key, 113142421Syokota * produce the accent char itself. 113242421Syokota */ 113342421Syokota if (ch == ' ') 1134127752Sdes return (acc->accchar); 113542421Syokota 113642421Syokota /* scan the accent map */ 113742421Syokota for (i = 0; i < NUM_ACCENTCHARS; ++i) { 113842421Syokota if (acc->map[i][0] == 0) /* end of table */ 113942421Syokota break; 114042421Syokota if (acc->map[i][0] == ch) 1141127752Sdes return (acc->map[i][1]); 114242421Syokota } 114342421Syokota /* this char cannot be accented... */ 1144127752Sdes return (ERRKEY); 114542421Syokota} 114642421Syokota 114742421Syokotaint 114842421Syokotagenkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate, 114942421Syokota int *accents) 115042421Syokota{ 115142421Syokota struct keyent_t *key; 115242421Syokota int state = *shiftstate; 115342421Syokota int action; 115442421Syokota int f; 115542421Syokota int i; 115642421Syokota 115754382Syokota i = keycode; 115842421Syokota f = state & (AGRS | ALKED); 115942421Syokota if ((f == AGRS1) || (f == AGRS2) || (f == ALKED)) 116054382Syokota i += ALTGR_OFFSET; 116154382Syokota key = &kbd->kb_keymap->key[i]; 116242421Syokota i = ((state & SHIFTS) ? 1 : 0) 116342421Syokota | ((state & CTLS) ? 2 : 0) 116442421Syokota | ((state & ALTS) ? 4 : 0); 116542421Syokota if (((key->flgs & FLAG_LOCK_C) && (state & CLKED)) 116642421Syokota || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) ) 116742421Syokota i ^= 1; 116842421Syokota 116942421Syokota if (up) { /* break: key released */ 117080040Syokota action = kbd->kb_lastact[keycode]; 117180040Syokota kbd->kb_lastact[keycode] = NOP; 117280040Syokota switch (action) { 117380040Syokota case LSHA: 117480040Syokota if (state & SHIFTAON) { 117580040Syokota set_lockkey_state(kbd, state, ALK); 117680040Syokota state &= ~ALKDOWN; 117780040Syokota } 117880040Syokota action = LSH; 117980040Syokota /* FALL THROUGH */ 118080040Syokota case LSH: 118180040Syokota state &= ~SHIFTS1; 118280040Syokota break; 118380040Syokota case RSHA: 118480040Syokota if (state & SHIFTAON) { 118580040Syokota set_lockkey_state(kbd, state, ALK); 118680040Syokota state &= ~ALKDOWN; 118780040Syokota } 118880040Syokota action = RSH; 118980040Syokota /* FALL THROUGH */ 119080040Syokota case RSH: 119180040Syokota state &= ~SHIFTS2; 119280040Syokota break; 119380040Syokota case LCTRA: 119480040Syokota if (state & SHIFTAON) { 119580040Syokota set_lockkey_state(kbd, state, ALK); 119680040Syokota state &= ~ALKDOWN; 119780040Syokota } 119880040Syokota action = LCTR; 119980040Syokota /* FALL THROUGH */ 120080040Syokota case LCTR: 120180040Syokota state &= ~CTLS1; 120280040Syokota break; 120380040Syokota case RCTRA: 120480040Syokota if (state & SHIFTAON) { 120580040Syokota set_lockkey_state(kbd, state, ALK); 120680040Syokota state &= ~ALKDOWN; 120780040Syokota } 120880040Syokota action = RCTR; 120980040Syokota /* FALL THROUGH */ 121080040Syokota case RCTR: 121180040Syokota state &= ~CTLS2; 121280040Syokota break; 121380040Syokota case LALTA: 121480040Syokota if (state & SHIFTAON) { 121580040Syokota set_lockkey_state(kbd, state, ALK); 121680040Syokota state &= ~ALKDOWN; 121780040Syokota } 121880040Syokota action = LALT; 121980040Syokota /* FALL THROUGH */ 122080040Syokota case LALT: 122180040Syokota state &= ~ALTS1; 122280040Syokota break; 122380040Syokota case RALTA: 122480040Syokota if (state & SHIFTAON) { 122580040Syokota set_lockkey_state(kbd, state, ALK); 122680040Syokota state &= ~ALKDOWN; 122780040Syokota } 122880040Syokota action = RALT; 122980040Syokota /* FALL THROUGH */ 123080040Syokota case RALT: 123180040Syokota state &= ~ALTS2; 123280040Syokota break; 123380040Syokota case ASH: 123480040Syokota state &= ~AGRS1; 123580040Syokota break; 123680040Syokota case META: 123780040Syokota state &= ~METAS1; 123880040Syokota break; 123980040Syokota case NLK: 124080040Syokota state &= ~NLKDOWN; 124180040Syokota break; 124280040Syokota case CLK: 124342421Syokota#ifndef PC98 124480040Syokota state &= ~CLKDOWN; 124542421Syokota#else 124680040Syokota state &= ~CLKED; 124780040Syokota i = state & LOCK_MASK; 124880040Syokota (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED, 124980040Syokota (caddr_t)&i); 125042421Syokota#endif 125180040Syokota break; 125280040Syokota case SLK: 125380040Syokota state &= ~SLKDOWN; 125480040Syokota break; 125580040Syokota case ALK: 125680040Syokota state &= ~ALKDOWN; 125780040Syokota break; 125880040Syokota case NOP: 125980040Syokota /* release events of regular keys are not reported */ 126080040Syokota *shiftstate &= ~SHIFTAON; 1261127752Sdes return (NOKEY); 126242421Syokota } 126380040Syokota *shiftstate = state & ~SHIFTAON; 126480040Syokota return (SPCLKEY | RELKEY | action); 126542421Syokota } else { /* make: key pressed */ 126680040Syokota action = key->map[i]; 126755820Syokota state &= ~SHIFTAON; 126842421Syokota if (key->spcl & (0x80 >> i)) { 126942421Syokota /* special keys */ 127080040Syokota if (kbd->kb_lastact[keycode] == NOP) 127180040Syokota kbd->kb_lastact[keycode] = action; 127280040Syokota if (kbd->kb_lastact[keycode] != action) 127380040Syokota action = NOP; 127442421Syokota switch (action) { 127542421Syokota /* LOCKING KEYS */ 127642421Syokota case NLK: 127742421Syokota set_lockkey_state(kbd, state, NLK); 127842421Syokota break; 127942421Syokota case CLK: 128042421Syokota#ifndef PC98 128142421Syokota set_lockkey_state(kbd, state, CLK); 128242421Syokota#else 128342421Syokota state |= CLKED; 128442421Syokota i = state & LOCK_MASK; 128542421Syokota (*kbdsw[kbd->kb_index]->ioctl)(kbd, KDSETLED, 128642421Syokota (caddr_t)&i); 128742421Syokota#endif 128842421Syokota break; 128942421Syokota case SLK: 129042421Syokota set_lockkey_state(kbd, state, SLK); 129142421Syokota break; 129242421Syokota case ALK: 129342421Syokota set_lockkey_state(kbd, state, ALK); 129442421Syokota break; 129542421Syokota /* NON-LOCKING KEYS */ 129642421Syokota case SPSC: case RBT: case SUSP: case STBY: 129754382Syokota case DBG: case NEXT: case PREV: case PNC: 129865759Sdwmalone case HALT: case PDWN: 129942421Syokota *accents = 0; 130042421Syokota break; 130142421Syokota case BTAB: 130242421Syokota *accents = 0; 130342421Syokota action |= BKEY; 130442421Syokota break; 130554382Syokota case LSHA: 130655820Syokota state |= SHIFTAON; 130754382Syokota action = LSH; 130854382Syokota /* FALL THROUGH */ 130942421Syokota case LSH: 131042421Syokota state |= SHIFTS1; 131142421Syokota break; 131254382Syokota case RSHA: 131355820Syokota state |= SHIFTAON; 131454382Syokota action = RSH; 131554382Syokota /* FALL THROUGH */ 131642421Syokota case RSH: 131742421Syokota state |= SHIFTS2; 131842421Syokota break; 131954382Syokota case LCTRA: 132055820Syokota state |= SHIFTAON; 132154382Syokota action = LCTR; 132254382Syokota /* FALL THROUGH */ 132342421Syokota case LCTR: 132442421Syokota state |= CTLS1; 132542421Syokota break; 132654382Syokota case RCTRA: 132755820Syokota state |= SHIFTAON; 132854382Syokota action = RCTR; 132954382Syokota /* FALL THROUGH */ 133042421Syokota case RCTR: 133142421Syokota state |= CTLS2; 133242421Syokota break; 133354382Syokota case LALTA: 133455820Syokota state |= SHIFTAON; 133554382Syokota action = LALT; 133654382Syokota /* FALL THROUGH */ 133742421Syokota case LALT: 133842421Syokota state |= ALTS1; 133942421Syokota break; 134054382Syokota case RALTA: 134155820Syokota state |= SHIFTAON; 134254382Syokota action = RALT; 134354382Syokota /* FALL THROUGH */ 134442421Syokota case RALT: 134542421Syokota state |= ALTS2; 134642421Syokota break; 134742421Syokota case ASH: 134842421Syokota state |= AGRS1; 134942421Syokota break; 135042421Syokota case META: 135142421Syokota state |= METAS1; 135242421Syokota break; 135380040Syokota case NOP: 135480040Syokota *shiftstate = state; 1355127752Sdes return (NOKEY); 135642421Syokota default: 135742421Syokota /* is this an accent (dead) key? */ 135855820Syokota *shiftstate = state; 135942421Syokota if (action >= F_ACC && action <= L_ACC) { 136042421Syokota action = save_accent_key(kbd, action, 136142421Syokota accents); 136242421Syokota switch (action) { 136342421Syokota case NOKEY: 136442421Syokota case ERRKEY: 1365127752Sdes return (action); 136642421Syokota default: 136742421Syokota if (state & METAS) 136842421Syokota return (action | MKEY); 136942421Syokota else 1370127752Sdes return (action); 137142421Syokota } 137242421Syokota /* NOT REACHED */ 137342421Syokota } 137442421Syokota /* other special keys */ 137542421Syokota if (*accents > 0) { 137642421Syokota *accents = 0; 1377127752Sdes return (ERRKEY); 137842421Syokota } 137942421Syokota if (action >= F_FN && action <= L_FN) 138042421Syokota action |= FKEY; 138142421Syokota /* XXX: return fkey string for the FKEY? */ 138255820Syokota return (SPCLKEY | action); 138342421Syokota } 138442421Syokota *shiftstate = state; 138542421Syokota return (SPCLKEY | action); 138642421Syokota } else { 138742421Syokota /* regular keys */ 138880040Syokota kbd->kb_lastact[keycode] = NOP; 138955820Syokota *shiftstate = state; 139042421Syokota if (*accents > 0) { 139142421Syokota /* make an accented char */ 139242421Syokota action = make_accent_char(kbd, action, accents); 139342421Syokota if (action == ERRKEY) 1394127752Sdes return (action); 139542421Syokota } 139642421Syokota if (state & METAS) 139742421Syokota action |= MKEY; 1398127752Sdes return (action); 139942421Syokota } 140042421Syokota } 140142421Syokota /* NOT REACHED */ 140242421Syokota} 1403