diff options
Diffstat (limited to 'sys/dev/atkbdc/atkbd.c')
-rw-r--r-- | sys/dev/atkbdc/atkbd.c | 244 |
1 files changed, 158 insertions, 86 deletions
diff --git a/sys/dev/atkbdc/atkbd.c b/sys/dev/atkbdc/atkbd.c index d50982c..f9e28fe 100644 --- a/sys/dev/atkbdc/atkbd.c +++ b/sys/dev/atkbdc/atkbd.c @@ -23,11 +23,12 @@ * (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 1999/01/19 11:31:14 yokota Exp $ + * $Id: atkbd.c,v 1.4 1999/01/28 10:55:55 yokota Exp $ */ #include "atkbd.h" #include "opt_kbd.h" +#include "opt_atkbd.h" #include "opt_devfs.h" #if NATKBD > 0 @@ -47,8 +48,11 @@ #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)) @@ -61,7 +65,8 @@ extern struct isa_driver atkbddriver; /* XXX: a kludge; see below */ static atkbd_softc_t *atkbd_softc[NATKBD]; -#define ATKBD_SOFTC(unit) atkbd_softc[(unit)] +#define ATKBD_SOFTC(unit) \ + (((unit) >= NATKBD) ? NULL : atkbd_softc[(unit)]) #endif /* __i386__ */ @@ -107,13 +112,11 @@ atkbd_softc_t #endif /* __i386__ */ int -atkbd_probe_unit(int unit, atkbd_softc_t *sc, int port, int irq, int flags) +atkbd_probe_unit(int unit, int port, int irq, int flags) { keyboard_switch_t *sw; int args[2]; - - if (sc->flags & ATKBD_ATTACHED) - return 0; + int error; sw = kbd_get_switch(ATKBD_DRIVER_NAME); if (sw == NULL) @@ -121,13 +124,17 @@ atkbd_probe_unit(int unit, atkbd_softc_t *sc, int port, int irq, int flags) args[0] = port; args[1] = irq; - return (*sw->probe)(unit, &sc->kbd, args, flags); + error = (*sw->probe)(unit, args, flags); + if (error) + return error; + return 0; } int -atkbd_attach_unit(int unit, atkbd_softc_t *sc) +atkbd_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) @@ -138,9 +145,15 @@ atkbd_attach_unit(int unit, atkbd_softc_t *sc) return ENXIO; /* reset, initialize and enable the device */ - error = (*sw->init)(sc->kbd); + args[0] = port; + args[1] = irq; + sc->kbd = NULL; + error = (*sw->probe)(unit, args, flags); if (error) - return ENXIO; + return error; + error = (*sw->init)(unit, &sc->kbd, args, flags); + if (error) + return error; (*sw->enable)(sc->kbd); #ifdef KBD_INSTALL_CDEV @@ -194,7 +207,7 @@ atkbd_timeout(void *arg) */ (*kbdsw[kbd->kb_index]->lock)(kbd, FALSE); if ((*kbdsw[kbd->kb_index]->check_char)(kbd)) - (*kbdsw[kbd->kb_index]->intr)(kbd); + (*kbdsw[kbd->kb_index]->intr)(kbd, NULL); } splx(s); timeout(atkbd_timeout, arg, hz/10); @@ -208,10 +221,9 @@ static int atkbdopen(dev_t dev, int flag, int mode, struct proc *p) { atkbd_softc_t *sc; - int unit; - unit = ATKBD_UNIT(dev); - if ((unit >= NATKBD) || ((sc = ATKBD_SOFTC(unit)) == NULL)) + sc = ATKBD_SOFTC(ATKBD_UNIT(dev)); + if (sc == NULL) return ENXIO; if (mode & (FWRITE | O_CREAT | O_APPEND | O_TRUNC)) return ENODEV; @@ -274,6 +286,7 @@ typedef struct atkbd_state { 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) */ @@ -298,6 +311,7 @@ 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, @@ -317,6 +331,7 @@ keyboard_switch_t atkbdsw = { atkbd_get_state, atkbd_set_state, genkbd_get_fkeystr, + atkbd_poll, genkbd_diag, }; @@ -329,10 +344,15 @@ 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 */ @@ -355,15 +375,26 @@ static int atkbd_configure(int flags) { keyboard_t *kbd; - KBDC kbdc; 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) + 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 */ @@ -372,34 +403,44 @@ atkbd_configure(int flags) /* probe the default keyboard */ arg[0] = -1; arg[1] = -1; - if (atkbd_probe(ATKBD_DEFAULT, &kbd, arg, flags)) + kbd = NULL; + if (atkbd_probe(ATKBD_DEFAULT, arg, flags)) + return 0; + if (atkbd_init(ATKBD_DEFAULT, &kbd, arg, flags)) return 0; - /* initialize it */ - kbdc = ((atkbd_state_t *)kbd->kb_data)->kbdc; - if (!(flags & KB_CONF_PROBE_ONLY) && !KBD_IS_INITIALIZED(kbd)) { - if (KBD_HAS_DEVICE(kbd) - && init_keyboard(kbdc, &kbd->kb_type, flags) - && (flags & KB_CONF_FAIL_IF_NO_KBD)) - return 0; - KBD_INIT_DONE(kbd); - } + /* return the number of found keyboards */ + return 1; +} - /* and register */ - if (!KBD_IS_CONFIGURED(kbd)) { - if (kbd_register(kbd) < 0) +/* low-level functions */ + +/* detect a keyboard */ +static int +atkbd_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; - KBD_CONFIG_DONE(kbd); } - return 1; /* return the number of found keyboards */ + 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; } -/* low-level functions */ - -/* initialize the keyboard_t structure and try to detect a keyboard */ +/* reset and initialize the device */ static int -atkbd_probe(int unit, keyboard_t **kbdp, void *arg, int flags) +atkbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) { keyboard_t *kbd; atkbd_state_t *state; @@ -407,13 +448,12 @@ atkbd_probe(int unit, keyboard_t **kbdp, void *arg, int flags) accentmap_t *accmap; fkeytab_t *fkeymap; int fkeymap_size; - KBDC kbdc; int *data = (int *)arg; /* XXX */ if (unit == ATKBD_DEFAULT) { *kbdp = kbd = &default_kbd; - if (KBD_IS_PROBED(kbd)) + if (KBD_IS_INITIALIZED(kbd) && KBD_IS_CONFIGURED(kbd)) return 0; state = &default_kbd_state; keymap = &default_keymap; @@ -445,7 +485,7 @@ atkbd_probe(int unit, keyboard_t **kbdp, void *arg, int flags) return ENOMEM; } bzero(state, sizeof(*state)); - } else if (KBD_IS_PROBED(*kbdp)) { + } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { return 0; } else { kbd = *kbdp; @@ -457,54 +497,39 @@ atkbd_probe(int unit, keyboard_t **kbdp, void *arg, int flags) fkeymap_size = kbd->kb_fkeytab_size; } - state->kbdc = kbdc = kbdc_open(data[0]); - if (kbdc == NULL) - return ENXIO; - kbd_init_struct(kbd, ATKBD_DRIVER_NAME, KB_OTHER, unit, flags, data[0], - IO_KBDSIZE); - bcopy(&key_map, keymap, sizeof(key_map)); - bcopy(&accent_map, accmap, sizeof(accent_map)); - bcopy(fkey_tab, fkeymap, - imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); - kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); - kbd->kb_data = (void *)state; - - if (probe_keyboard(kbdc, flags)) { - if (flags & KB_CONF_FAIL_IF_NO_KBD) + if (!KBD_IS_PROBED(kbd)) { + state->kbdc = kbdc_open(data[0]); + if (state->kbdc == NULL) return ENXIO; - } else { - KBD_FOUND_DEVICE(kbd); + kbd_init_struct(kbd, ATKBD_DRIVER_NAME, KB_OTHER, unit, flags, + data[0], IO_KBDSIZE); + bcopy(&key_map, keymap, sizeof(key_map)); + bcopy(&accent_map, accmap, sizeof(accent_map)); + bcopy(fkey_tab, fkeymap, + imin(fkeymap_size*sizeof(fkeymap[0]), sizeof(fkey_tab))); + kbd_set_maps(kbd, keymap, accmap, fkeymap, fkeymap_size); + kbd->kb_data = (void *)state; + + if (probe_keyboard(state->kbdc, flags)) { /* shouldn't happen */ + if (flags & KB_CONF_FAIL_IF_NO_KBD) + return ENXIO; + } else { + KBD_FOUND_DEVICE(kbd); + } + atkbd_clear_state(kbd); + state->ks_mode = K_XLATE; + /* + * FIXME: set the initial value for lock keys in ks_state + * according to the BIOS data? + */ + KBD_PROBE_DONE(kbd); } - atkbd_clear_state(kbd); - state->ks_mode = K_XLATE; - /* - * FIXME: set the initial value for lock keys in ks_state - * according to the BIOS data? - */ - - KBD_PROBE_DONE(kbd); - return 0; -} - -/* reset and initialize the device */ -static int -atkbd_init(keyboard_t *kbd) -{ - KBDC kbdc; - - if ((kbd == NULL) || !KBD_IS_PROBED(kbd)) - return ENXIO; /* shouldn't happen */ - kbdc = ((atkbd_state_t *)kbd->kb_data)->kbdc; - if (kbdc == NULL) - return ENXIO; /* shouldn't happen */ - - if (!KBD_IS_INITIALIZED(kbd)) { + if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { if (KBD_HAS_DEVICE(kbd) - && init_keyboard(kbdc, &kbd->kb_type, kbd->kb_config) - && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) + && init_keyboard(state->kbdc, &kbd->kb_type, kbd->kb_config) + && (kbd->kb_config & KB_CONF_FAIL_IF_NO_KBD)) return ENXIO; - atkbd_ioctl(kbd, KDSETLED, - (caddr_t)&((atkbd_state_t *)(kbd->kb_data))->ks_state); + atkbd_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); KBD_INIT_DONE(kbd); } if (!KBD_IS_CONFIGURED(kbd)) { @@ -526,7 +551,7 @@ atkbd_term(keyboard_t *kbd) /* keyboard interrupt routine */ static int -atkbd_intr(keyboard_t *kbd) +atkbd_intr(keyboard_t *kbd, void *arg) { atkbd_state_t *state; int c; @@ -954,12 +979,18 @@ atkbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) /* set LEDs and quit */ return atkbd_ioctl(kbd, KDSETLED, arg); - case KDSETRAD: /* set keyboard repeat rate */ + case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ splx(s); if (!KBD_HAS_DEVICE(kbd)) return 0; - return write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, - *(int *)arg); + i = typematic(((int *)arg)[0], ((int *)arg)[1]); + return write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, i); + + case KDSETRAD: /* set keyboard repeat rate (old interface) */ + splx(s); + if (!KBD_HAS_DEVICE(kbd)) + return 0; + return write_kbd(state->kbdc, KBDC_SET_TYPEMATIC, *(int *)arg); case PIO_KEYMAP: /* set keyboard translation table */ case PIO_KEYMAPENT: /* set keyboard translation table entry */ @@ -990,6 +1021,7 @@ atkbd_clear_state(keyboard_t *kbd) state = (atkbd_state_t *)kbd->kb_data; state->ks_flags = 0; + state->ks_polling = 0; state->ks_state &= LOCK_MASK; /* preserve locking key state */ state->ks_accents = 0; state->ks_composed_char = 0; @@ -1023,6 +1055,22 @@ atkbd_set_state(keyboard_t *kbd, void *buf, size_t len) return 0; } +static int +atkbd_poll(keyboard_t *kbd, int on) +{ + atkbd_state_t *state; + int s; + + state = (atkbd_state_t *)kbd->kb_data; + s = spltty(); + if (on) + ++state->ks_polling; + else + --state->ks_polling; + splx(s); + return 0; +} + /* local functions */ static int @@ -1347,4 +1395,28 @@ get_kbd_id(KBDC kbdc) return ((id2 << 8) | id1); } +static int +typematic(int delay, int rate) +{ + static int delays[] = { 250, 500, 750, 1000 }; + static int rates[] = { 34, 38, 42, 46, 50, 55, 59, 63, + 68, 76, 84, 92, 100, 110, 118, 126, + 136, 152, 168, 184, 200, 220, 236, 252, + 272, 304, 336, 368, 400, 440, 472, 504 }; + int value; + int i; + + for (i = sizeof(delays)/sizeof(delays[0]) - 1; i > 0; --i) { + if (delay >= delays[i]) + break; + } + value = i << 5; + for (i = sizeof(rates)/sizeof(rates[0]) - 1; i > 0; --i) { + if (rate >= rates[i]) + break; + } + value |= i; + return value; +} + #endif /* NATKBD > 0 */ |