kbd.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,245 行 · 第 1/2 页
C
1,245 行
/*- * Copyright (c) 1999 Kazutaka YOKOTA <yokota@zodiac.mech.utsunomiya-u.ac.jp> * 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. * * $Id: kbd.c,v 1.3.2.1 1999/05/09 11:02:13 yokota Exp $ */#include "kbd.h"#include "opt_kbd.h"#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/malloc.h>#include <sys/conf.h>#include <sys/proc.h>#include <sys/tty.h>#include <sys/poll.h>#include <sys/vnode.h>#include <sys/uio.h>#include <machine/console.h>#include <dev/kbd/kbdreg.h>/* 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;#ifdef KBD_INSTALL_CDEVstatic struct cdevsw *kbdcdevsw_ini;static struct cdevsw **kbdcdevsw = &kbdcdevsw_ini;#endif#define ARRAY_DELTA 4static intkbd_realloc_array(void){ keyboard_t **new_kbd; keyboard_switch_t **new_kbdsw;#ifdef KBD_INSTALL_CDEV struct cdevsw **new_cdevsw;#endif int newsize; int s; s = spltty(); newsize = ((keyboards + ARRAY_DELTA)/ARRAY_DELTA)*ARRAY_DELTA; new_kbd = malloc(sizeof(*new_kbd)*newsize, M_DEVBUF, M_NOWAIT); if (new_kbd == NULL) { splx(s); return ENOMEM; } new_kbdsw = malloc(sizeof(*new_kbdsw)*newsize, M_DEVBUF, M_NOWAIT); if (new_kbdsw == NULL) { free(new_kbd, M_DEVBUF); splx(s); return ENOMEM; }#ifdef KBD_INSTALL_CDEV new_cdevsw = malloc(sizeof(*new_cdevsw)*newsize, M_DEVBUF, M_NOWAIT); if (new_cdevsw == NULL) { free(new_kbd, M_DEVBUF); free(new_kbdsw, M_DEVBUF); splx(s); return ENOMEM; }#endif bzero(new_kbd, sizeof(*new_kbd)*newsize); bzero(new_kbdsw, sizeof(*new_kbdsw)*newsize); bcopy(keyboard, new_kbd, sizeof(*keyboard)*keyboards); bcopy(kbdsw, new_kbdsw, sizeof(*kbdsw)*keyboards);#ifdef KBD_INSTALL_CDEV bzero(new_cdevsw, sizeof(*new_cdevsw)*newsize); bcopy(kbdcdevsw, new_cdevsw, sizeof(*kbdcdevsw)*keyboards);#endif if (keyboards > 1) { free(keyboard, M_DEVBUF); free(kbdsw, M_DEVBUF);#ifdef KBD_INSTALL_CDEV free(kbdcdevsw, M_DEVBUF);#endif } keyboard = new_kbd; kbdsw = new_kbdsw;#ifdef KBD_INSTALL_CDEV kbdcdevsw = new_cdevsw;#endif 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 */voidkbd_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;}voidkbd_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;}/* register a keyboard and associate it with a function table */intkbd_register(keyboard_t *kbd){ keyboard_driver_t **list; keyboard_driver_t *p; int index; 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; list = (keyboard_driver_t **)kbddriver_set.ls_items; while ((p = *list++) != NULL) { if (strcmp(p->name, kbd->kb_name) == 0) { keyboard[index] = kbd; kbdsw[index] = p->kbdsw; return index; } } return -1;}intkbd_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 funciton table by the driver name */keyboard_switch_t*kbd_get_switch(char *driver){ keyboard_driver_t **list; keyboard_driver_t *p; list = (keyboard_driver_t **)kbddriver_set.ls_items; while ((p = *list++) != NULL) { 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 */intkbd_find_keyboard(char *driver, int unit){ int i; for (i = 0; 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;}/* allocate a keyboard */intkbd_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; (*kbdsw[index]->clear_state)(keyboard[index]); } splx(s); return index;}intkbd_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; (*kbdsw[kbd->kb_index]->clear_state)(kbd); error = 0; } splx(s); return error;}intkbd_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 (!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. */intkbd_configure(int flags){ keyboard_driver_t **list; keyboard_driver_t *p; list = (keyboard_driver_t **)kbddriver_set.ls_items; while ((p = *list++) != NULL) { 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) minor(dev)static d_open_t kbdopen;static d_close_t kbdclose;static d_read_t kbdread;static d_write_t kbdwrite;static d_ioctl_t kbdioctl;static d_reset_t kbdreset;static d_devtotty_t kbddevtotty;static d_poll_t kbdpoll;static d_mmap_t kbdmmap;#define CDEV_MAJOR 112static struct cdevsw kbd_cdevsw = { kbdopen, kbdclose, kbdread, kbdwrite, /* ??? */ kbdioctl, nullstop, kbdreset, kbddevtotty, kbdpoll, kbdmmap, nostrategy, "kbd", NULL, -1, nodump, nopsize,};static voidvkbdattach(void *arg){ static int kbd_devsw_installed = FALSE; dev_t dev; if (!kbd_devsw_installed) { dev = makedev(CDEV_MAJOR, 0); cdevsw_add(&dev, &kbd_cdevsw, NULL); kbd_devsw_installed = TRUE; }}PSEUDO_SET(vkbdattach, kbd);intkbd_attach(dev_t dev, keyboard_t *kbd, struct cdevsw *cdevsw){ int s; if (kbd->kb_index >= keyboards) return EINVAL; if (keyboard[kbd->kb_index] != kbd) return EINVAL; s = spltty(); kbd->kb_minor = minor(dev); kbdcdevsw[kbd->kb_index] = cdevsw; splx(s); /* XXX: DEVFS? */ printf("kbd%d at %s%d\n", kbd->kb_index, kbd->kb_name, kbd->kb_unit); return 0;}intkbd_detach(dev_t dev, keyboard_t *kbd, struct cdevsw *cdevsw){ int s; if (kbd->kb_index >= keyboards) return EINVAL; if (keyboard[kbd->kb_index] != kbd) return EINVAL; if (kbdcdevsw[kbd->kb_index] != cdevsw) return EINVAL; s = spltty(); (*kbdsw[kbd->kb_index]->term)(kbd); kbdcdevsw[kbd->kb_index] = NULL; splx(s); return 0;}static intkbdopen(dev_t dev, int flag, int mode, struct proc *p){ int unit; unit = KBD_UNIT(dev); if (unit >= keyboards) return ENXIO; if (kbdcdevsw[unit] == NULL) return ENXIO; if (KBD_IS_BUSY(keyboard[unit])) return EBUSY; return (*kbdcdevsw[unit]->d_open)(makedev(0, keyboard[unit]->kb_minor), flag, mode, p);}static intkbdclose(dev_t dev, int flag, int mode, struct proc *p){ int unit; unit = KBD_UNIT(dev); if (kbdcdevsw[unit] == NULL) return ENXIO; return (*kbdcdevsw[unit]->d_close)(makedev(0, keyboard[unit]->kb_minor), flag, mode, p);}static intkbdread(dev_t dev, struct uio *uio, int flag){ int unit; unit = KBD_UNIT(dev); if (kbdcdevsw[unit] == NULL) return ENXIO; return (*kbdcdevsw[unit]->d_read)(makedev(0, keyboard[unit]->kb_minor), uio, flag);}static intkbdwrite(dev_t dev, struct uio *uio, int flag){ int unit; unit = KBD_UNIT(dev); if (kbdcdevsw[unit] == NULL) return ENXIO; return (*kbdcdevsw[unit]->d_write)(makedev(0, keyboard[unit]->kb_minor), uio, flag);}static intkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p){ int unit; unit = KBD_UNIT(dev); if (kbdcdevsw[unit] == NULL) return ENXIO; return (*kbdcdevsw[unit]->d_ioctl)(makedev(0, keyboard[unit]->kb_minor), cmd, arg, flag, p);}static intkbdreset(dev_t dev){ int unit; unit = KBD_UNIT(dev); if (kbdcdevsw[unit] == NULL) return ENXIO; return (*kbdcdevsw[unit]->d_reset)(makedev(0, keyboard[unit]->kb_minor));}static struct tty*kbddevtotty(dev_t dev){ int unit; unit = KBD_UNIT(dev); if (kbdcdevsw[unit] == NULL) return NULL; return (*kbdcdevsw[unit]->d_devtotty)(makedev(0, keyboard[unit]->kb_minor));}static intkbdpoll(dev_t dev, int event, struct proc *p){ int unit; unit = KBD_UNIT(dev); if (kbdcdevsw[unit] == NULL) return ENXIO; return (*kbdcdevsw[unit]->d_poll)(makedev(0, keyboard[unit]->kb_minor), event, p);}static intkbdmmap(dev_t dev, vm_offset_t offset, int nprot){ int unit; unit = KBD_UNIT(dev); if (kbdcdevsw[unit] == NULL) return ENXIO; return (*kbdcdevsw[unit]->d_mmap)(makedev(0, keyboard[unit]->kb_minor), offset, nprot);}/* * Generic keyboard cdev driver functions * Keyboard subdrivers may call these functions to implement common * driver functions. */#define KB_QSIZE 512#define KB_BUFSIZE 64static kbd_callback_func_t genkbd_event;intgenkbdopen(genkbd_softc_t *sc, keyboard_t *kbd, int mode, int flag, struct proc *p){ int s; int i; s = spltty(); if (!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)). */#if 0 bzero(&sc->gkb_q, sizeof(sc->gkb_q));#endif clist_alloc_cblocks(&sc->gkb_q, KB_QSIZE, KB_QSIZE/2); /* XXX */ sc->gkb_rsel.si_flags = 0; sc->gkb_rsel.si_pid = 0;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?