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 + -
显示快捷键?