From 41d278420730221a7cda91f1d2d273e1d91f0ab8 Mon Sep 17 00:00:00 2001 From: Kevin Kirspel Date: Wed, 17 May 2017 08:40:27 -0400 Subject: Add FREEBSD keyboard driver files --- freebsd/sys/dev/kbd/kbd.c | 1477 +++++++++++++++++++++++++++++++++++++++ freebsd/sys/dev/kbd/kbdreg.h | 307 ++++++++ freebsd/sys/dev/kbd/kbdtables.h | 238 +++++++ freebsd/sys/sys/kbio.h | 269 +++++++ 4 files changed, 2291 insertions(+) create mode 100644 freebsd/sys/dev/kbd/kbd.c create mode 100644 freebsd/sys/dev/kbd/kbdreg.h create mode 100644 freebsd/sys/dev/kbd/kbdtables.h create mode 100644 freebsd/sys/sys/kbio.h diff --git a/freebsd/sys/dev/kbd/kbd.c b/freebsd/sys/dev/kbd/kbd.c new file mode 100644 index 00000000..3505b29d --- /dev/null +++ b/freebsd/sys/dev/kbd/kbd.c @@ -0,0 +1,1477 @@ +#include + +/*- + * Copyright (c) 1999 Kazutaka YOKOTA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer as + * the first lines of this file unmodified. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#define KBD_INDEX(dev) dev2unit(dev) + +#define KB_QSIZE 512 +#define KB_BUFSIZE 64 + +typedef struct genkbd_softc { + int gkb_flags; /* flag/status bits */ +#define KB_ASLEEP (1 << 0) + struct selinfo gkb_rsel; + char gkb_q[KB_QSIZE]; /* input queue */ + unsigned int gkb_q_start; + unsigned int gkb_q_length; +} genkbd_softc_t; + +static SLIST_HEAD(, keyboard_driver) keyboard_drivers = + SLIST_HEAD_INITIALIZER(keyboard_drivers); + +SET_DECLARE(kbddriver_set, const keyboard_driver_t); + +/* local arrays */ + +/* + * We need at least one entry each in order to initialize a keyboard + * for the kernel console. The arrays will be increased dynamically + * when necessary. + */ + +static int keyboards = 1; +static keyboard_t *kbd_ini; +static keyboard_t **keyboard = &kbd_ini; +static keyboard_switch_t *kbdsw_ini; + keyboard_switch_t **kbdsw = &kbdsw_ini; + +static int keymap_restrict_change; +static SYSCTL_NODE(_hw, OID_AUTO, kbd, CTLFLAG_RD, 0, "kbd"); +SYSCTL_INT(_hw_kbd, OID_AUTO, keymap_restrict_change, CTLFLAG_RW, + &keymap_restrict_change, 0, "restrict ability to change keymap"); + +#define ARRAY_DELTA 4 + +static int +kbd_realloc_array(void) +{ + keyboard_t **new_kbd; + keyboard_switch_t **new_kbdsw; + int newsize; + int s; + + s = spltty(); + newsize = rounddown(keyboards + ARRAY_DELTA, ARRAY_DELTA); + new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT|M_ZERO); + if (new_kbd == NULL) { + splx(s); + return (ENOMEM); + } + new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF, + M_NOWAIT|M_ZERO); + if (new_kbdsw == NULL) { + free(new_kbd, M_DEVBUF); + splx(s); + return (ENOMEM); + } + bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards); + bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards); + if (keyboards > 1) { + free(keyboard, M_DEVBUF); + free(kbdsw, M_DEVBUF); + } + keyboard = new_kbd; + kbdsw = new_kbdsw; + keyboards = newsize; + splx(s); + + if (bootverbose) + printf("kbd: new array size %d\n", keyboards); + + return (0); +} + +/* + * Low-level keyboard driver functions + * Keyboard subdrivers, such as the AT keyboard driver and the USB keyboard + * driver, call these functions to initialize the keyboard_t structure + * and register it to the virtual keyboard driver `kbd'. + */ + +/* initialize the keyboard_t structure */ +void +kbd_init_struct(keyboard_t *kbd, char *name, int type, int unit, int config, + int port, int port_size) +{ + kbd->kb_flags = KB_NO_DEVICE; /* device has not been found */ + kbd->kb_name = name; + kbd->kb_type = type; + kbd->kb_unit = unit; + kbd->kb_config = config & ~KB_CONF_PROBE_ONLY; + kbd->kb_led = 0; /* unknown */ + kbd->kb_io_base = port; + kbd->kb_io_size = port_size; + kbd->kb_data = NULL; + kbd->kb_keymap = NULL; + kbd->kb_accentmap = NULL; + kbd->kb_fkeytab = NULL; + kbd->kb_fkeytab_size = 0; + kbd->kb_delay1 = KB_DELAY1; /* these values are advisory only */ + kbd->kb_delay2 = KB_DELAY2; + kbd->kb_count = 0L; + bzero(kbd->kb_lastact, sizeof(kbd->kb_lastact)); +} + +void +kbd_set_maps(keyboard_t *kbd, keymap_t *keymap, accentmap_t *accmap, + fkeytab_t *fkeymap, int fkeymap_size) +{ + kbd->kb_keymap = keymap; + kbd->kb_accentmap = accmap; + kbd->kb_fkeytab = fkeymap; + kbd->kb_fkeytab_size = fkeymap_size; +} + +/* declare a new keyboard driver */ +int +kbd_add_driver(keyboard_driver_t *driver) +{ + if (SLIST_NEXT(driver, link)) + return (EINVAL); + SLIST_INSERT_HEAD(&keyboard_drivers, driver, link); + return (0); +} + +int +kbd_delete_driver(keyboard_driver_t *driver) +{ + SLIST_REMOVE(&keyboard_drivers, driver, keyboard_driver, link); + SLIST_NEXT(driver, link) = NULL; + return (0); +} + +/* register a keyboard and associate it with a function table */ +int +kbd_register(keyboard_t *kbd) +{ + const keyboard_driver_t **list; + const keyboard_driver_t *p; + keyboard_t *mux; + keyboard_info_t ki; + int index; + + mux = kbd_get_keyboard(kbd_find_keyboard("kbdmux", -1)); + + for (index = 0; index < keyboards; ++index) { + if (keyboard[index] == NULL) + break; + } + if (index >= keyboards) { + if (kbd_realloc_array()) + return (-1); + } + + kbd->kb_index = index; + KBD_UNBUSY(kbd); + KBD_VALID(kbd); + kbd->kb_active = 0; /* disabled until someone calls kbd_enable() */ + kbd->kb_token = NULL; + kbd->kb_callback.kc_func = NULL; + kbd->kb_callback.kc_arg = NULL; + + SLIST_FOREACH(p, &keyboard_drivers, link) { + if (strcmp(p->name, kbd->kb_name) == 0) { + keyboard[index] = kbd; + kbdsw[index] = p->kbdsw; + + if (mux != NULL) { + bzero(&ki, sizeof(ki)); + strcpy(ki.kb_name, kbd->kb_name); + ki.kb_unit = kbd->kb_unit; + + (void)kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki); + } + + return (index); + } + } + SET_FOREACH(list, kbddriver_set) { + p = *list; + if (strcmp(p->name, kbd->kb_name) == 0) { + keyboard[index] = kbd; + kbdsw[index] = p->kbdsw; + + if (mux != NULL) { + bzero(&ki, sizeof(ki)); + strcpy(ki.kb_name, kbd->kb_name); + ki.kb_unit = kbd->kb_unit; + + (void)kbdd_ioctl(mux, KBADDKBD, (caddr_t) &ki); + } + + return (index); + } + } + + return (-1); +} + +int +kbd_unregister(keyboard_t *kbd) +{ + int error; + int s; + + if ((kbd->kb_index < 0) || (kbd->kb_index >= keyboards)) + return (ENOENT); + if (keyboard[kbd->kb_index] != kbd) + return (ENOENT); + + s = spltty(); + if (KBD_IS_BUSY(kbd)) { + error = (*kbd->kb_callback.kc_func)(kbd, KBDIO_UNLOADING, + kbd->kb_callback.kc_arg); + if (error) { + splx(s); + return (error); + } + if (KBD_IS_BUSY(kbd)) { + splx(s); + return (EBUSY); + } + } + KBD_INVALID(kbd); + keyboard[kbd->kb_index] = NULL; + kbdsw[kbd->kb_index] = NULL; + + splx(s); + return (0); +} + +/* find a function table by the driver name */ +keyboard_switch_t * +kbd_get_switch(char *driver) +{ + const keyboard_driver_t **list; + const keyboard_driver_t *p; + + SLIST_FOREACH(p, &keyboard_drivers, link) { + if (strcmp(p->name, driver) == 0) + return (p->kbdsw); + } + SET_FOREACH(list, kbddriver_set) { + p = *list; + if (strcmp(p->name, driver) == 0) + return (p->kbdsw); + } + + return (NULL); +} + +/* + * Keyboard client functions + * Keyboard clients, such as the console driver `syscons' and the keyboard + * cdev driver, use these functions to claim and release a keyboard for + * exclusive use. + */ + +/* + * find the keyboard specified by a driver name and a unit number + * starting at given index + */ +int +kbd_find_keyboard2(char *driver, int unit, int index) +{ + int i; + + if ((index < 0) || (index >= keyboards)) + return (-1); + + for (i = index; i < keyboards; ++i) { + if (keyboard[i] == NULL) + continue; + if (!KBD_IS_VALID(keyboard[i])) + continue; + if (strcmp("*", driver) && strcmp(keyboard[i]->kb_name, driver)) + continue; + if ((unit != -1) && (keyboard[i]->kb_unit != unit)) + continue; + return (i); + } + + return (-1); +} + +/* find the keyboard specified by a driver name and a unit number */ +int +kbd_find_keyboard(char *driver, int unit) +{ + return (kbd_find_keyboard2(driver, unit, 0)); +} + +/* allocate a keyboard */ +int +kbd_allocate(char *driver, int unit, void *id, kbd_callback_func_t *func, + void *arg) +{ + int index; + int s; + + if (func == NULL) + return (-1); + + s = spltty(); + index = kbd_find_keyboard(driver, unit); + if (index >= 0) { + if (KBD_IS_BUSY(keyboard[index])) { + splx(s); + return (-1); + } + keyboard[index]->kb_token = id; + KBD_BUSY(keyboard[index]); + keyboard[index]->kb_callback.kc_func = func; + keyboard[index]->kb_callback.kc_arg = arg; + kbdd_clear_state(keyboard[index]); + } + splx(s); + return (index); +} + +int +kbd_release(keyboard_t *kbd, void *id) +{ + int error; + int s; + + s = spltty(); + if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { + error = EINVAL; + } else if (kbd->kb_token != id) { + error = EPERM; + } else { + kbd->kb_token = NULL; + KBD_UNBUSY(kbd); + kbd->kb_callback.kc_func = NULL; + kbd->kb_callback.kc_arg = NULL; + kbdd_clear_state(kbd); + error = 0; + } + splx(s); + return (error); +} + +int +kbd_change_callback(keyboard_t *kbd, void *id, kbd_callback_func_t *func, + void *arg) +{ + int error; + int s; + + s = spltty(); + if (!KBD_IS_VALID(kbd) || !KBD_IS_BUSY(kbd)) { + error = EINVAL; + } else if (kbd->kb_token != id) { + error = EPERM; + } else if (func == NULL) { + error = EINVAL; + } else { + kbd->kb_callback.kc_func = func; + kbd->kb_callback.kc_arg = arg; + error = 0; + } + splx(s); + return (error); +} + +/* get a keyboard structure */ +keyboard_t * +kbd_get_keyboard(int index) +{ + if ((index < 0) || (index >= keyboards)) + return (NULL); + if (keyboard[index] == NULL) + return (NULL); + if (!KBD_IS_VALID(keyboard[index])) + return (NULL); + return (keyboard[index]); +} + +/* + * The back door for the console driver; configure keyboards + * This function is for the kernel console to initialize keyboards + * at very early stage. + */ + +int +kbd_configure(int flags) +{ + const keyboard_driver_t **list; + const keyboard_driver_t *p; + + SLIST_FOREACH(p, &keyboard_drivers, link) { + if (p->configure != NULL) + (*p->configure)(flags); + } + SET_FOREACH(list, kbddriver_set) { + p = *list; + if (p->configure != NULL) + (*p->configure)(flags); + } + + return (0); +} + +#ifdef KBD_INSTALL_CDEV + +/* + * Virtual keyboard cdev driver functions + * The virtual keyboard driver dispatches driver functions to + * appropriate subdrivers. + */ + +#define KBD_UNIT(dev) dev2unit(dev) + +static d_open_t genkbdopen; +static d_close_t genkbdclose; +static d_read_t genkbdread; +static d_write_t genkbdwrite; +static d_ioctl_t genkbdioctl; +static d_poll_t genkbdpoll; + + +static struct cdevsw kbd_cdevsw = { + .d_version = D_VERSION, + .d_flags = D_NEEDGIANT, + .d_open = genkbdopen, + .d_close = genkbdclose, + .d_read = genkbdread, + .d_write = genkbdwrite, + .d_ioctl = genkbdioctl, + .d_poll = genkbdpoll, + .d_name = "kbd", +}; + +int +kbd_attach(keyboard_t *kbd) +{ + + if (kbd->kb_index >= keyboards) + return (EINVAL); + if (keyboard[kbd->kb_index] != kbd) + return (EINVAL); + + kbd->kb_dev = make_dev(&kbd_cdevsw, kbd->kb_index, UID_ROOT, GID_WHEEL, + 0600, "%s%r", kbd->kb_name, kbd->kb_unit); + make_dev_alias(kbd->kb_dev, "kbd%r", kbd->kb_index); + kbd->kb_dev->si_drv1 = malloc(sizeof(genkbd_softc_t), M_DEVBUF, + M_WAITOK | M_ZERO); + printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit); + return (0); +} + +int +kbd_detach(keyboard_t *kbd) +{ + + if (kbd->kb_index >= keyboards) + return (EINVAL); + if (keyboard[kbd->kb_index] != kbd) + return (EINVAL); + + free(kbd->kb_dev->si_drv1, M_DEVBUF); + destroy_dev(kbd->kb_dev); + + return (0); +} + +/* + * Generic keyboard cdev driver functions + * Keyboard subdrivers may call these functions to implement common + * driver functions. + */ + +static void +genkbd_putc(genkbd_softc_t *sc, char c) +{ + unsigned int p; + + if (sc->gkb_q_length == KB_QSIZE) + return; + + p = (sc->gkb_q_start + sc->gkb_q_length) % KB_QSIZE; + sc->gkb_q[p] = c; + sc->gkb_q_length++; +} + +static size_t +genkbd_getc(genkbd_softc_t *sc, char *buf, size_t len) +{ + + /* Determine copy size. */ + if (sc->gkb_q_length == 0) + return (0); + if (len >= sc->gkb_q_length) + len = sc->gkb_q_length; + if (len >= KB_QSIZE - sc->gkb_q_start) + len = KB_QSIZE - sc->gkb_q_start; + + /* Copy out data and progress offset. */ + memcpy(buf, sc->gkb_q + sc->gkb_q_start, len); + sc->gkb_q_start = (sc->gkb_q_start + len) % KB_QSIZE; + sc->gkb_q_length -= len; + + return (len); +} + +static kbd_callback_func_t genkbd_event; + +static int +genkbdopen(struct cdev *dev, int mode, int flag, struct thread *td) +{ + keyboard_t *kbd; + genkbd_softc_t *sc; + int s; + int i; + + s = spltty(); + sc = dev->si_drv1; + kbd = kbd_get_keyboard(KBD_INDEX(dev)); + if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { + splx(s); + return (ENXIO); + } + i = kbd_allocate(kbd->kb_name, kbd->kb_unit, sc, + genkbd_event, (void *)sc); + if (i < 0) { + splx(s); + return (EBUSY); + } + /* assert(i == kbd->kb_index) */ + /* assert(kbd == kbd_get_keyboard(i)) */ + + /* + * NOTE: even when we have successfully claimed a keyboard, + * the device may still be missing (!KBD_HAS_DEVICE(kbd)). + */ + + sc->gkb_q_length = 0; + splx(s); + + return (0); +} + +static int +genkbdclose(struct cdev *dev, int mode, int flag, struct thread *td) +{ + keyboard_t *kbd; + genkbd_softc_t *sc; + int s; + + /* + * NOTE: the device may have already become invalid. + * kbd == NULL || !KBD_IS_VALID(kbd) + */ + s = spltty(); + sc = dev->si_drv1; + kbd = kbd_get_keyboard(KBD_INDEX(dev)); + if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { + /* XXX: we shall be forgiving and don't report error... */ + } else { + kbd_release(kbd, (void *)sc); + } + splx(s); + return (0); +} + +static int +genkbdread(struct cdev *dev, struct uio *uio, int flag) +{ + keyboard_t *kbd; + genkbd_softc_t *sc; + u_char buffer[KB_BUFSIZE]; + int len; + int error; + int s; + + /* wait for input */ + s = spltty(); + sc = dev->si_drv1; + kbd = kbd_get_keyboard(KBD_INDEX(dev)); + if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { + splx(s); + return (ENXIO); + } + while (sc->gkb_q_length == 0) { + if (flag & O_NONBLOCK) { + splx(s); + return (EWOULDBLOCK); + } + sc->gkb_flags |= KB_ASLEEP; + error = tsleep(sc, PZERO | PCATCH, "kbdrea", 0); + kbd = kbd_get_keyboard(KBD_INDEX(dev)); + if ((kbd == NULL) || !KBD_IS_VALID(kbd)) { + splx(s); + return (ENXIO); /* our keyboard has gone... */ + } + if (error) { + sc->gkb_flags &= ~KB_ASLEEP; + splx(s); + return (error); + } + } + splx(s); + + /* copy as much input as possible */ + error = 0; + while (uio->uio_resid > 0) { + len = imin(uio->uio_resid, sizeof(buffer)); + len = genkbd_getc(sc, buffer, len); + if (len <= 0) + break; + error = uiomove(buffer, len, uio); + if (error) + break; + } + + return (error); +} + +static int +genkbdwrite(struct cdev *dev, struct uio *uio, int flag) +{ + keyboard_t *kbd; + + kbd = kbd_get_keyboard(KBD_INDEX(dev)); + if ((kbd == NULL) || !KBD_IS_VALID(kbd)) + return (ENXIO); + return (ENODEV); +} + +static int +genkbdioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, struct thread *td) +{ + keyboard_t *kbd; + int error; + + kbd = kbd_get_keyboard(KBD_INDEX(dev)); + if ((kbd == NULL) || !KBD_IS_VALID(kbd)) + return (ENXIO); + error = kbdd_ioctl(kbd, cmd, arg); + if (error == ENOIOCTL) + error = ENODEV; + return (error); +} + +static int +genkbdpoll(struct cdev *dev, int events, struct thread *td) +{ + keyboard_t *kbd; + genkbd_softc_t *sc; + int revents; + int s; + + revents = 0; + s = spltty(); + sc = dev->si_drv1; + kbd = kbd_get_keyboard(KBD_INDEX(dev)); + if ((sc == NULL) || (kbd == NULL) || !KBD_IS_VALID(kbd)) { + revents = POLLHUP; /* the keyboard has gone */ + } else if (events & (POLLIN | POLLRDNORM)) { + if (sc->gkb_q_length > 0) + revents = events & (POLLIN | POLLRDNORM); + else + selrecord(td, &sc->gkb_rsel); + } + splx(s); + return (revents); +} + +static int +genkbd_event(keyboard_t *kbd, int event, void *arg) +{ + genkbd_softc_t *sc; + size_t len; + u_char *cp; + int mode; + u_int c; + + /* assert(KBD_IS_VALID(kbd)) */ + sc = (genkbd_softc_t *)arg; + + switch (event) { + case KBDIO_KEYINPUT: + break; + case KBDIO_UNLOADING: + /* the keyboard is going... */ + kbd_release(kbd, (void *)sc); + if (sc->gkb_flags & KB_ASLEEP) { + sc->gkb_flags &= ~KB_ASLEEP; + wakeup(sc); + } + selwakeuppri(&sc->gkb_rsel, PZERO); + return (0); + default: + return (EINVAL); + } + + /* obtain the current key input mode */ + if (kbdd_ioctl(kbd, KDGKBMODE, (caddr_t)&mode)) + mode = K_XLATE; + + /* read all pending input */ + while (kbdd_check_char(kbd)) { + c = kbdd_read_char(kbd, FALSE); + if (c == NOKEY) + continue; + if (c == ERRKEY) /* XXX: ring bell? */ + continue; + if (!KBD_IS_BUSY(kbd)) + /* the device is not open, discard the input */ + continue; + + /* store the byte as is for K_RAW and K_CODE modes */ + if (mode != K_XLATE) { + genkbd_putc(sc, KEYCHAR(c)); + continue; + } + + /* K_XLATE */ + if (c & RELKEY) /* key release is ignored */ + continue; + + /* process special keys; most of them are just ignored... */ + if (c & SPCLKEY) { + switch (KEYCHAR(c)) { + default: + /* ignore them... */ + continue; + case BTAB: /* a backtab: ESC [ Z */ + genkbd_putc(sc, 0x1b); + genkbd_putc(sc, '['); + genkbd_putc(sc, 'Z'); + continue; + } + } + + /* normal chars, normal chars with the META, function keys */ + switch (KEYFLAGS(c)) { + case 0: /* a normal char */ + genkbd_putc(sc, KEYCHAR(c)); + break; + case MKEY: /* the META flag: prepend ESC */ + genkbd_putc(sc, 0x1b); + genkbd_putc(sc, KEYCHAR(c)); + break; + case FKEY | SPCLKEY: /* a function key, return string */ + cp = kbdd_get_fkeystr(kbd, KEYCHAR(c), &len); + if (cp != NULL) { + while (len-- > 0) + genkbd_putc(sc, *cp++); + } + break; + } + } + + /* wake up sleeping/polling processes */ + if (sc->gkb_q_length > 0) { + if (sc->gkb_flags & KB_ASLEEP) { + sc->gkb_flags &= ~KB_ASLEEP; + wakeup(sc); + } + selwakeuppri(&sc->gkb_rsel, PZERO); + } + + return (0); +} + +#endif /* KBD_INSTALL_CDEV */ + +/* + * Generic low-level keyboard functions + * The low-level functions in the keyboard subdriver may use these + * functions. + */ + +#ifndef KBD_DISABLE_KEYMAP_LOAD +static int key_change_ok(struct keyent_t *, struct keyent_t *, struct thread *); +static int keymap_change_ok(keymap_t *, keymap_t *, struct thread *); +static int accent_change_ok(accentmap_t *, accentmap_t *, struct thread *); +static int fkey_change_ok(fkeytab_t *, fkeyarg_t *, struct thread *); +#endif + +int +genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) +{ + keymap_t *mapp; + okeymap_t *omapp; + keyarg_t *keyp; + fkeyarg_t *fkeyp; + int s; + int i, j; + int error; + + s = spltty(); + switch (cmd) { + + case KDGKBINFO: /* get keyboard information */ + ((keyboard_info_t *)arg)->kb_index = kbd->kb_index; + i = imin(strlen(kbd->kb_name) + 1, + sizeof(((keyboard_info_t *)arg)->kb_name)); + bcopy(kbd->kb_name, ((keyboard_info_t *)arg)->kb_name, i); + ((keyboard_info_t *)arg)->kb_unit = kbd->kb_unit; + ((keyboard_info_t *)arg)->kb_type = kbd->kb_type; + ((keyboard_info_t *)arg)->kb_config = kbd->kb_config; + ((keyboard_info_t *)arg)->kb_flags = kbd->kb_flags; + break; + + case KDGKBTYPE: /* get keyboard type */ + *(int *)arg = kbd->kb_type; + break; + + case KDGETREPEAT: /* get keyboard repeat rate */ + ((int *)arg)[0] = kbd->kb_delay1; + ((int *)arg)[1] = kbd->kb_delay2; + break; + + case GIO_KEYMAP: /* get keyboard translation table */ + error = copyout(kbd->kb_keymap, *(void **)arg, + sizeof(keymap_t)); + splx(s); + return (error); + case OGIO_KEYMAP: /* get keyboard translation table (compat) */ + mapp = kbd->kb_keymap; + omapp = (okeymap_t *)arg; + omapp->n_keys = mapp->n_keys; + for (i = 0; i < NUM_KEYS; i++) { + for (j = 0; j < NUM_STATES; j++) + omapp->key[i].map[j] = + mapp->key[i].map[j]; + omapp->key[i].spcl = mapp->key[i].spcl; + omapp->key[i].flgs = mapp->key[i].flgs; + } + break; + case PIO_KEYMAP: /* set keyboard translation table */ + case OPIO_KEYMAP: /* set keyboard translation table (compat) */ +#ifndef KBD_DISABLE_KEYMAP_LOAD + mapp = malloc(sizeof *mapp, M_TEMP, M_WAITOK); + if (cmd == OPIO_KEYMAP) { + omapp = (okeymap_t *)arg; + mapp->n_keys = omapp->n_keys; + for (i = 0; i < NUM_KEYS; i++) { + for (j = 0; j < NUM_STATES; j++) + mapp->key[i].map[j] = + omapp->key[i].map[j]; + mapp->key[i].spcl = omapp->key[i].spcl; + mapp->key[i].flgs = omapp->key[i].flgs; + } + } else { + error = copyin(*(void **)arg, mapp, sizeof *mapp); + if (error != 0) { + splx(s); + free(mapp, M_TEMP); + return (error); + } + } + + error = keymap_change_ok(kbd->kb_keymap, mapp, curthread); + if (error != 0) { + splx(s); + free(mapp, M_TEMP); + return (error); + } + bzero(kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); + bcopy(mapp, kbd->kb_keymap, sizeof(*kbd->kb_keymap)); + free(mapp, M_TEMP); + break; +#else + splx(s); + return (ENODEV); +#endif + + case GIO_KEYMAPENT: /* get keyboard translation table entry */ + keyp = (keyarg_t *)arg; + if (keyp->keynum >= sizeof(kbd->kb_keymap->key) / + sizeof(kbd->kb_keymap->key[0])) { + splx(s); + return (EINVAL); + } + bcopy(&kbd->kb_keymap->key[keyp->keynum], &keyp->key, + sizeof(keyp->key)); + break; + case PIO_KEYMAPENT: /* set keyboard translation table entry */ +#ifndef KBD_DISABLE_KEYMAP_LOAD + keyp = (keyarg_t *)arg; + if (keyp->keynum >= sizeof(kbd->kb_keymap->key) / + sizeof(kbd->kb_keymap->key[0])) { + splx(s); + return (EINVAL); + } + error = key_change_ok(&kbd->kb_keymap->key[keyp->keynum], + &keyp->key, curthread); + if (error != 0) { + splx(s); + return (error); + } + bcopy(&keyp->key, &kbd->kb_keymap->key[keyp->keynum], + sizeof(keyp->key)); + break; +#else + splx(s); + return (ENODEV); +#endif + + case GIO_DEADKEYMAP: /* get accent key translation table */ + bcopy(kbd->kb_accentmap, arg, sizeof(*kbd->kb_accentmap)); + break; + case PIO_DEADKEYMAP: /* set accent key translation table */ +#ifndef KBD_DISABLE_KEYMAP_LOAD + error = accent_change_ok(kbd->kb_accentmap, + (accentmap_t *)arg, curthread); + if (error != 0) { + splx(s); + return (error); + } + bcopy(arg, kbd->kb_accentmap, sizeof(*kbd->kb_accentmap)); + break; +#else + splx(s); + return (ENODEV); +#endif + + case GETFKEY: /* get functionkey string */ + fkeyp = (fkeyarg_t *)arg; + if (fkeyp->keynum >= kbd->kb_fkeytab_size) { + splx(s); + return (EINVAL); + } + bcopy(kbd->kb_fkeytab[fkeyp->keynum].str, fkeyp->keydef, + kbd->kb_fkeytab[fkeyp->keynum].len); + fkeyp->flen = kbd->kb_fkeytab[fkeyp->keynum].len; + break; + case SETFKEY: /* set functionkey string */ +#ifndef KBD_DISABLE_KEYMAP_LOAD + fkeyp = (fkeyarg_t *)arg; + if (fkeyp->keynum >= kbd->kb_fkeytab_size) { + splx(s); + return (EINVAL); + } + error = fkey_change_ok(&kbd->kb_fkeytab[fkeyp->keynum], + fkeyp, curthread); + if (error != 0) { + splx(s); + return (error); + } + kbd->kb_fkeytab[fkeyp->keynum].len = min(fkeyp->flen, MAXFK); + bcopy(fkeyp->keydef, kbd->kb_fkeytab[fkeyp->keynum].str, + kbd->kb_fkeytab[fkeyp->keynum].len); + break; +#else + splx(s); + return (ENODEV); +#endif + + default: + splx(s); + return (ENOIOCTL); + } + + splx(s); + return (0); +} + +#ifndef KBD_DISABLE_KEYMAP_LOAD +#define RESTRICTED_KEY(key, i) \ + ((key->spcl & (0x80 >> i)) && \ + (key->map[i] == RBT || key->map[i] == SUSP || \ + key->map[i] == STBY || key->map[i] == DBG || \ + key->map[i] == PNC || key->map[i] == HALT || \ + key->map[i] == PDWN)) + +static int +key_change_ok(struct keyent_t *oldkey, struct keyent_t *newkey, struct thread *td) +{ + int i; + + /* Low keymap_restrict_change means any changes are OK. */ + if (keymap_restrict_change <= 0) + return (0); + + /* High keymap_restrict_change means only root can change the keymap. */ + if (keymap_restrict_change >= 2) { + for (i = 0; i < NUM_STATES; i++) + if (oldkey->map[i] != newkey->map[i]) + return priv_check(td, PRIV_KEYBOARD); + if (oldkey->spcl != newkey->spcl) + return priv_check(td, PRIV_KEYBOARD); + if (oldkey->flgs != newkey->flgs) + return priv_check(td, PRIV_KEYBOARD); + return (0); + } + + /* Otherwise we have to see if any special keys are being changed. */ + for (i = 0; i < NUM_STATES; i++) { + /* + * If either the oldkey or the newkey action is restricted + * then we must make sure that the action doesn't change. + */ + if (!RESTRICTED_KEY(oldkey, i) && !RESTRICTED_KEY(newkey, i)) + continue; + if ((oldkey->spcl & (0x80 >> i)) == (newkey->spcl & (0x80 >> i)) + && oldkey->map[i] == newkey->map[i]) + continue; + return priv_check(td, PRIV_KEYBOARD); + } + + return (0); +} + +static int +keymap_change_ok(keymap_t *oldmap, keymap_t *newmap, struct thread *td) +{ + int keycode, error; + + for (keycode = 0; keycode < NUM_KEYS; keycode++) { + if ((error = key_change_ok(&oldmap->key[keycode], + &newmap->key[keycode], td)) != 0) + return (error); + } + return (0); +} + +static int +accent_change_ok(accentmap_t *oldmap, accentmap_t *newmap, struct thread *td) +{ + struct acc_t *oldacc, *newacc; + int accent, i; + + if (keymap_restrict_change <= 2) + return (0); + + if (oldmap->n_accs != newmap->n_accs) + return priv_check(td, PRIV_KEYBOARD); + + for (accent = 0; accent < oldmap->n_accs; accent++) { + oldacc = &oldmap->acc[accent]; + newacc = &newmap->acc[accent]; + if (oldacc->accchar != newacc->accchar) + return priv_check(td, PRIV_KEYBOARD); + for (i = 0; i < NUM_ACCENTCHARS; ++i) { + if (oldacc->map[i][0] != newacc->map[i][0]) + return priv_check(td, PRIV_KEYBOARD); + if (oldacc->map[i][0] == 0) /* end of table */ + break; + if (oldacc->map[i][1] != newacc->map[i][1]) + return priv_check(td, PRIV_KEYBOARD); + } + } + + return (0); +} + +static int +fkey_change_ok(fkeytab_t *oldkey, fkeyarg_t *newkey, struct thread *td) +{ + if (keymap_restrict_change <= 3) + return (0); + + if (oldkey->len != newkey->flen || + bcmp(oldkey->str, newkey->keydef, oldkey->len) != 0) + return priv_check(td, PRIV_KEYBOARD); + + return (0); +} +#endif + +/* get a pointer to the string associated with the given function key */ +u_char * +genkbd_get_fkeystr(keyboard_t *kbd, int fkey, size_t *len) +{ + if (kbd == NULL) + return (NULL); + fkey -= F_FN; + if (fkey > kbd->kb_fkeytab_size) + return (NULL); + *len = kbd->kb_fkeytab[fkey].len; + return (kbd->kb_fkeytab[fkey].str); +} + +/* diagnostic dump */ +static char * +get_kbd_type_name(int type) +{ + static struct { + int type; + char *name; + } name_table[] = { + { KB_84, "AT 84" }, + { KB_101, "AT 101/102" }, + { KB_OTHER, "generic" }, + }; + int i; + + for (i = 0; i < nitems(name_table); ++i) { + if (type == name_table[i].type) + return (name_table[i].name); + } + return ("unknown"); +} + +void +genkbd_diag(keyboard_t *kbd, int level) +{ + if (level > 0) { + printf("kbd%d: %s%d, %s (%d), config:0x%x, flags:0x%x", + kbd->kb_index, kbd->kb_name, kbd->kb_unit, + get_kbd_type_name(kbd->kb_type), kbd->kb_type, + kbd->kb_config, kbd->kb_flags); + if (kbd->kb_io_base > 0) + printf(", port:0x%x-0x%x", kbd->kb_io_base, + kbd->kb_io_base + kbd->kb_io_size - 1); + printf("\n"); + } +} + +#define set_lockkey_state(k, s, l) \ + if (!((s) & l ## DOWN)) { \ + int i; \ + (s) |= l ## DOWN; \ + (s) ^= l ## ED; \ + i = (s) & LOCK_MASK; \ + (void)kbdd_ioctl((k), KDSETLED, (caddr_t)&i); \ + } + +static u_int +save_accent_key(keyboard_t *kbd, u_int key, int *accents) +{ + int i; + + /* make an index into the accent map */ + i = key - F_ACC + 1; + if ((i > kbd->kb_accentmap->n_accs) + || (kbd->kb_accentmap->acc[i - 1].accchar == 0)) { + /* the index is out of range or pointing to an empty entry */ + *accents = 0; + return (ERRKEY); + } + + /* + * If the same accent key has been hit twice, produce the accent + * char itself. + */ + if (i == *accents) { + key = kbd->kb_accentmap->acc[i - 1].accchar; + *accents = 0; + return (key); + } + + /* remember the index and wait for the next key */ + *accents = i; + return (NOKEY); +} + +static u_int +make_accent_char(keyboard_t *kbd, u_int ch, int *accents) +{ + struct acc_t *acc; + int i; + + acc = &kbd->kb_accentmap->acc[*accents - 1]; + *accents = 0; + + /* + * If the accent key is followed by the space key, + * produce the accent char itself. + */ + if (ch == ' ') + return (acc->accchar); + + /* scan the accent map */ + for (i = 0; i < NUM_ACCENTCHARS; ++i) { + if (acc->map[i][0] == 0) /* end of table */ + break; + if (acc->map[i][0] == ch) + return (acc->map[i][1]); + } + /* this char cannot be accented... */ + return (ERRKEY); +} + +int +genkbd_keyaction(keyboard_t *kbd, int keycode, int up, int *shiftstate, + int *accents) +{ + struct keyent_t *key; + int state = *shiftstate; + int action; + int f; + int i; + + i = keycode; + f = state & (AGRS | ALKED); + if ((f == AGRS1) || (f == AGRS2) || (f == ALKED)) + i += ALTGR_OFFSET; + key = &kbd->kb_keymap->key[i]; + i = ((state & SHIFTS) ? 1 : 0) + | ((state & CTLS) ? 2 : 0) + | ((state & ALTS) ? 4 : 0); + if (((key->flgs & FLAG_LOCK_C) && (state & CLKED)) + || ((key->flgs & FLAG_LOCK_N) && (state & NLKED)) ) + i ^= 1; + + if (up) { /* break: key released */ + action = kbd->kb_lastact[keycode]; + kbd->kb_lastact[keycode] = NOP; + switch (action) { + case LSHA: + if (state & SHIFTAON) { + set_lockkey_state(kbd, state, ALK); + state &= ~ALKDOWN; + } + action = LSH; + /* FALL THROUGH */ + case LSH: + state &= ~SHIFTS1; + break; + case RSHA: + if (state & SHIFTAON) { + set_lockkey_state(kbd, state, ALK); + state &= ~ALKDOWN; + } + action = RSH; + /* FALL THROUGH */ + case RSH: + state &= ~SHIFTS2; + break; + case LCTRA: + if (state & SHIFTAON) { + set_lockkey_state(kbd, state, ALK); + state &= ~ALKDOWN; + } + action = LCTR; + /* FALL THROUGH */ + case LCTR: + state &= ~CTLS1; + break; + case RCTRA: + if (state & SHIFTAON) { + set_lockkey_state(kbd, state, ALK); + state &= ~ALKDOWN; + } + action = RCTR; + /* FALL THROUGH */ + case RCTR: + state &= ~CTLS2; + break; + case LALTA: + if (state & SHIFTAON) { + set_lockkey_state(kbd, state, ALK); + state &= ~ALKDOWN; + } + action = LALT; + /* FALL THROUGH */ + case LALT: + state &= ~ALTS1; + break; + case RALTA: + if (state & SHIFTAON) { + set_lockkey_state(kbd, state, ALK); + state &= ~ALKDOWN; + } + action = RALT; + /* FALL THROUGH */ + case RALT: + state &= ~ALTS2; + break; + case ASH: + state &= ~AGRS1; + break; + case META: + state &= ~METAS1; + break; + case NLK: + state &= ~NLKDOWN; + break; + case CLK: + state &= ~CLKDOWN; + break; + case SLK: + state &= ~SLKDOWN; + break; + case ALK: + state &= ~ALKDOWN; + break; + case NOP: + /* release events of regular keys are not reported */ + *shiftstate &= ~SHIFTAON; + return (NOKEY); + } + *shiftstate = state & ~SHIFTAON; + return (SPCLKEY | RELKEY | action); + } else { /* make: key pressed */ + action = key->map[i]; + state &= ~SHIFTAON; + if (key->spcl & (0x80 >> i)) { + /* special keys */ + if (kbd->kb_lastact[keycode] == NOP) + kbd->kb_lastact[keycode] = action; + if (kbd->kb_lastact[keycode] != action) + action = NOP; + switch (action) { + /* LOCKING KEYS */ + case NLK: + set_lockkey_state(kbd, state, NLK); + break; + case CLK: + set_lockkey_state(kbd, state, CLK); + break; + case SLK: + set_lockkey_state(kbd, state, SLK); + break; + case ALK: + set_lockkey_state(kbd, state, ALK); + break; + /* NON-LOCKING KEYS */ + case SPSC: case RBT: case SUSP: case STBY: + case DBG: case NEXT: case PREV: case PNC: + case HALT: case PDWN: + *accents = 0; + break; + case BTAB: + *accents = 0; + action |= BKEY; + break; + case LSHA: + state |= SHIFTAON; + action = LSH; + /* FALL THROUGH */ + case LSH: + state |= SHIFTS1; + break; + case RSHA: + state |= SHIFTAON; + action = RSH; + /* FALL THROUGH */ + case RSH: + state |= SHIFTS2; + break; + case LCTRA: + state |= SHIFTAON; + action = LCTR; + /* FALL THROUGH */ + case LCTR: + state |= CTLS1; + break; + case RCTRA: + state |= SHIFTAON; + action = RCTR; + /* FALL THROUGH */ + case RCTR: + state |= CTLS2; + break; + case LALTA: + state |= SHIFTAON; + action = LALT; + /* FALL THROUGH */ + case LALT: + state |= ALTS1; + break; + case RALTA: + state |= SHIFTAON; + action = RALT; + /* FALL THROUGH */ + case RALT: + state |= ALTS2; + break; + case ASH: + state |= AGRS1; + break; + case META: + state |= METAS1; + break; + case NOP: + *shiftstate = state; + return (NOKEY); + default: + /* is this an accent (dead) key? */ + *shiftstate = state; + if (action >= F_ACC && action <= L_ACC) { + action = save_accent_key(kbd, action, + accents); + switch (action) { + case NOKEY: + case ERRKEY: + return (action); + default: + if (state & METAS) + return (action | MKEY); + else + return (action); + } + /* NOT REACHED */ + } + /* other special keys */ + if (*accents > 0) { + *accents = 0; + return (ERRKEY); + } + if (action >= F_FN && action <= L_FN) + action |= FKEY; + /* XXX: return fkey string for the FKEY? */ + return (SPCLKEY | action); + } + *shiftstate = state; + return (SPCLKEY | action); + } else { + /* regular keys */ + kbd->kb_lastact[keycode] = NOP; + *shiftstate = state; + if (*accents > 0) { + /* make an accented char */ + action = make_accent_char(kbd, action, accents); + if (action == ERRKEY) + return (action); + } + if (state & METAS) + action |= MKEY; + return (action); + } + } + /* NOT REACHED */ +} diff --git a/freebsd/sys/dev/kbd/kbdreg.h b/freebsd/sys/dev/kbd/kbdreg.h new file mode 100644 index 00000000..ff4a694b --- /dev/null +++ b/freebsd/sys/dev/kbd/kbdreg.h @@ -0,0 +1,307 @@ +/*- + * Copyright (c) 1999 Kazutaka YOKOTA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer as + * the first lines of this file unmodified. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _DEV_KBD_KBDREG_H_ +#define _DEV_KBD_KBDREG_H_ + +/* forward declarations */ +typedef struct keyboard keyboard_t; +struct keymap; +struct accentmap; +struct fkeytab; +struct cdevsw; + +/* call back funcion */ +typedef int kbd_callback_func_t(keyboard_t *kbd, int event, + void *arg); +/* event types */ +#define KBDIO_KEYINPUT 0 +#define KBDIO_UNLOADING 1 + +typedef struct keyboard_callback { + kbd_callback_func_t *kc_func; + void *kc_arg; +} keyboard_callback_t; + +/* keyboard */ +struct keyboard { + /* the following fields are managed by kbdio */ + int kb_index; /* kbdio index# */ + int kb_minor; /* minor number of the sub-device */ + int kb_flags; /* internal flags */ +#define KB_VALID (1 << 16) /* this entry is valid */ +#define KB_NO_DEVICE (1 << 17) /* device not present */ +#define KB_PROBED (1 << 18) /* device probed */ +#define KB_INITIALIZED (1 << 19) /* device initialized */ +#define KB_REGISTERED (1 << 20) /* device registered to kbdio */ +#define KB_BUSY (1 << 21) /* device used by a client */ +#define KB_POLLED (1 << 22) /* device is polled */ + int kb_active; /* 0: inactive */ + void *kb_token; /* id of the current client */ + keyboard_callback_t kb_callback;/* callback function */ + + /* + * Device configuration flags: + * The upper 16 bits are common between various keyboard devices. + * The lower 16 bits are device-specific. + */ + int kb_config; +#define KB_CONF_PROBE_ONLY (1 << 16) /* probe only, don't initialize */ + + /* the following fields are set up by the driver */ + char *kb_name; /* driver name */ + int kb_unit; /* unit # */ + int kb_type; /* KB_84, KB_101, KB_OTHER,... */ + int kb_io_base; /* port# if any */ + int kb_io_size; /* # of occupied port */ + int kb_led; /* LED status */ + struct keymap *kb_keymap; /* key map */ + struct accentmap *kb_accentmap; /* accent map */ + struct fkeytab *kb_fkeytab; /* function key strings */ + int kb_fkeytab_size;/* # of function key strings */ + void *kb_data; /* the driver's private data */ + int kb_delay1; + int kb_delay2; +#define KB_DELAY1 500 +#define KB_DELAY2 100 + unsigned long kb_count; /* # of processed key strokes */ + u_char kb_lastact[NUM_KEYS/2]; + struct cdev *kb_dev; +}; + +#define KBD_IS_VALID(k) ((k)->kb_flags & KB_VALID) +#define KBD_VALID(k) ((k)->kb_flags |= KB_VALID) +#define KBD_INVALID(k) ((k)->kb_flags &= ~KB_VALID) +#define KBD_HAS_DEVICE(k) (!((k)->kb_flags & KB_NO_DEVICE)) +#define KBD_FOUND_DEVICE(k) ((k)->kb_flags &= ~KB_NO_DEVICE) +#define KBD_IS_PROBED(k) ((k)->kb_flags & KB_PROBED) +#define KBD_PROBE_DONE(k) ((k)->kb_flags |= KB_PROBED) +#define KBD_IS_INITIALIZED(k) ((k)->kb_flags & KB_INITIALIZED) +#define KBD_INIT_DONE(k) ((k)->kb_flags |= KB_INITIALIZED) +#define KBD_IS_CONFIGURED(k) ((k)->kb_flags & KB_REGISTERED) +#define KBD_CONFIG_DONE(k) ((k)->kb_flags |= KB_REGISTERED) +#define KBD_IS_BUSY(k) ((k)->kb_flags & KB_BUSY) +#define KBD_BUSY(k) ((k)->kb_flags |= KB_BUSY) +#define KBD_UNBUSY(k) ((k)->kb_flags &= ~KB_BUSY) +#define KBD_IS_POLLED(k) ((k)->kb_flags & KB_POLLED) +#define KBD_POLL(k) ((k)->kb_flags |= KB_POLLED) +#define KBD_UNPOLL(k) ((k)->kb_flags &= ~KB_POLLED) +#define KBD_IS_ACTIVE(k) ((k)->kb_active) +#define KBD_ACTIVATE(k) (++(k)->kb_active) +#define KBD_DEACTIVATE(k) (--(k)->kb_active) +#define KBD_LED_VAL(k) ((k)->kb_led) + +/* keyboard function table */ +typedef int kbd_probe_t(int unit, void *arg, int flags); +typedef int kbd_init_t(int unit, keyboard_t **kbdp, void *arg, + int flags); +typedef int kbd_term_t(keyboard_t *kbd); +typedef int kbd_intr_t(keyboard_t *kbd, void *arg); +typedef int kbd_test_if_t(keyboard_t *kbd); +typedef int kbd_enable_t(keyboard_t *kbd); +typedef int kbd_disable_t(keyboard_t *kbd); +typedef int kbd_read_t(keyboard_t *kbd, int wait); +typedef int kbd_check_t(keyboard_t *kbd); +typedef u_int kbd_read_char_t(keyboard_t *kbd, int wait); +typedef int kbd_check_char_t(keyboard_t *kbd); +typedef int kbd_ioctl_t(keyboard_t *kbd, u_long cmd, caddr_t data); +typedef int kbd_lock_t(keyboard_t *kbd, int lock); +typedef void kbd_clear_state_t(keyboard_t *kbd); +typedef int kbd_get_state_t(keyboard_t *kbd, void *buf, size_t len); +typedef int kbd_set_state_t(keyboard_t *kbd, void *buf, size_t len); +typedef u_char *kbd_get_fkeystr_t(keyboard_t *kbd, int fkey, + size_t *len); +typedef int kbd_poll_mode_t(keyboard_t *kbd, int on); +typedef void kbd_diag_t(keyboard_t *kbd, int level); + +typedef struct keyboard_switch { + kbd_probe_t *probe; + kbd_init_t *init; + kbd_term_t *term; + kbd_intr_t *intr; + kbd_test_if_t *test_if; + kbd_enable_t *enable; + kbd_disable_t *disable; + kbd_read_t *read; + kbd_check_t *check; + kbd_read_char_t *read_char; + kbd_check_char_t *check_char; + kbd_ioctl_t *ioctl; + kbd_lock_t *lock; + kbd_clear_state_t *clear_state; + kbd_get_state_t *get_state; + kbd_set_state_t *set_state; + kbd_get_fkeystr_t *get_fkeystr; + kbd_poll_mode_t *poll; + kbd_diag_t *diag; +} keyboard_switch_t; + +/* + * Keyboard disciplines: call actual handlers via kbdsw[]. + */ +#define kbdd_probe(kbd, unit, arg, flags) \ + (*kbdsw[(kbd)->kb_index]->probe)((unit), (arg), (flags)) +#define kbdd_init(kbd, unit, kbdpp, arg, flags) \ + (*kbdsw[(kbd)->kb_index]->init)((unit), (kbdpp), (arg), (flags)) +#define kbdd_term(kbd) \ + (*kbdsw[(kbd)->kb_index]->term)((kbd)) +#define kbdd_intr(kbd, arg) \ + (*kbdsw[(kbd)->kb_index]->intr)((kbd), (arg)) +#define kbdd_test_if(kbd) \ + (*kbdsw[(kbd)->kb_index]->test_if)((kbd)) +#define kbdd_enable(kbd) \ + (*kbdsw[(kbd)->kb_index]->enable)((kbd)) +#define kbdd_disable(kbd) \ + (*kbdsw[(kbd)->kb_index]->disable)((kbd)) +#define kbdd_read(kbd, wait) \ + (*kbdsw[(kbd)->kb_index]->read)((kbd), (wait)) +#define kbdd_check(kbd) \ + (*kbdsw[(kbd)->kb_index]->check)((kbd)) +#define kbdd_read_char(kbd, wait) \ + (*kbdsw[(kbd)->kb_index]->read_char)((kbd), (wait)) +#define kbdd_check_char(kbd) \ + (*kbdsw[(kbd)->kb_index]->check_char)((kbd)) +#define kbdd_ioctl(kbd, cmd, arg) \ + (((kbd) == NULL) ? \ + ENODEV : \ + (*kbdsw[(kbd)->kb_index]->ioctl)((kbd), (cmd), (arg))) +#define kbdd_lock(kbd, lockf) \ + (*kbdsw[(kbd)->kb_index]->lock)((kbd), (lockf)) +#define kbdd_clear_state(kbd) \ + (*kbdsw[(kbd)->kb_index]->clear_state)((kbd)) +#define kbdd_get_state(kbd, buf, len) \ + (*kbdsw[(kbd)->kb_index]->get_state)((kbd), (buf), (len)) +#define kbdd_set_state(kbd, buf, len) \ + (*kbdsw[(kbd)->kb_index]->set_state)((kbd), (buf), (len)) +#define kbdd_get_fkeystr(kbd, fkey, len) \ + (*kbdsw[(kbd)->kb_index]->get_fkeystr)((kbd), (fkey), (len)) +#define kbdd_poll(kbd, on) \ + (*kbdsw[(kbd)->kb_index]->poll)((kbd), (on)) +#define kbdd_diag(kbd, level) \ + (*kbdsw[(kbd)->kb_index]->diag)((kbd), (leve)) + +/* keyboard driver */ +typedef struct keyboard_driver { + SLIST_ENTRY(keyboard_driver) link; + char *name; + keyboard_switch_t *kbdsw; + int (*configure)(int); /* backdoor for the console driver */ +} keyboard_driver_t; + +#ifdef _KERNEL + +#define KEYBOARD_DRIVER(name, sw, config) \ + static struct keyboard_driver name##_kbd_driver = { \ + { NULL }, #name, &sw, config \ + }; \ + DATA_SET(kbddriver_set, name##_kbd_driver); + +/* global variables */ +extern keyboard_switch_t **kbdsw; + +/* functions for the keyboard driver */ +int kbd_add_driver(keyboard_driver_t *driver); +int kbd_delete_driver(keyboard_driver_t *driver); +int kbd_register(keyboard_t *kbd); +int kbd_unregister(keyboard_t *kbd); +keyboard_switch_t *kbd_get_switch(char *driver); +void kbd_init_struct(keyboard_t *kbd, char *name, int type, + int unit, int config, int port, + int port_size); +void kbd_set_maps(keyboard_t *kbd, struct keymap *keymap, + struct accentmap *accmap, + struct fkeytab *fkeymap, int fkeymap_size); + +/* functions for the keyboard client */ +int kbd_allocate(char *driver, int unit, void *id, + kbd_callback_func_t *func, void *arg); +int kbd_release(keyboard_t *kbd, void *id); +int kbd_change_callback(keyboard_t *kbd, void *id, + kbd_callback_func_t *func, void *arg); +int kbd_find_keyboard(char *driver, int unit); +int kbd_find_keyboard2(char *driver, int unit, int index); +keyboard_t *kbd_get_keyboard(int index); + +/* a back door for the console driver to tickle the keyboard driver XXX */ +int kbd_configure(int flags); + /* see `kb_config' above for flag bit definitions */ + +#ifdef KBD_INSTALL_CDEV + +/* virtual keyboard cdev driver functions */ +int kbd_attach(keyboard_t *kbd); +int kbd_detach(keyboard_t *kbd); + +#endif /* KBD_INSTALL_CDEV */ + +/* generic low-level keyboard functions */ + +/* shift key state */ +#define SHIFTS1 (1 << 16) +#define SHIFTS2 (1 << 17) +#define SHIFTS (SHIFTS1 | SHIFTS2) +#define CTLS1 (1 << 18) +#define CTLS2 (1 << 19) +#define CTLS (CTLS1 | CTLS2) +#define ALTS1 (1 << 20) +#define ALTS2 (1 << 21) +#define ALTS (ALTS1 | ALTS2) +#define AGRS1 (1 << 22) +#define AGRS2 (1 << 23) +#define AGRS (AGRS1 | AGRS2) +#define METAS1 (1 << 24) +#define METAS2 (1 << 25) +#define METAS (METAS1 | METAS2) +#define NLKDOWN (1 << 26) +#define SLKDOWN (1 << 27) +#define CLKDOWN (1 << 28) +#define ALKDOWN (1 << 29) +#define SHIFTAON (1 << 30) +/* lock key state (defined in sys/kbio.h) */ +/* +#define CLKED LED_CAP +#define NLKED LED_NUM +#define SLKED LED_SCR +#define ALKED (1 << 3) +#define LOCK_MASK (CLKED | NLKED | SLKED | ALKED) +#define LED_CAP (1 << 0) +#define LED_NUM (1 << 1) +#define LED_SCR (1 << 2) +#define LED_MASK (LED_CAP | LED_NUM | LED_SCR) +*/ + +kbd_get_fkeystr_t genkbd_get_fkeystr; +kbd_diag_t genkbd_diag; + +int genkbd_commonioctl(keyboard_t *kbd, u_long cmd, caddr_t arg); +int genkbd_keyaction(keyboard_t *kbd, int keycode, int up, + int *shiftstate, int *accents); + +#endif /* _KERNEL */ + +#endif /* !_DEV_KBD_KBDREG_H_ */ diff --git a/freebsd/sys/dev/kbd/kbdtables.h b/freebsd/sys/dev/kbd/kbdtables.h new file mode 100644 index 00000000..5ff744c0 --- /dev/null +++ b/freebsd/sys/dev/kbd/kbdtables.h @@ -0,0 +1,238 @@ +/*- + * Copyright (c) 1992-1998 Sen Schmidt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification, immediately at the beginning of the file. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef KBD_DFLT_KEYMAP + +/* US iso8859 */ +#define ISO_ACCENTCHARS +/* + * Automatically generated from /usr/share/syscons/keymaps/us.iso.kbd. + * DO NOT EDIT! + */ +static keymap_t key_map = { 0x6d, { +/* alt + * scan cntrl alt alt cntrl + * code base shift cntrl shift alt shift cntrl shift spcl flgs + * --------------------------------------------------------------------------- + */ +/*00*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 }, +/*01*/{{ 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B, DBG, 0x1B, }, 0x02,0x00 }, +/*02*/{{ '1', '!', NOP, NOP, '1', '!', NOP, NOP, }, 0x33,0x00 }, +/*03*/{{ '2', '@', 0x00, 0x00, '2', '@', 0x00, 0x00, }, 0x00,0x00 }, +/*04*/{{ '3', '#', NOP, NOP, '3', '#', NOP, NOP, }, 0x33,0x00 }, +/*05*/{{ '4', '$', NOP, NOP, '4', '$', NOP, NOP, }, 0x33,0x00 }, +/*06*/{{ '5', '%', NOP, NOP, '5', '%', NOP, NOP, }, 0x33,0x00 }, +/*07*/{{ '6', '^', 0x1E, 0x1E, '6', '^', 0x1E, 0x1E, }, 0x00,0x00 }, +/*08*/{{ '7', '&', NOP, NOP, '7', '&', NOP, NOP, }, 0x33,0x00 }, +/*09*/{{ '8', '*', NOP, NOP, '8', '*', NOP, NOP, }, 0x33,0x00 }, +/*0a*/{{ '9', '(', NOP, NOP, '9', '(', NOP, NOP, }, 0x33,0x00 }, +/*0b*/{{ '0', ')', NOP, NOP, '0', ')', NOP, NOP, }, 0x33,0x00 }, +/*0c*/{{ '-', '_', 0x1F, 0x1F, '-', '_', 0x1F, 0x1F, }, 0x00,0x00 }, +/*0d*/{{ '=', '+', NOP, NOP, '=', '+', NOP, NOP, }, 0x33,0x00 }, +/*0e*/{{ 0x08, 0x08, 0x7F, 0x7F, 0x08, 0x08, 0x7F, 0x7F, }, 0x00,0x00 }, +/*0f*/{{ 0x09, BTAB, NOP, NOP, 0x09, BTAB, NOP, NOP, }, 0x77,0x00 }, +/*10*/{{ 'q', 'Q', 0x11, 0x11, 'q', 'Q', 0x11, 0x11, }, 0x00,0x01 }, +/*11*/{{ 'w', 'W', 0x17, 0x17, 'w', 'W', 0x17, 0x17, }, 0x00,0x01 }, +/*12*/{{ 'e', 'E', 0x05, 0x05, 'e', 'E', 0x05, 0x05, }, 0x00,0x01 }, +/*13*/{{ 'r', 'R', 0x12, 0x12, 'r', 'R', 0x12, 0x12, }, 0x00,0x01 }, +/*14*/{{ 't', 'T', 0x14, 0x14, 't', 'T', 0x14, 0x14, }, 0x00,0x01 }, +/*15*/{{ 'y', 'Y', 0x19, 0x19, 'y', 'Y', 0x19, 0x19, }, 0x00,0x01 }, +/*16*/{{ 'u', 'U', 0x15, 0x15, 'u', 'U', 0x15, 0x15, }, 0x00,0x01 }, +/*17*/{{ 'i', 'I', 0x09, 0x09, 'i', 'I', 0x09, 0x09, }, 0x00,0x01 }, +/*18*/{{ 'o', 'O', 0x0F, 0x0F, 'o', 'O', 0x0F, 0x0F, }, 0x00,0x01 }, +/*19*/{{ 'p', 'P', 0x10, 0x10, 'p', 'P', 0x10, 0x10, }, 0x00,0x01 }, +/*1a*/{{ '[', '{', 0x1B, 0x1B, '[', '{', 0x1B, 0x1B, }, 0x00,0x00 }, +/*1b*/{{ ']', '}', 0x1D, 0x1D, ']', '}', 0x1D, 0x1D, }, 0x00,0x00 }, +/*1c*/{{ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, }, 0x00,0x00 }, +/*1d*/{{ LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, LCTR, }, 0xFF,0x00 }, +/*1e*/{{ 'a', 'A', 0x01, 0x01, 'a', 'A', 0x01, 0x01, }, 0x00,0x01 }, +/*1f*/{{ 's', 'S', 0x13, 0x13, 's', 'S', 0x13, 0x13, }, 0x00,0x01 }, +/*20*/{{ 'd', 'D', 0x04, 0x04, 'd', 'D', 0x04, 0x04, }, 0x00,0x01 }, +/*21*/{{ 'f', 'F', 0x06, 0x06, 'f', 'F', 0x06, 0x06, }, 0x00,0x01 }, +/*22*/{{ 'g', 'G', 0x07, 0x07, 'g', 'G', 0x07, 0x07, }, 0x00,0x01 }, +/*23*/{{ 'h', 'H', 0x08, 0x08, 'h', 'H', 0x08, 0x08, }, 0x00,0x01 }, +/*24*/{{ 'j', 'J', 0x0A, 0x0A, 'j', 'J', 0x0A, 0x0A, }, 0x00,0x01 }, +/*25*/{{ 'k', 'K', 0x0B, 0x0B, 'k', 'K', 0x0B, 0x0B, }, 0x00,0x01 }, +/*26*/{{ 'l', 'L', 0x0C, 0x0C, 'l', 'L', 0x0C, 0x0C, }, 0x00,0x01 }, +/*27*/{{ ';', ':', NOP, NOP, ';', ':', NOP, NOP, }, 0x33,0x00 }, +/*28*/{{ '\'', '"', NOP, NOP, '\'', '"', NOP, NOP, }, 0x33,0x00 }, +/*29*/{{ '`', '~', NOP, NOP, '`', '~', NOP, NOP, }, 0x33,0x00 }, +/*2a*/{{ LSH, LSH, LSH, LSH, LSH, LSH, LSH, LSH, }, 0xFF,0x00 }, +/*2b*/{{ '\\', '|', 0x1C, 0x1C, '\\', '|', 0x1C, 0x1C, }, 0x00,0x00 }, +/*2c*/{{ 'z', 'Z', 0x1A, 0x1A, 'z', 'Z', 0x1A, 0x1A, }, 0x00,0x01 }, +/*2d*/{{ 'x', 'X', 0x18, 0x18, 'x', 'X', 0x18, 0x18, }, 0x00,0x01 }, +/*2e*/{{ 'c', 'C', 0x03, 0x03, 'c', 'C', 0x03, 0x03, }, 0x00,0x01 }, +/*2f*/{{ 'v', 'V', 0x16, 0x16, 'v', 'V', 0x16, 0x16, }, 0x00,0x01 }, +/*30*/{{ 'b', 'B', 0x02, 0x02, 'b', 'B', 0x02, 0x02, }, 0x00,0x01 }, +/*31*/{{ 'n', 'N', 0x0E, 0x0E, 'n', 'N', 0x0E, 0x0E, }, 0x00,0x01 }, +/*32*/{{ 'm', 'M', 0x0D, 0x0D, 'm', 'M', 0x0D, 0x0D, }, 0x00,0x01 }, +/*33*/{{ ',', '<', NOP, NOP, ',', '<', NOP, NOP, }, 0x33,0x00 }, +/*34*/{{ '.', '>', NOP, NOP, '.', '>', NOP, NOP, }, 0x33,0x00 }, +/*35*/{{ '/', '?', NOP, NOP, '/', '?', NOP, NOP, }, 0x33,0x00 }, +/*36*/{{ RSH, RSH, RSH, RSH, RSH, RSH, RSH, RSH, }, 0xFF,0x00 }, +/*37*/{{ '*', '*', '*', '*', '*', '*', '*', '*', }, 0x00,0x00 }, +/*38*/{{ LALT, LALT, LALT, LALT, LALT, LALT, LALT, LALT, }, 0xFF,0x00 }, +/*39*/{{ ' ', ' ', 0x00, ' ', ' ', ' ', SUSP, ' ', }, 0x02,0x00 }, +/*3a*/{{ CLK, CLK, CLK, CLK, CLK, CLK, CLK, CLK, }, 0xFF,0x00 }, +/*3b*/{{ F( 1), F(13), F(25), F(37), S( 1), S(11), S( 1), S(11),}, 0xFF,0x00 }, +/*3c*/{{ F( 2), F(14), F(26), F(38), S( 2), S(12), S( 2), S(12),}, 0xFF,0x00 }, +/*3d*/{{ F( 3), F(15), F(27), F(39), S( 3), S(13), S( 3), S(13),}, 0xFF,0x00 }, +/*3e*/{{ F( 4), F(16), F(28), F(40), S( 4), S(14), S( 4), S(14),}, 0xFF,0x00 }, +/*3f*/{{ F( 5), F(17), F(29), F(41), S( 5), S(15), S( 5), S(15),}, 0xFF,0x00 }, +/*40*/{{ F( 6), F(18), F(30), F(42), S( 6), S(16), S( 6), S(16),}, 0xFF,0x00 }, +/*41*/{{ F( 7), F(19), F(31), F(43), S( 7), S( 7), S( 7), S( 7),}, 0xFF,0x00 }, +/*42*/{{ F( 8), F(20), F(32), F(44), S( 8), S( 8), S( 8), S( 8),}, 0xFF,0x00 }, +/*43*/{{ F( 9), F(21), F(33), F(45), S( 9), S( 9), S( 9), S( 9),}, 0xFF,0x00 }, +/*44*/{{ F(10), F(22), F(34), F(46), S(10), S(10), S(10), S(10),}, 0xFF,0x00 }, +/*45*/{{ NLK, NLK, NLK, NLK, NLK, NLK, NLK, NLK, }, 0xFF,0x00 }, +/*46*/{{ SLK, SLK, SLK, SLK, SLK, SLK, SLK, SLK, }, 0xFF,0x00 }, +/*47*/{{ F(49), '7', '7', '7', '7', '7', '7', '7', }, 0x80,0x02 }, +/*48*/{{ F(50), '8', '8', '8', '8', '8', '8', '8', }, 0x80,0x02 }, +/*49*/{{ F(51), '9', '9', '9', '9', '9', '9', '9', }, 0x80,0x02 }, +/*4a*/{{ F(52), '-', '-', '-', '-', '-', '-', '-', }, 0x80,0x02 }, +/*4b*/{{ F(53), '4', '4', '4', '4', '4', '4', '4', }, 0x80,0x02 }, +/*4c*/{{ F(54), '5', '5', '5', '5', '5', '5', '5', }, 0x80,0x02 }, +/*4d*/{{ F(55), '6', '6', '6', '6', '6', '6', '6', }, 0x80,0x02 }, +/*4e*/{{ F(56), '+', '+', '+', '+', '+', '+', '+', }, 0x80,0x02 }, +/*4f*/{{ F(57), '1', '1', '1', '1', '1', '1', '1', }, 0x80,0x02 }, +/*50*/{{ F(58), '2', '2', '2', '2', '2', '2', '2', }, 0x80,0x02 }, +/*51*/{{ F(59), '3', '3', '3', '3', '3', '3', '3', }, 0x80,0x02 }, +/*52*/{{ F(60), '0', '0', '0', '0', '0', '0', '0', }, 0x80,0x02 }, +/*53*/{{ 0x7F, '.', '.', '.', '.', '.', RBT, RBT, }, 0x03,0x02 }, +/*54*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 }, +/*55*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 }, +/*56*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 }, +/*57*/{{ F(11), F(23), F(35), F(47), S(11), S(11), S(11), S(11),}, 0xFF,0x00 }, +/*58*/{{ F(12), F(24), F(36), F(48), S(12), S(12), S(12), S(12),}, 0xFF,0x00 }, +/*59*/{{ 0x0D, 0x0D, 0x0A, 0x0A, 0x0D, 0x0D, 0x0A, 0x0A, }, 0x00,0x00 }, +/*5a*/{{ RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, RCTR, }, 0xFF,0x00 }, +/*5b*/{{ '/', '/', '/', '/', '/', '/', '/', '/', }, 0x00,0x02 }, +/*5c*/{{ NEXT, PREV, DBG, DBG, NOP, NOP, NOP, NOP, }, 0xFF,0x00 }, +/*5d*/{{ RALT, RALT, RALT, RALT, RALT, RALT, RALT, RALT, }, 0xFF,0x00 }, +/*5e*/{{ F(49), F(49), F(49), F(49), F(49), F(49), F(49), F(49),}, 0xFF,0x00 }, +/*5f*/{{ F(50), F(50), F(50), F(50), F(50), F(50), F(50), F(50),}, 0xFF,0x00 }, +/*60*/{{ F(51), F(51), F(51), F(51), F(51), F(51), F(51), F(51),}, 0xFF,0x00 }, +/*61*/{{ F(53), F(53), F(53), F(53), F(53), F(53), F(53), F(53),}, 0xFF,0x00 }, +/*62*/{{ F(55), F(55), F(55), F(55), F(55), F(55), F(55), F(55),}, 0xFF,0x00 }, +/*63*/{{ F(57), F(57), F(57), F(57), F(57), F(57), F(57), F(57),}, 0xFF,0x00 }, +/*64*/{{ F(58), F(58), F(58), F(58), F(58), F(58), F(58), F(58),}, 0xFF,0x00 }, +/*65*/{{ F(59), F(59), F(59), F(59), F(59), F(59), F(59), F(59),}, 0xFF,0x00 }, +/*66*/{{ F(60),PASTE, F(60), F(60), F(60), F(60), F(60), F(60),}, 0xFF,0x00 }, +/*67*/{{ F(61), F(61), F(61), F(61), F(61), F(61), RBT, F(61),}, 0xFF,0x00 }, +/*68*/{{ SLK, SPSC, SLK, SPSC, SUSP, NOP, SUSP, NOP, }, 0xFF,0x00 }, +/*69*/{{ F(62), F(62), F(62), F(62), F(62), F(62), F(62), F(62),}, 0xFF,0x00 }, +/*6a*/{{ F(63), F(63), F(63), F(63), F(63), F(63), F(63), F(63),}, 0xFF,0x00 }, +/*6b*/{{ F(64), F(64), F(64), F(64), F(64), F(64), F(64), F(64),}, 0xFF,0x00 }, +/*6c*/{{ NOP, NOP, NOP, NOP, NOP, NOP, NOP, NOP, }, 0xFF,0x00 }, +} }; + +#if defined(NO_ACCENTCHARS) +static accentmap_t accent_map = { 0, /* empty accent map */ + { + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, { 0 }, + } +}; +#endif + +#if defined(ISO_ACCENTCHARS) +static accentmap_t accent_map = { 15, /* iso8859 accent map */ + { + /* dgra=0 */ + { '`', { { 'a',0xe0 }, { 'A',0xc0 }, { 'e',0xe8 }, { 'E',0xc8 }, + { 'i',0xec }, { 'I',0xcc }, { 'o',0xf2 }, { 'O',0xd2 }, + { 'u',0xf9 }, { 'U',0xd9 }, }, }, + /* dacu=1 */ + { 0xb4, { { 'a',0xe1 }, { 'A',0xc1 }, { 'e',0xe9 }, { 'E',0xc9 }, + { 'i',0xed }, { 'I',0xcd }, { 'o',0xf3 }, { 'O',0xd3 }, + { 'u',0xfa }, { 'U',0xda }, { 'y',0xfd }, { 'Y',0xdd }, }, }, + /* dcir=2 */ + { '^', { { 'a',0xe2 }, { 'A',0xc2 }, { 'e',0xea }, { 'E',0xca }, + { 'i',0xee }, { 'I',0xce }, { 'o',0xf4 }, { 'O',0xd4 }, + { 'u',0xfb }, { 'U',0xdb }, }, }, + /* dtil=3 */ + { '~', { { 'a',0xe3 }, { 'A',0xc3 }, { 'n',0xf1 }, { 'N',0xd1 }, + { 'o',0xf5 }, { 'O',0xd5 }, }, }, + /* dmac=4 */ + { 0 }, + /* dbre=5 */ + { 0 }, + /* ddot=6 */ + { 0 }, + /* duml=7 */ + { 0xa8, { { 'a',0xe4 }, { 'A',0xc4 }, { 'e',0xeb }, { 'E',0xcb }, + { 'i',0xef }, { 'I',0xcf }, { 'o',0xf6 }, { 'O',0xd6 }, + { 'u',0xfc }, { 'U',0xdc }, { 'y',0xff }, }, }, + /* dsla=8 */ + { 0 }, + /* drin=9 */ + { 0xb0, { { 'a',0xe5 }, { 'A',0xc5 }, }, }, + /* dced=10 */ + { 0xb8, { { 'c',0xe7 }, { 'C',0xc7 }, }, }, + /* dapo=11 */ + { 0 }, + /* ddac=12 */ + { 0 }, + /* dogo=13 */ + { 0 }, + /* dcar=14 */ + { 0 }, + } +}; +#endif /* ISO_ACCENTCHARS */ + +#endif /* !KBD_DFLT_KEYMAP */ + +static fkeytab_t fkey_tab[96] = { +/* 01-04 */ {"\033[M", 3}, {"\033[N", 3}, {"\033[O", 3}, {"\033[P", 3}, +/* 05-08 */ {"\033[Q", 3}, {"\033[R", 3}, {"\033[S", 3}, {"\033[T", 3}, +/* 09-12 */ {"\033[U", 3}, {"\033[V", 3}, {"\033[W", 3}, {"\033[X", 3}, +/* 13-16 */ {"\033[Y", 3}, {"\033[Z", 3}, {"\033[a", 3}, {"\033[b", 3}, +/* 17-20 */ {"\033[c", 3}, {"\033[d", 3}, {"\033[e", 3}, {"\033[f", 3}, +/* 21-24 */ {"\033[g", 3}, {"\033[h", 3}, {"\033[i", 3}, {"\033[j", 3}, +/* 25-28 */ {"\033[k", 3}, {"\033[l", 3}, {"\033[m", 3}, {"\033[n", 3}, +/* 29-32 */ {"\033[o", 3}, {"\033[p", 3}, {"\033[q", 3}, {"\033[r", 3}, +/* 33-36 */ {"\033[s", 3}, {"\033[t", 3}, {"\033[u", 3}, {"\033[v", 3}, +/* 37-40 */ {"\033[w", 3}, {"\033[x", 3}, {"\033[y", 3}, {"\033[z", 3}, +/* 41-44 */ {"\033[@", 3}, {"\033[[", 3}, {"\033[\\",3}, {"\033[]", 3}, +/* 45-48 */ {"\033[^", 3}, {"\033[_", 3}, {"\033[`", 3}, {"\033[{", 3}, +/* 49-52 */ {"\033[H", 3}, {"\033[A", 3}, {"\033[I", 3}, {"-" , 1}, +/* 53-56 */ {"\033[D", 3}, {"\033[E", 3}, {"\033[C", 3}, {"+" , 1}, +/* 57-60 */ {"\033[F", 3}, {"\033[B", 3}, {"\033[G", 3}, {"\033[L", 3}, +/* 61-64 */ {"\177", 1}, {"\033[J", 3}, {"\033[~", 3}, {"\033[}", 3}, +/* 65-68 */ {"", 0} , {"", 0} , {"", 0} , {"", 0} , +/* 69-72 */ {"", 0} , {"", 0} , {"", 0} , {"", 0} , +/* 73-76 */ {"", 0} , {"", 0} , {"", 0} , {"", 0} , +/* 77-80 */ {"", 0} , {"", 0} , {"", 0} , {"", 0} , +/* 81-84 */ {"", 0} , {"", 0} , {"", 0} , {"", 0} , +/* 85-88 */ {"", 0} , {"", 0} , {"", 0} , {"", 0} , +/* 89-92 */ {"", 0} , {"", 0} , {"", 0} , {"", 0} , +/* 93-96 */ {"", 0} , {"", 0} , {"", 0} , {"", 0} +}; diff --git a/freebsd/sys/sys/kbio.h b/freebsd/sys/sys/kbio.h new file mode 100644 index 00000000..7f17bda7 --- /dev/null +++ b/freebsd/sys/sys/kbio.h @@ -0,0 +1,269 @@ +/*- + * $FreeBSD$ + */ + +#ifndef _SYS_KBIO_H_ +#define _SYS_KBIO_H_ + +#ifndef _KERNEL +#include +#endif +#include + +/* get/set keyboard I/O mode */ +#define K_RAW 0 /* keyboard returns scancodes */ +#define K_XLATE 1 /* keyboard returns ascii */ +#define K_CODE 2 /* keyboard returns keycodes */ +#define KDGKBMODE _IOR('K', 6, int) +#define KDSKBMODE _IOWINT('K', 7) + +/* make tone */ +#define KDMKTONE _IOWINT('K', 8) + +/* see console.h for the definitions of the following ioctls */ +#ifdef notdef +#define KDGETMODE _IOR('K', 9, int) +#define KDSETMODE _IOWINT('K', 10) +#define KDSBORDER _IOWINT('K', 13) +#endif + +/* get/set keyboard lock state */ +#define CLKED 1 /* Caps locked */ +#define NLKED 2 /* Num locked */ +#define SLKED 4 /* Scroll locked */ +#define ALKED 8 /* AltGr locked */ +#define LOCK_MASK (CLKED | NLKED | SLKED | ALKED) +#define KDGKBSTATE _IOR('K', 19, int) +#define KDSKBSTATE _IOWINT('K', 20) + +/* enable/disable I/O access */ +#define KDENABIO _IO('K', 60) +#define KDDISABIO _IO('K', 61) + +/* make sound */ +#define KIOCSOUND _IOWINT('K', 63) + +/* get keyboard model */ +#define KB_OTHER 0 /* keyboard not known */ +#define KB_84 1 /* 'old' 84 key AT-keyboard */ +#define KB_101 2 /* MF-101 or MF-102 keyboard */ +#define KDGKBTYPE _IOR('K', 64, int) + +/* get/set keyboard LED state */ +#define LED_CAP 1 /* Caps lock LED */ +#define LED_NUM 2 /* Num lock LED */ +#define LED_SCR 4 /* Scroll lock LED */ +#define LED_MASK (LED_CAP | LED_NUM | LED_SCR) +#define KDGETLED _IOR('K', 65, int) +#define KDSETLED _IOWINT('K', 66) + +/* set keyboard repeat rate (obsolete, use KDSETREPEAT below) */ +#define KDSETRAD _IOWINT('K', 67) + +struct keyboard_info { + int kb_index; /* kbdio index# */ + char kb_name[16]; /* driver name */ + int kb_unit; /* unit# */ + int kb_type; /* KB_84, KB_101, KB_OTHER,... */ + int kb_config; /* device configuration flags */ + int kb_flags; /* internal flags */ +}; +typedef struct keyboard_info keyboard_info_t; + +/* add/remove keyboard to/from mux */ +#define KBADDKBD _IOW('K', 68, keyboard_info_t) /* add keyboard */ +#define KBRELKBD _IOW('K', 69, keyboard_info_t) /* release keyboard */ + +/* see console.h for the definition of the following ioctl */ +#ifdef notdef +#define KDRASTER _IOW('K', 100, scr_size_t) +#endif + +/* get keyboard information */ +#define KDGKBINFO _IOR('K', 101, keyboard_info_t) + +/* set/get keyboard repeat rate (new interface) */ +struct keyboard_repeat { + int kb_repeat[2]; +}; +typedef struct keyboard_repeat keyboard_repeat_t; +#define KDSETREPEAT _IOW('K', 102, keyboard_repeat_t) +#define KDGETREPEAT _IOR('K', 103, keyboard_repeat_t) + +/* get/set key map/accent map/function key strings */ + +#define NUM_KEYS 256 /* number of keys in table */ +#define NUM_STATES 8 /* states per key */ +#define ALTGR_OFFSET 128 /* offset for altlock keys */ + +#define NUM_DEADKEYS 15 /* number of accent keys */ +#define NUM_ACCENTCHARS 52 /* max number of accent chars */ + +#define NUM_FKEYS 96 /* max number of function keys */ +#define MAXFK 16 /* max length of a function key str */ + +#ifndef _KEYMAP_DECLARED +#define _KEYMAP_DECLARED + +struct keyent_t { + u_int map[NUM_STATES]; + u_char spcl; + u_char flgs; +#define FLAG_LOCK_O 0 +#define FLAG_LOCK_C 1 +#define FLAG_LOCK_N 2 +}; + +struct keymap { + u_short n_keys; + struct keyent_t key[NUM_KEYS]; +}; +typedef struct keymap keymap_t; + +#ifdef _KERNEL +struct okeyent_t { + u_char map[NUM_STATES]; + u_char spcl; + u_char flgs; +}; + +struct okeymap { + u_short n_keys; + struct okeyent_t key[NUM_KEYS]; +}; +typedef struct okeymap okeymap_t; +#endif /* _KERNEL */ + +#endif /* !_KEYMAP_DECLARED */ + +/* defines for "special" keys (spcl bit set in keymap) */ +#define NOP 0x00 /* nothing (dead key) */ +#define LSH 0x02 /* left shift key */ +#define RSH 0x03 /* right shift key */ +#define CLK 0x04 /* caps lock key */ +#define NLK 0x05 /* num lock key */ +#define SLK 0x06 /* scroll lock key */ +#define LALT 0x07 /* left alt key */ +#define BTAB 0x08 /* backwards tab */ +#define LCTR 0x09 /* left control key */ +#define NEXT 0x0a /* switch to next screen */ +#define F_SCR 0x0b /* switch to first screen */ +#define L_SCR 0x1a /* switch to last screen */ +#define F_FN 0x1b /* first function key */ +#define L_FN 0x7a /* last function key */ +/* 0x7b-0x7f reserved do not use ! */ +#define RCTR 0x80 /* right control key */ +#define RALT 0x81 /* right alt (altgr) key */ +#define ALK 0x82 /* alt lock key */ +#define ASH 0x83 /* alt shift key */ +#define META 0x84 /* meta key */ +#define RBT 0x85 /* boot machine */ +#define DBG 0x86 /* call debugger */ +#define SUSP 0x87 /* suspend power (APM) */ +#define SPSC 0x88 /* toggle splash/text screen */ + +#define F_ACC DGRA /* first accent key */ +#define DGRA 0x89 /* grave */ +#define DACU 0x8a /* acute */ +#define DCIR 0x8b /* circumflex */ +#define DTIL 0x8c /* tilde */ +#define DMAC 0x8d /* macron */ +#define DBRE 0x8e /* breve */ +#define DDOT 0x8f /* dot */ +#define DUML 0x90 /* umlaut/diaresis */ +#define DDIA 0x90 /* diaresis */ +#define DSLA 0x91 /* slash */ +#define DRIN 0x92 /* ring */ +#define DCED 0x93 /* cedilla */ +#define DAPO 0x94 /* apostrophe */ +#define DDAC 0x95 /* double acute */ +#define DOGO 0x96 /* ogonek */ +#define DCAR 0x97 /* caron */ +#define L_ACC DCAR /* last accent key */ + +#define STBY 0x98 /* Go into standby mode (apm) */ +#define PREV 0x99 /* switch to previous screen */ +#define PNC 0x9a /* force system panic */ +#define LSHA 0x9b /* left shift key / alt lock */ +#define RSHA 0x9c /* right shift key / alt lock */ +#define LCTRA 0x9d /* left ctrl key / alt lock */ +#define RCTRA 0x9e /* right ctrl key / alt lock */ +#define LALTA 0x9f /* left alt key / alt lock */ +#define RALTA 0xa0 /* right alt key / alt lock */ +#define HALT 0xa1 /* halt machine */ +#define PDWN 0xa2 /* halt machine and power down */ +#define PASTE 0xa3 /* paste from cut-paste buffer */ + +#define F(x) ((x)+F_FN-1) +#define S(x) ((x)+F_SCR-1) +#define ACC(x) ((x)+F_ACC) + +struct acc_t { + u_char accchar; + u_char map[NUM_ACCENTCHARS][2]; +}; + +struct accentmap { + u_short n_accs; + struct acc_t acc[NUM_DEADKEYS]; +}; +typedef struct accentmap accentmap_t; + +struct keyarg { + u_short keynum; + struct keyent_t key; +}; +typedef struct keyarg keyarg_t; + +struct fkeytab { + u_char str[MAXFK]; + u_char len; +}; +typedef struct fkeytab fkeytab_t; + +struct fkeyarg { + u_short keynum; + char keydef[MAXFK]; + char flen; +}; +typedef struct fkeyarg fkeyarg_t; + +#define GETFKEY _IOWR('k', 0, fkeyarg_t) +#define SETFKEY _IOWR('k', 1, fkeyarg_t) +#ifdef notdef /* see console.h */ +#define GIO_SCRNMAP _IOR('k', 2, scrmap_t) +#define PIO_SCRNMAP _IOW('k', 3, scrmap_t) +#endif +/* XXX: Should have keymap_t as an argument, but that's too big for ioctl()! */ +#define GIO_KEYMAP _IO('k', 6) +#define PIO_KEYMAP _IO('k', 7) +#ifdef _KERNEL +#define OGIO_KEYMAP _IOR('k', 6, okeymap_t) +#define OPIO_KEYMAP _IOW('k', 7, okeymap_t) +#endif /* _KERNEL */ +#define GIO_DEADKEYMAP _IOR('k', 8, accentmap_t) +#define PIO_DEADKEYMAP _IOW('k', 9, accentmap_t) +#define GIO_KEYMAPENT _IOWR('k', 10, keyarg_t) +#define PIO_KEYMAPENT _IOW('k', 11, keyarg_t) + +/* flags set to the return value in the KD_XLATE mode */ + +#define NOKEY 0x01000000 /* no key pressed marker */ +#define FKEY 0x02000000 /* function key marker */ +#define MKEY 0x04000000 /* meta key marker (prepend ESC)*/ +#define BKEY 0x08000000 /* backtab (ESC [ Z) */ + +#define SPCLKEY 0x80000000 /* special key */ +#define RELKEY 0x40000000 /* key released */ +#define ERRKEY 0x20000000 /* error */ + +/* + * The top byte is used to store the flags. This means there are 24 + * bits left to store the actual character. Because UTF-8 can encode + * 2^21 different characters, this is good enough to get Unicode + * working. + */ +#define KEYCHAR(c) ((c) & 0x00ffffff) +#define KEYFLAGS(c) ((c) & ~0x00ffffff) + +#endif /* !_SYS_KBIO_H_ */ -- cgit v1.2.3