summaryrefslogtreecommitdiffstats
path: root/sys/dev/atkbdc/atkbd.c
diff options
context:
space:
mode:
authoryokota <yokota@FreeBSD.org>1999-03-10 10:36:53 +0000
committeryokota <yokota@FreeBSD.org>1999-03-10 10:36:53 +0000
commit1c67fa8f3d842ef1daea6a8442e829e386fafdd5 (patch)
tree41f00cd620389bf07e2912551d080e830f0dc85a /sys/dev/atkbdc/atkbd.c
parent6eb9a9adf91724bc8f8bb0516ce6bc9f52b58d95 (diff)
downloadFreeBSD-src-1c67fa8f3d842ef1daea6a8442e829e386fafdd5.zip
FreeBSD-src-1c67fa8f3d842ef1daea6a8442e829e386fafdd5.tar.gz
Keyboard driver update in preparation for the USB keyboard driver.
- Refined internal interface in keyboard drivers so that: 1. the side effect of device probe is kept minimal, 2. polling mode function is added, 3. and new ioctl and configuration options are added (see below). - Added new ioctl: KDSETREPEAT Set keyboard typematic rate. There has existed an ioctl command, KDSETRAD, for the same purpose. However, KDSETRAD is dependent on the AT keyboard. KDSETREPEAT provides more generic interface. KDSETRAD will still be supported in the atkbd driver. - Added new configuration options: ATKBD_DFLT_KEYMAP Specify a keymap to be used as the default, built-in keymap. (There has been undocumented options, DKKEYMAP, UKKEYMAP, GRKEYMAP, SWKEYMAP, RUKEYMAP, ESKEYMAP, and ISKEYMAP to set the default keymap. These options are now gone for good. The new option is more general.) KBD_DISABLE_KEYMAP_LOADING Don't allow the user to change the keymap.
Diffstat (limited to 'sys/dev/atkbdc/atkbd.c')
-rw-r--r--sys/dev/atkbdc/atkbd.c244
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 */
OpenPOWER on IntegriCloud