Changeset View
Changeset View
Standalone View
Standalone View
head/sys/dev/kbdmux/kbdmux.c
Show All 26 Lines | |||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
* SUCH DAMAGE. | * SUCH DAMAGE. | ||||
* | * | ||||
* $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $ | * $Id: kbdmux.c,v 1.4 2005/07/14 17:38:35 max Exp $ | ||||
* $FreeBSD$ | * $FreeBSD$ | ||||
*/ | */ | ||||
#include "opt_compat.h" | #include "opt_compat.h" | ||||
#include "opt_evdev.h" | |||||
#include "opt_kbd.h" | #include "opt_kbd.h" | ||||
#include "opt_kbdmux.h" | #include "opt_kbdmux.h" | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||
#include <sys/consio.h> | #include <sys/consio.h> | ||||
#include <sys/fcntl.h> | #include <sys/fcntl.h> | ||||
Show All 16 Lines | |||||
/* the initial key map, accent map and fkey strings */ | /* the initial key map, accent map and fkey strings */ | ||||
#ifdef KBDMUX_DFLT_KEYMAP | #ifdef KBDMUX_DFLT_KEYMAP | ||||
#define KBD_DFLT_KEYMAP | #define KBD_DFLT_KEYMAP | ||||
#include "kbdmuxmap.h" | #include "kbdmuxmap.h" | ||||
#endif | #endif | ||||
#include <dev/kbd/kbdtables.h> | #include <dev/kbd/kbdtables.h> | ||||
#ifdef EVDEV_SUPPORT | |||||
#include <dev/evdev/evdev.h> | |||||
#include <dev/evdev/input.h> | |||||
#endif | |||||
#define KEYBOARD_NAME "kbdmux" | #define KEYBOARD_NAME "kbdmux" | ||||
MALLOC_DECLARE(M_KBDMUX); | MALLOC_DECLARE(M_KBDMUX); | ||||
MALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor"); | MALLOC_DEFINE(M_KBDMUX, KEYBOARD_NAME, "Keyboard multiplexor"); | ||||
/***************************************************************************** | /***************************************************************************** | ||||
***************************************************************************** | ***************************************************************************** | ||||
** Keyboard state | ** Keyboard state | ||||
▲ Show 20 Lines • Show All 79 Lines • ▼ Show 20 Lines | #define TASK (1 << 2) /* interrupt task queued */ | ||||
int ks_polling; /* poll nesting count */ | int ks_polling; /* poll nesting count */ | ||||
int ks_mode; /* K_XLATE, K_RAW, K_CODE */ | int ks_mode; /* K_XLATE, K_RAW, K_CODE */ | ||||
int ks_state; /* state */ | int ks_state; /* state */ | ||||
int ks_accents; /* accent key index (> 0) */ | int ks_accents; /* accent key index (> 0) */ | ||||
u_int ks_composed_char; /* composed char code */ | u_int ks_composed_char; /* composed char code */ | ||||
u_char ks_prefix; /* AT scan code prefix */ | u_char ks_prefix; /* AT scan code prefix */ | ||||
#ifdef EVDEV_SUPPORT | |||||
struct evdev_dev * ks_evdev; | |||||
int ks_evdev_state; | |||||
#endif | |||||
SLIST_HEAD(, kbdmux_kbd) ks_kbds; /* keyboards */ | SLIST_HEAD(, kbdmux_kbd) ks_kbds; /* keyboards */ | ||||
KBDMUX_LOCK_DECL_GLOBAL; | KBDMUX_LOCK_DECL_GLOBAL; | ||||
}; | }; | ||||
typedef struct kbdmux_state kbdmux_state_t; | typedef struct kbdmux_state kbdmux_state_t; | ||||
/***************************************************************************** | /***************************************************************************** | ||||
▲ Show 20 Lines • Show All 196 Lines • ▼ Show 20 Lines | static keyboard_switch_t kbdmuxsw = { | ||||
.clear_state = kbdmux_clear_state, | .clear_state = kbdmux_clear_state, | ||||
.get_state = kbdmux_get_state, | .get_state = kbdmux_get_state, | ||||
.set_state = kbdmux_set_state, | .set_state = kbdmux_set_state, | ||||
.get_fkeystr = genkbd_get_fkeystr, | .get_fkeystr = genkbd_get_fkeystr, | ||||
.poll = kbdmux_poll, | .poll = kbdmux_poll, | ||||
.diag = genkbd_diag, | .diag = genkbd_diag, | ||||
}; | }; | ||||
#ifdef EVDEV_SUPPORT | |||||
static const struct evdev_methods kbdmux_evdev_methods = { | |||||
.ev_event = evdev_ev_kbd_event, | |||||
}; | |||||
#endif | |||||
/* | /* | ||||
* Return the number of found keyboards | * Return the number of found keyboards | ||||
*/ | */ | ||||
static int | static int | ||||
kbdmux_configure(int flags) | kbdmux_configure(int flags) | ||||
{ | { | ||||
return (1); | return (1); | ||||
} | } | ||||
Show All 17 Lines | |||||
kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags) | kbdmux_init(int unit, keyboard_t **kbdp, void *arg, int flags) | ||||
{ | { | ||||
keyboard_t *kbd = NULL; | keyboard_t *kbd = NULL; | ||||
kbdmux_state_t *state = NULL; | kbdmux_state_t *state = NULL; | ||||
keymap_t *keymap = NULL; | keymap_t *keymap = NULL; | ||||
accentmap_t *accmap = NULL; | accentmap_t *accmap = NULL; | ||||
fkeytab_t *fkeymap = NULL; | fkeytab_t *fkeymap = NULL; | ||||
int error, needfree, fkeymap_size, delay[2]; | int error, needfree, fkeymap_size, delay[2]; | ||||
#ifdef EVDEV_SUPPORT | |||||
struct evdev_dev *evdev; | |||||
char phys_loc[NAMELEN]; | |||||
#endif | |||||
if (*kbdp == NULL) { | if (*kbdp == NULL) { | ||||
*kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO); | *kbdp = kbd = malloc(sizeof(*kbd), M_KBDMUX, M_NOWAIT | M_ZERO); | ||||
state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO); | state = malloc(sizeof(*state), M_KBDMUX, M_NOWAIT | M_ZERO); | ||||
keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT); | keymap = malloc(sizeof(key_map), M_KBDMUX, M_NOWAIT); | ||||
accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT); | accmap = malloc(sizeof(accent_map), M_KBDMUX, M_NOWAIT); | ||||
fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT); | fkeymap = malloc(sizeof(fkey_tab), M_KBDMUX, M_NOWAIT); | ||||
fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); | fkeymap_size = sizeof(fkey_tab)/sizeof(fkey_tab[0]); | ||||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { | ||||
kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; | kbd->kb_config = flags & ~KB_CONF_PROBE_ONLY; | ||||
kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); | kbdmux_ioctl(kbd, KDSETLED, (caddr_t)&state->ks_state); | ||||
delay[0] = kbd->kb_delay1; | delay[0] = kbd->kb_delay1; | ||||
delay[1] = kbd->kb_delay2; | delay[1] = kbd->kb_delay2; | ||||
kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); | kbdmux_ioctl(kbd, KDSETREPEAT, (caddr_t)delay); | ||||
#ifdef EVDEV_SUPPORT | |||||
/* register as evdev provider */ | |||||
evdev = evdev_alloc(); | |||||
evdev_set_name(evdev, "System keyboard multiplexer"); | |||||
snprintf(phys_loc, NAMELEN, KEYBOARD_NAME"%d", unit); | |||||
evdev_set_phys(evdev, phys_loc); | |||||
evdev_set_id(evdev, BUS_VIRTUAL, 0, 0, 0); | |||||
evdev_set_methods(evdev, kbd, &kbdmux_evdev_methods); | |||||
evdev_support_event(evdev, EV_SYN); | |||||
evdev_support_event(evdev, EV_KEY); | |||||
evdev_support_event(evdev, EV_LED); | |||||
evdev_support_event(evdev, EV_REP); | |||||
evdev_support_all_known_keys(evdev); | |||||
evdev_support_led(evdev, LED_NUML); | |||||
evdev_support_led(evdev, LED_CAPSL); | |||||
evdev_support_led(evdev, LED_SCROLLL); | |||||
if (evdev_register(evdev)) | |||||
evdev_free(evdev); | |||||
else | |||||
state->ks_evdev = evdev; | |||||
state->ks_evdev_state = 0; | |||||
#endif | |||||
KBD_INIT_DONE(kbd); | KBD_INIT_DONE(kbd); | ||||
} | } | ||||
if (!KBD_IS_CONFIGURED(kbd)) { | if (!KBD_IS_CONFIGURED(kbd)) { | ||||
if (kbd_register(kbd) < 0) { | if (kbd_register(kbd) < 0) { | ||||
error = ENXIO; | error = ENXIO; | ||||
goto bad; | goto bad; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | while ((k = SLIST_FIRST(&state->ks_kbds)) != NULL) { | ||||
free(k, M_KBDMUX); | free(k, M_KBDMUX); | ||||
} | } | ||||
KBDMUX_UNLOCK(state); | KBDMUX_UNLOCK(state); | ||||
kbd_unregister(kbd); | kbd_unregister(kbd); | ||||
#ifdef EVDEV_SUPPORT | |||||
evdev_free(state->ks_evdev); | |||||
#endif | |||||
KBDMUX_LOCK_DESTROY(state); | KBDMUX_LOCK_DESTROY(state); | ||||
bzero(state, sizeof(*state)); | bzero(state, sizeof(*state)); | ||||
free(state, M_KBDMUX); | free(state, M_KBDMUX); | ||||
free(kbd->kb_keymap, M_KBDMUX); | free(kbd->kb_keymap, M_KBDMUX); | ||||
free(kbd->kb_accentmap, M_KBDMUX); | free(kbd->kb_accentmap, M_KBDMUX); | ||||
free(kbd->kb_fkeytab, M_KBDMUX); | free(kbd->kb_fkeytab, M_KBDMUX); | ||||
free(kbd, M_KBDMUX); | free(kbd, M_KBDMUX); | ||||
▲ Show 20 Lines • Show All 146 Lines • ▼ Show 20 Lines | if (scancode == -1) { | ||||
KBDMUX_UNLOCK(state); | KBDMUX_UNLOCK(state); | ||||
return (NOKEY); | return (NOKEY); | ||||
} | } | ||||
/* XXX FIXME: check for -1 if wait == 1! */ | /* XXX FIXME: check for -1 if wait == 1! */ | ||||
kbd->kb_count ++; | kbd->kb_count ++; | ||||
#ifdef EVDEV_SUPPORT | |||||
/* push evdev event */ | |||||
if (evdev_rcpt_mask & EVDEV_RCPT_KBDMUX && state->ks_evdev != NULL) { | |||||
uint16_t key = evdev_scancode2key(&state->ks_evdev_state, | |||||
scancode); | |||||
if (key != KEY_RESERVED) { | |||||
evdev_push_event(state->ks_evdev, EV_KEY, | |||||
key, scancode & 0x80 ? 0 : 1); | |||||
evdev_sync(state->ks_evdev); | |||||
} | |||||
} | |||||
#endif | |||||
/* return the byte as is for the K_RAW mode */ | /* return the byte as is for the K_RAW mode */ | ||||
if (state->ks_mode == K_RAW) { | if (state->ks_mode == K_RAW) { | ||||
KBDMUX_UNLOCK(state); | KBDMUX_UNLOCK(state); | ||||
return (scancode); | return (scancode); | ||||
} | } | ||||
/* translate the scan code into a keycode */ | /* translate the scan code into a keycode */ | ||||
keycode = scancode & 0x7F; | keycode = scancode & 0x7F; | ||||
▲ Show 20 Lines • Show All 410 Lines • ▼ Show 20 Lines | case KDSETLED: /* set keyboard LED */ | ||||
/* NOTE: lock key state in ks_state won't be changed */ | /* NOTE: lock key state in ks_state won't be changed */ | ||||
if (*(int *)arg & ~LOCK_MASK) { | if (*(int *)arg & ~LOCK_MASK) { | ||||
KBDMUX_UNLOCK(state); | KBDMUX_UNLOCK(state); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
KBD_LED_VAL(kbd) = *(int *)arg; | KBD_LED_VAL(kbd) = *(int *)arg; | ||||
#ifdef EVDEV_SUPPORT | |||||
if (state->ks_evdev != NULL && | |||||
evdev_rcpt_mask & EVDEV_RCPT_KBDMUX) | |||||
evdev_push_leds(state->ks_evdev, *(int *)arg); | |||||
#endif | |||||
/* KDSETLED on all slave keyboards */ | /* KDSETLED on all slave keyboards */ | ||||
SLIST_FOREACH(k, &state->ks_kbds, next) | SLIST_FOREACH(k, &state->ks_kbds, next) | ||||
(void)kbdd_ioctl(k->kbd, KDSETLED, arg); | (void)kbdd_ioctl(k->kbd, KDSETLED, arg); | ||||
KBDMUX_UNLOCK(state); | KBDMUX_UNLOCK(state); | ||||
break; | break; | ||||
case KDGKBSTATE: /* get lock key state */ | case KDGKBSTATE: /* get lock key state */ | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | case KDSETRAD: /* set keyboard repeat rate (old interface) */ | ||||
if (mode & ~0x7f) { | if (mode & ~0x7f) { | ||||
KBDMUX_UNLOCK(state); | KBDMUX_UNLOCK(state); | ||||
return (EINVAL); | return (EINVAL); | ||||
} | } | ||||
kbd->kb_delay1 = delays[(mode >> 5) & 3]; | kbd->kb_delay1 = delays[(mode >> 5) & 3]; | ||||
kbd->kb_delay2 = rates[mode & 0x1f]; | kbd->kb_delay2 = rates[mode & 0x1f]; | ||||
#ifdef EVDEV_SUPPORT | |||||
if (state->ks_evdev != NULL && | |||||
evdev_rcpt_mask & EVDEV_RCPT_KBDMUX) | |||||
evdev_push_repeats(state->ks_evdev, kbd); | |||||
#endif | |||||
/* perform command on all slave keyboards */ | /* perform command on all slave keyboards */ | ||||
SLIST_FOREACH(k, &state->ks_kbds, next) | SLIST_FOREACH(k, &state->ks_kbds, next) | ||||
(void)kbdd_ioctl(k->kbd, cmd, arg); | (void)kbdd_ioctl(k->kbd, cmd, arg); | ||||
KBDMUX_UNLOCK(state); | KBDMUX_UNLOCK(state); | ||||
break; | break; | ||||
case PIO_KEYMAP: /* set keyboard translation table */ | case PIO_KEYMAP: /* set keyboard translation table */ | ||||
▲ Show 20 Lines • Show All 182 Lines • ▼ Show 20 Lines | default: | ||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
break; | break; | ||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
DEV_MODULE(kbdmux, kbdmux_modevent, NULL); | DEV_MODULE(kbdmux, kbdmux_modevent, NULL); | ||||
#ifdef EVDEV_SUPPORT | |||||
MODULE_DEPEND(kbdmux, evdev, 1, 1, 1); | |||||
#endif |