atkbd.c

来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 1,423 行 · 第 1/3 页

C
1,423
字号
/*- * 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: atkbd.c,v 1.3.2.2 1999/05/09 11:02:11 yokota Exp $ */#include "atkbd.h"#include "opt_kbd.h"#include "opt_atkbd.h"#include "opt_devfs.h"#if NATKBD > 0#include <sys/param.h>#include <sys/systm.h>#include <sys/kernel.h>#include <sys/conf.h>#include <sys/proc.h>#include <sys/tty.h>#include <sys/fcntl.h>#include <sys/malloc.h>#include <dev/kbd/kbdreg.h>#include <dev/kbd/atkbdreg.h>#include <dev/kbd/atkbdcreg.h>#ifndef __i386__#include <sys/bus.h>#include <isa/isareg.h>extern devclass_t atkbd_devclass;#define ATKBD_SOFTC(unit)		\	((atkbd_softc_t *)devclass_get_softc(atkbd_devclass, unit))#else /* __i386__ */#include <i386/isa/isa.h>#include <i386/isa/isa_device.h>extern struct isa_driver 	atkbddriver;	/* XXX: a kludge; see below */static atkbd_softc_t		*atkbd_softc[NATKBD];#define ATKBD_SOFTC(unit)		\	(((unit) >= NATKBD) ? NULL : atkbd_softc[(unit)])#endif /* __i386__ */static timeout_t	atkbd_timeout;#ifdef KBD_INSTALL_CDEVstatic d_open_t		atkbdopen;static d_close_t	atkbdclose;static d_read_t		atkbdread;static d_ioctl_t	atkbdioctl;static d_poll_t		atkbdpoll;static struct  cdevsw atkbd_cdevsw = {	atkbdopen,	atkbdclose,	atkbdread,	nowrite,	atkbdioctl,	nostop,		nullreset,	nodevtotty,	atkbdpoll,	nommap,		NULL,		ATKBD_DRIVER_NAME,	NULL,		-1,};#endif /* KBD_INSTALL_CDEV */#ifdef __i386__atkbd_softc_t*atkbd_get_softc(int unit){	atkbd_softc_t *sc;	if (unit >= sizeof(atkbd_softc)/sizeof(atkbd_softc[0]))		return NULL;	sc = atkbd_softc[unit];	if (sc == NULL) {		sc = atkbd_softc[unit]		   = malloc(sizeof(*sc), M_DEVBUF, M_NOWAIT);		if (sc == NULL)			return NULL;		bzero(sc, sizeof(*sc));	}	return sc;}#endif /* __i386__ */intatkbd_probe_unit(int unit, int port, int irq, int flags){	keyboard_switch_t *sw;	int args[2];	int error;	sw = kbd_get_switch(ATKBD_DRIVER_NAME);	if (sw == NULL)		return ENXIO;	args[0] = port;	args[1] = irq;	error = (*sw->probe)(unit, args, flags);	if (error)		return error;	return 0;}intatkbd_attach_unit(int unit, atkbd_softc_t *sc, int port, int irq, int flags){	keyboard_switch_t *sw;	int args[2];	int error;	if (sc->flags & ATKBD_ATTACHED)		return 0;	sw = kbd_get_switch(ATKBD_DRIVER_NAME);	if (sw == NULL)		return ENXIO;	/* reset, initialize and enable the device */	args[0] = port;	args[1] = irq;	sc->kbd = NULL;	error = (*sw->probe)(unit, args, flags);	if (error)		return error;	error = (*sw->init)(unit, &sc->kbd, args, flags);	if (error)		return error;	(*sw->enable)(sc->kbd);#ifdef KBD_INSTALL_CDEV	/* attach a virtual keyboard cdev */	error = kbd_attach(makedev(0, ATKBD_MKMINOR(unit)), sc->kbd,			   &atkbd_cdevsw);	if (error)		return error;#endif	/*	 * This is a kludge to compensate for lost keyboard interrupts.	 * A similar code used to be in syscons. See below. XXX	 */	atkbd_timeout(sc->kbd);	if (bootverbose)		(*sw->diag)(sc->kbd, bootverbose);	sc->flags |= ATKBD_ATTACHED;	return 0;}static voidatkbd_timeout(void *arg){	keyboard_t *kbd;	int s;	/* The following comments are extracted from syscons.c (1.287) */	/* 	 * With release 2.1 of the Xaccel server, the keyboard is left	 * hanging pretty often. Apparently an interrupt from the	 * keyboard is lost, and I don't know why (yet).	 * This ugly hack calls scintr if input is ready for the keyboard	 * and conveniently hides the problem.			XXX	 */	/*	 * Try removing anything stuck in the keyboard controller; whether	 * it's a keyboard scan code or mouse data. `scintr()' doesn't	 * read the mouse data directly, but `kbdio' routines will, as a	 * side effect.	 */	s = spltty();	kbd = (keyboard_t *)arg;	if ((*kbdsw[kbd->kb_index]->lock)(kbd, TRUE)) {		/*		 * We have seen the lock flag is not set. Let's reset		 * the flag early, otherwise the LED update routine fails		 * which may want the lock during the interrupt routine.		 */		(*kbdsw[kbd->kb_index]->lock)(kbd, FALSE);		if ((*kbdsw[kbd->kb_index]->check_char)(kbd))			(*kbdsw[kbd->kb_index]->intr)(kbd, NULL);	}	splx(s);	timeout(atkbd_timeout, arg, hz/10);}/* cdev driver functions */#ifdef KBD_INSTALL_CDEVstatic intatkbdopen(dev_t dev, int flag, int mode, struct proc *p){	atkbd_softc_t *sc;	sc = ATKBD_SOFTC(ATKBD_UNIT(dev));	if (sc == NULL)		return ENXIO;	if (mode & (FWRITE | O_CREAT | O_APPEND | O_TRUNC))		return ENODEV;	/* FIXME: set the initial input mode (K_XLATE?) and lock state? */	return genkbdopen(&sc->gensc, sc->kbd, flag, mode, p);}static intatkbdclose(dev_t dev, int flag, int mode, struct proc *p){	atkbd_softc_t *sc;	sc = ATKBD_SOFTC(ATKBD_UNIT(dev));	return genkbdclose(&sc->gensc, sc->kbd, flag, mode, p);}static intatkbdread(dev_t dev, struct uio *uio, int flag){	atkbd_softc_t *sc;	sc = ATKBD_SOFTC(ATKBD_UNIT(dev));	return genkbdread(&sc->gensc, sc->kbd, uio, flag);}static intatkbdioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p){	atkbd_softc_t *sc;	sc = ATKBD_SOFTC(ATKBD_UNIT(dev));	return genkbdioctl(&sc->gensc, sc->kbd, cmd, arg, flag, p);}static intatkbdpoll(dev_t dev, int event, struct proc *p){	atkbd_softc_t *sc;	sc = ATKBD_SOFTC(ATKBD_UNIT(dev));	return genkbdpoll(&sc->gensc, sc->kbd, event, p);}#endif /* KBD_INSTALL_CDEV *//* LOW-LEVEL */#include <machine/limits.h>#include <machine/console.h>#include <machine/clock.h>#define ATKBD_DEFAULT	0typedef struct atkbd_state {	KBDC		kbdc;		/* keyboard controller */					/* XXX: don't move this field; pcvt					 * expects `kbdc' to be the first					 * field in this structure. */	int		ks_mode;	/* input mode (K_XLATE,K_RAW,K_CODE) */	int		ks_flags;	/* flags */#define COMPOSE		(1 << 0)	int		ks_polling;	int		ks_state;	/* shift/lock key state */	int		ks_accents;	/* accent key index (> 0) */	u_int		ks_composed_char; /* composed char code (> 0) */	u_char		ks_prefix;	/* AT scan code prefix */} atkbd_state_t;/* keyboard driver declaration */static int		atkbd_configure(int flags);static kbd_probe_t	atkbd_probe;static kbd_init_t	atkbd_init;static kbd_term_t	atkbd_term;static kbd_intr_t	atkbd_intr;static kbd_test_if_t	atkbd_test_if;static kbd_enable_t	atkbd_enable;static kbd_disable_t	atkbd_disable;static kbd_read_t	atkbd_read;static kbd_check_t	atkbd_check;static kbd_read_char_t	atkbd_read_char;static kbd_check_char_t	atkbd_check_char;static kbd_ioctl_t	atkbd_ioctl;static kbd_lock_t	atkbd_lock;static kbd_clear_state_t atkbd_clear_state;static kbd_get_state_t	atkbd_get_state;static kbd_set_state_t	atkbd_set_state;static kbd_poll_mode_t	atkbd_poll;keyboard_switch_t atkbdsw = {	atkbd_probe,	atkbd_init,	atkbd_term,	atkbd_intr,	atkbd_test_if,	atkbd_enable,	atkbd_disable,	atkbd_read,	atkbd_check,	atkbd_read_char,	atkbd_check_char,	atkbd_ioctl,	atkbd_lock,	atkbd_clear_state,	atkbd_get_state,	atkbd_set_state,	genkbd_get_fkeystr,	atkbd_poll,	genkbd_diag,};KEYBOARD_DRIVER(atkbd, atkbdsw, atkbd_configure);/* local functions */static int		setup_kbd_port(KBDC kbdc, int port, int intr);static int		get_kbd_echo(KBDC kbdc);static int		probe_keyboard(KBDC kbdc, int flags);static int		init_keyboard(KBDC kbdc, int *type, int flags);static int		write_kbd(KBDC kbdc, int command, int data);static int		get_kbd_id(KBDC kbdc);static int		typematic(int delay, int rate);/* local variables *//* the initial key map, accent map and fkey strings */#ifdef ATKBD_DFLT_KEYMAP#define KBD_DFLT_KEYMAP#include "atkbdmap.h"#endif#include <dev/kbd/kbdtables.h>/* structures for the default keyboard */static keyboard_t	default_kbd;static atkbd_state_t	default_kbd_state;static keymap_t		default_keymap;static accentmap_t	default_accentmap;static fkeytab_t	default_fkeytab[NUM_FKEYS];/*  * The back door to the keyboard driver! * This function is called by the console driver, via the kbdio module, * to tickle keyboard drivers when the low-level console is being initialized. * Almost nothing in the kernel has been initialied yet.  Try to probe * keyboards if possible. * NOTE: because of the way the low-level conole is initialized, this routine * may be called more than once!! */static intatkbd_configure(int flags){	keyboard_t *kbd;	int arg[2];#ifdef __i386__	struct isa_device *dev;	int i;	/* XXX: a kludge to obtain the device configuration flags */	dev = find_isadev(isa_devtab_tty, &atkbddriver, 0);	if (dev != NULL) {		flags |= dev->id_flags;		/* if the driver is disabled, unregister the keyboard if any */		if (!dev->id_enabled) {			i = kbd_find_keyboard(ATKBD_DRIVER_NAME, ATKBD_DEFAULT);			if (i >= 0) {				kbd = kbd_get_keyboard(i);				kbd_unregister(kbd);				kbd->kb_flags &= ~KB_REGISTERED;				return 0;			}		}	}#endif	/* probe the keyboard controller */	atkbdc_configure();	/* probe the default keyboard */	arg[0] = -1;	arg[1] = -1;	kbd = NULL;	if (atkbd_probe(ATKBD_DEFAULT, arg, flags))		return 0;	if (atkbd_init(ATKBD_DEFAULT, &kbd, arg, flags))		return 0;	/* return the number of found keyboards */	return 1;}/* low-level functions *//* detect a keyboard */static intatkbd_probe(int unit, void *arg, int flags){	KBDC kbdc;	int *data = (int *)arg;	/* XXX */	if (unit == ATKBD_DEFAULT) {		if (KBD_IS_PROBED(&default_kbd))			return 0;	}	kbdc = kbdc_open(data[0]);	if (kbdc == NULL)		return ENXIO;	if (probe_keyboard(kbdc, flags)) {		if (flags & KB_CONF_FAIL_IF_NO_KBD)			return ENXIO;	}	return 0;}/* reset and initialize the device */static intatkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags){	keyboard_t *kbd;	atkbd_state_t *state;	keymap_t *keymap;	accentmap_t *accmap;	fkeytab_t *fkeymap;	int fkeymap_size;	int *data = (int *)arg;	/* XXX */	if (unit == ATKBD_DEFAULT) {		*kbdp = kbd = &default_kbd;		if (KBD_IS_INITIALIZED(kbd) && KBD_IS_CONFIGURED(kbd))			return 0;		state = &default_kbd_state;		keymap = &default_keymap;		accmap = &default_accentmap;		fkeymap = default_fkeytab;		fkeymap_size =			sizeof(default_fkeytab)/sizeof(default_fkeytab[0]);	} else if (*kbdp == NULL) {		*kbdp = kbd = malloc(sizeof(*kbd), M_DEVBUF, M_NOWAIT);		if (kbd == NULL)			return ENOMEM;		bzero(kbd, sizeof(*kbd));		state = malloc(sizeof(*state), M_DEVBUF, M_NOWAIT);		keymap = malloc(sizeof(key_map), M_DEVBUF, M_NOWAIT);		accmap = malloc(sizeof(accent_map), M_DEVBUF, M_NOWAIT);		fkeymap = malloc(sizeof(fkey_tab), M_DEVBUF, M_NOWAIT);		fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]);		if ((state == NULL) || (keymap == NULL) || (accmap == NULL)		     || (fkeymap == NULL)) {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?