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