diff options
Diffstat (limited to 'sys/dev/usb/ukbd.c')
-rw-r--r-- | sys/dev/usb/ukbd.c | 1538 |
1 files changed, 0 insertions, 1538 deletions
diff --git a/sys/dev/usb/ukbd.c b/sys/dev/usb/ukbd.c deleted file mode 100644 index 5a7c9fc..0000000 --- a/sys/dev/usb/ukbd.c +++ /dev/null @@ -1,1538 +0,0 @@ -/*- - * Copyright (c) 1998 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Lennart Augustsson (lennart@augustsson.net) at - * Carlstedt Research & Technology. - * - * 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. - * 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. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``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 FOUNDATION OR CONTRIBUTORS - * 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. - * - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -/* - * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf - */ - -#include "opt_compat.h" -#include "opt_kbd.h" -#include "opt_ukbd.h" - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/ioccom.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/file.h> -#include <sys/limits.h> -#include <sys/selinfo.h> -#include <sys/sysctl.h> -#include <sys/uio.h> - -#include <dev/usb/usb.h> -#include <dev/usb/usbhid.h> -#include <dev/usb/usbdi.h> -#include <dev/usb/usbdi_util.h> -#include "usbdevs.h" -#include <dev/usb/usb_quirks.h> -#include <dev/usb/hid.h> - -#include <sys/kbio.h> -#include <dev/kbd/kbdreg.h> - -#define UKBD_EMULATE_ATSCANCODE 1 - -#define DRIVER_NAME "ukbd" - -#define delay(d) DELAY(d) - -#ifdef USB_DEBUG -#define DPRINTF(x) if (ukbddebug) printf x -#define DPRINTFN(n,x) if (ukbddebug>(n)) printf x -int ukbddebug = 0; -SYSCTL_NODE(_hw_usb, OID_AUTO, ukbd, CTLFLAG_RW, 0, "USB ukbd"); -SYSCTL_INT(_hw_usb_ukbd, OID_AUTO, debug, CTLFLAG_RW, - &ukbddebug, 0, "ukbd debug level"); -#else -#define DPRINTF(x) -#define DPRINTFN(n,x) -#endif - -#define UPROTO_BOOT_KEYBOARD 1 - -#define NKEYCODE 6 - -struct ukbd_data { - u_int8_t modifiers; -#define MOD_CONTROL_L 0x01 -#define MOD_CONTROL_R 0x10 -#define MOD_SHIFT_L 0x02 -#define MOD_SHIFT_R 0x20 -#define MOD_ALT_L 0x04 -#define MOD_ALT_R 0x40 -#define MOD_WIN_L 0x08 -#define MOD_WIN_R 0x80 - u_int8_t reserved; - u_int8_t keycode[NKEYCODE]; -}; - -#define MAXKEYS (NMOD+2*NKEYCODE) - -typedef struct ukbd_softc { - device_t sc_dev; /* base device */ -} ukbd_softc_t; - -#define UKBD_CHUNK 128 /* chunk size for read */ -#define UKBD_BSIZE 1020 /* buffer size */ - -typedef void usbd_intr_t(usbd_xfer_handle, usbd_private_handle, usbd_status); -typedef void usbd_disco_t(void *); - -static usbd_intr_t ukbd_intr; -static int ukbd_driver_load(module_t mod, int what, void *arg); - -static device_probe_t ukbd_match; -static device_attach_t ukbd_attach; -static device_detach_t ukbd_detach; -static device_resume_t ukbd_resume; - -static device_method_t ukbd_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, ukbd_match), - DEVMETHOD(device_attach, ukbd_attach), - DEVMETHOD(device_detach, ukbd_detach), - DEVMETHOD(device_resume, ukbd_resume), - - { 0, 0 } -}; - -static driver_t ukbd_driver = { - "ukbd", - ukbd_methods, - sizeof(struct ukbd_softc) -}; - -static devclass_t ukbd_devclass; - -MODULE_DEPEND(ukbd, usb, 1, 1, 1); -DRIVER_MODULE(ukbd, uhub, ukbd_driver, ukbd_devclass, ukbd_driver_load, 0); - -static int -ukbd_match(device_t self) -{ - struct usb_attach_arg *uaa = device_get_ivars(self); - - keyboard_switch_t *sw; - void *arg[2]; - int unit = device_get_unit(self); - - sw = kbd_get_switch(DRIVER_NAME); - if (sw == NULL) - return (UMATCH_NONE); - - arg[0] = (void *)uaa; - arg[1] = (void *)ukbd_intr; - if ((*sw->probe)(unit, (void *)arg, 0)) - return (UMATCH_NONE); - - if (usbd_get_quirks(uaa->device)->uq_flags & UQ_KBD_IGNORE) - return (UMATCH_NONE); - - return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); -} - -static int -ukbd_attach(device_t self) -{ - struct ukbd_softc *sc = device_get_softc(self); - struct usb_attach_arg *uaa = device_get_ivars(self); - usbd_interface_handle iface = uaa->iface; - usb_interface_descriptor_t *id; - - keyboard_switch_t *sw; - keyboard_t *kbd; - void *arg[2]; - int unit = device_get_unit(self); - - sc->sc_dev = self; - sw = kbd_get_switch(DRIVER_NAME); - if (sw == NULL) - return ENXIO; - - id = usbd_get_interface_descriptor(iface); - - arg[0] = (void *)uaa; - arg[1] = (void *)ukbd_intr; - kbd = NULL; - if ((*sw->probe)(unit, (void *)arg, 0)) - return ENXIO; - if ((*sw->init)(unit, &kbd, (void *)arg, 0)) - return ENXIO; - (*sw->enable)(kbd); - -#ifdef KBD_INSTALL_CDEV - if (kbd_attach(kbd)) - return ENXIO; -#endif - if (bootverbose) - (*sw->diag)(kbd, bootverbose); - - return 0; -} - -int -ukbd_detach(device_t self) -{ - keyboard_t *kbd; - int error; - - kbd = kbd_get_keyboard(kbd_find_keyboard(DRIVER_NAME, - device_get_unit(self))); - if (kbd == NULL) { - DPRINTF(("%s: keyboard not attached!?\n", device_get_nameunit(self))); - return ENXIO; - } - kbdd_disable(kbd); - -#ifdef KBD_INSTALL_CDEV - error = kbd_detach(kbd); - if (error) - return error; -#endif - error = kbdd_term(kbd); - if (error) - return error; - - DPRINTF(("%s: disconnected\n", device_get_nameunit(self))); - - return (0); -} - -static int -ukbd_resume(device_t self) -{ - keyboard_t *kbd; - - kbd = kbd_get_keyboard(kbd_find_keyboard(DRIVER_NAME, - device_get_unit(self))); - if (kbd) - kbdd_clear_state(kbd); - return (0); -} - -void -ukbd_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) -{ - keyboard_t *kbd = (keyboard_t *)addr; - - kbdd_intr(kbd, (void *)status); -} - -#define UKBD_DEFAULT 0 - -#define KEY_ERROR 0x01 - -#define KEY_PRESS 0 -#define KEY_RELEASE 0x400 -#define KEY_INDEX(c) ((c) & ~KEY_RELEASE) - -#define SCAN_PRESS 0 -#define SCAN_RELEASE 0x80 -#define SCAN_PREFIX_E0 0x100 -#define SCAN_PREFIX_E1 0x200 -#define SCAN_PREFIX_CTL 0x400 -#define SCAN_PREFIX_SHIFT 0x800 -#define SCAN_PREFIX (SCAN_PREFIX_E0 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL \ - | SCAN_PREFIX_SHIFT) -#define SCAN_CHAR(c) ((c) & 0x7f) - -#define NMOD 8 -static struct { - int mask, key; -} ukbd_mods[NMOD] = { - { MOD_CONTROL_L, 0xe0 }, - { MOD_CONTROL_R, 0xe4 }, - { MOD_SHIFT_L, 0xe1 }, - { MOD_SHIFT_R, 0xe5 }, - { MOD_ALT_L, 0xe2 }, - { MOD_ALT_R, 0xe6 }, - { MOD_WIN_L, 0xe3 }, - { MOD_WIN_R, 0xe7 }, -}; - -#define NN 0 /* no translation */ -/* - * Translate USB keycodes to AT keyboard scancodes. - */ -/* - * FIXME: Mac USB keyboard generates: - * 0x53: keypad NumLock/Clear - * 0x66: Power - * 0x67: keypad = - * 0x68: F13 - * 0x69: F14 - * 0x6a: F15 - */ -static u_int8_t ukbd_trtab[256] = { - 0, 0, 0, 0, 30, 48, 46, 32, /* 00 - 07 */ - 18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */ - 50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */ - 22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */ - 4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */ - 28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */ - 27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */ - 53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */ - 65, 66, 67, 68, 87, 88, 92, 70, /* 40 - 47 */ - 104, 102, 94, 96, 103, 99, 101, 98, /* 48 - 4F */ - 97, 100, 95, 69, 91, 55, 74, 78, /* 50 - 57 */ - 89, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */ - 72, 73, 82, 83, 86, 107, 122, NN, /* 60 - 67 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 68 - 6F */ - NN, NN, NN, NN, 115, 108, 111, 113, /* 70 - 77 */ - 109, 110, 112, 118, 114, 116, 117, 119, /* 78 - 7F */ - 121, 120, NN, NN, NN, NN, NN, 115, /* 80 - 87 */ - 112, 125, 121, 123, NN, NN, NN, NN, /* 88 - 8F */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 90 - 97 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */ - NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */ - NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */ - NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */ - NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */ - 29, 42, 56, 105, 90, 54, 93, 106, /* E0 - E7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* E8 - EF */ - NN, NN, NN, NN, NN, NN, NN, NN, /* F0 - F7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* F8 - FF */ -}; - -typedef struct ukbd_state { - usbd_interface_handle ks_iface; /* interface */ - usbd_pipe_handle ks_intrpipe; /* interrupt pipe */ - struct usb_attach_arg *ks_uaa; - int ks_ep_addr; - - struct ukbd_data ks_ndata; - struct ukbd_data ks_odata; - u_long ks_ntime[NKEYCODE]; - u_long ks_otime[NKEYCODE]; - -#define INPUTBUFSIZE (NMOD + 2*NKEYCODE) - u_int ks_input[INPUTBUFSIZE]; /* input buffer */ - int ks_inputs; - int ks_inputhead; - int ks_inputtail; - - int ks_ifstate; -#define INTRENABLED (1 << 0) -#define DISCONNECTED (1 << 1) - - struct callout ks_timeout_handle; - - 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) */ -#ifdef UKBD_EMULATE_ATSCANCODE - u_int ks_buffered_char[2]; - u_int8_t ks_leds; /* store for async led requests */ -#endif -} ukbd_state_t; - -/* keyboard driver declaration */ -static int ukbd_configure(int flags); -static kbd_probe_t ukbd_probe; -static kbd_init_t ukbd_init; -static kbd_term_t ukbd_term; -static kbd_intr_t ukbd_interrupt; -static kbd_test_if_t ukbd_test_if; -static kbd_enable_t ukbd_enable; -static kbd_disable_t ukbd_disable; -static kbd_read_t ukbd_read; -static kbd_check_t ukbd_check; -static kbd_read_char_t ukbd_read_char; -static kbd_check_char_t ukbd_check_char; -static kbd_ioctl_t ukbd_ioctl; -static kbd_lock_t ukbd_lock; -static kbd_clear_state_t ukbd_clear_state; -static kbd_get_state_t ukbd_get_state; -static kbd_set_state_t ukbd_set_state; -static kbd_poll_mode_t ukbd_poll; - -keyboard_switch_t ukbdsw = { - ukbd_probe, - ukbd_init, - ukbd_term, - ukbd_interrupt, - ukbd_test_if, - ukbd_enable, - ukbd_disable, - ukbd_read, - ukbd_check, - ukbd_read_char, - ukbd_check_char, - ukbd_ioctl, - ukbd_lock, - ukbd_clear_state, - ukbd_get_state, - ukbd_set_state, - genkbd_get_fkeystr, - ukbd_poll, - genkbd_diag, -}; - -KEYBOARD_DRIVER(ukbd, ukbdsw, ukbd_configure); - -/* local functions */ -static int ukbd_enable_intr(keyboard_t *kbd, int on, - usbd_intr_t *func); -static void ukbd_timeout(void *arg); - -static int ukbd_getc(ukbd_state_t *state, int wait); -static int probe_keyboard(struct usb_attach_arg *uaa, int flags); -static int init_keyboard(ukbd_state_t *state, int *type, - int flags); -static void set_leds(ukbd_state_t *state, int leds); -static int set_typematic(keyboard_t *kbd, int code); -#ifdef UKBD_EMULATE_ATSCANCODE -static int keycode2scancode(int keycode, int shift, int up); -#endif - -/* local variables */ - -/* the initial key map, accent map and fkey strings */ -#if defined(UKBD_DFLT_KEYMAP) && !defined(KLD_MODULE) -#define KBD_DFLT_KEYMAP -#include "ukbdmap.h" -#endif -#include <dev/kbd/kbdtables.h> - -/* structures for the default keyboard */ -static keyboard_t default_kbd; -static ukbd_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 int -ukbd_configure(int flags) -{ - return 0; - -#if 0 /* not yet */ - keyboard_t *kbd; - device_t device; - struct usb_attach_arg *uaa; - void *arg[2]; - - device = devclass_get_device(ukbd_devclass, UKBD_DEFAULT); - if (device == NULL) - return 0; - uaa = (struct usb_attach_arg *)device_get_ivars(device); - if (uaa == NULL) - return 0; - - /* probe the default keyboard */ - arg[0] = (void *)uaa; - arg[1] = (void *)ukbd_intr; - kbd = NULL; - if (ukbd_probe(UKBD_DEFAULT, arg, flags)) - return 0; - if (ukbd_init(UKBD_DEFAULT, &kbd, arg, flags)) - return 0; - - /* return the number of found keyboards */ - return 1; -#endif -} - -/* low-level functions */ - -/* detect a keyboard */ -static int -ukbd_probe(int unit, void *arg, int flags) -{ - void **data; - struct usb_attach_arg *uaa; - - data = (void **)arg; - uaa = (struct usb_attach_arg *)data[0]; - - /* XXX */ - if (unit == UKBD_DEFAULT) { - if (KBD_IS_PROBED(&default_kbd)) - return 0; - } - if (probe_keyboard(uaa, flags)) - return ENXIO; - return 0; -} - -/* reset and initialize the device */ -static int -ukbd_init(int unit, keyboard_t **kbdp, void *arg, int flags) -{ - keyboard_t *kbd; - ukbd_state_t *state; - keymap_t *keymap; - accentmap_t *accmap; - fkeytab_t *fkeymap; - int fkeymap_size; - void **data = (void **)arg; - struct usb_attach_arg *uaa = (struct usb_attach_arg *)data[0]; - - /* XXX */ - if (unit == UKBD_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)) { - if (state != NULL) - free(state, M_DEVBUF); - if (keymap != NULL) - free(keymap, M_DEVBUF); - if (accmap != NULL) - free(accmap, M_DEVBUF); - if (fkeymap != NULL) - free(fkeymap, M_DEVBUF); - free(kbd, M_DEVBUF); - return ENOMEM; - } - } else if (KBD_IS_INITIALIZED(*kbdp) && KBD_IS_CONFIGURED(*kbdp)) { - return 0; - } else { - kbd = *kbdp; - state = (ukbd_state_t *)kbd->kb_data; - keymap = kbd->kb_keymap; - accmap = kbd->kb_accentmap; - fkeymap = kbd->kb_fkeytab; - fkeymap_size = kbd->kb_fkeytab_size; - } - - if (!KBD_IS_PROBED(kbd)) { - kbd_init_struct(kbd, DRIVER_NAME, KB_OTHER, unit, flags, 0, 0); - bzero(state, sizeof(*state)); - 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(uaa, flags)) - return ENXIO; - else - KBD_FOUND_DEVICE(kbd); - ukbd_clear_state(kbd); - state->ks_mode = K_XLATE; - state->ks_iface = uaa->iface; - state->ks_uaa = uaa; - state->ks_ifstate = 0; - callout_init(&state->ks_timeout_handle, 0); - /* - * FIXME: set the initial value for lock keys in ks_state - * according to the BIOS data? - */ - KBD_PROBE_DONE(kbd); - } - if (!KBD_IS_INITIALIZED(kbd) && !(flags & KB_CONF_PROBE_ONLY)) { - if (KBD_HAS_DEVICE(kbd) - && init_keyboard((ukbd_state_t *)kbd->kb_data, - &kbd->kb_type, kbd->kb_flags)) { - kbd->kb_flags = 0; - /* XXX: Missing free()'s */ - return ENXIO; - } - ukbd_ioctl(kbd, KDSETLED, (caddr_t)&(state->ks_state)); - KBD_INIT_DONE(kbd); - } - if (!KBD_IS_CONFIGURED(kbd)) { - if (kbd_register(kbd) < 0) { - kbd->kb_flags = 0; - /* XXX: Missing free()'s */ - return ENXIO; - } - if (ukbd_enable_intr(kbd, TRUE, (usbd_intr_t *)data[1]) == 0) - ukbd_timeout((void *)kbd); - KBD_CONFIG_DONE(kbd); - } - - return 0; -} - -static int -ukbd_enable_intr(keyboard_t *kbd, int on, usbd_intr_t *func) -{ - ukbd_state_t *state = (ukbd_state_t *)kbd->kb_data; - usbd_status err; - - if (on) { - /* Set up interrupt pipe. */ - if (state->ks_ifstate & INTRENABLED) - return EBUSY; - - state->ks_ifstate |= INTRENABLED; - err = usbd_open_pipe_intr(state->ks_iface, state->ks_ep_addr, - USBD_SHORT_XFER_OK, - &state->ks_intrpipe, kbd, - &state->ks_ndata, - sizeof(state->ks_ndata), func, - USBD_DEFAULT_INTERVAL); - if (err) - return (EIO); - } else { - /* Disable interrupts. */ - usbd_abort_pipe(state->ks_intrpipe); - usbd_close_pipe(state->ks_intrpipe); - - state->ks_ifstate &= ~INTRENABLED; - } - - return (0); -} - -/* finish using this keyboard */ -static int -ukbd_term(keyboard_t *kbd) -{ - ukbd_state_t *state; - int error; - int s; - - s = splusb(); - - state = (ukbd_state_t *)kbd->kb_data; - DPRINTF(("ukbd_term: ks_ifstate=0x%x\n", state->ks_ifstate)); - - callout_stop(&state->ks_timeout_handle); - - if (state->ks_ifstate & INTRENABLED) - ukbd_enable_intr(kbd, FALSE, NULL); - if (state->ks_ifstate & INTRENABLED) { - splx(s); - DPRINTF(("ukbd_term: INTRENABLED!\n")); - return ENXIO; - } - - error = kbd_unregister(kbd); - DPRINTF(("ukbd_term: kbd_unregister() %d\n", error)); - if (error == 0) { - kbd->kb_flags = 0; - if (kbd != &default_kbd) { - free(kbd->kb_keymap, M_DEVBUF); - free(kbd->kb_accentmap, M_DEVBUF); - free(kbd->kb_fkeytab, M_DEVBUF); - free(state, M_DEVBUF); - free(kbd, M_DEVBUF); - } - } - - splx(s); - return error; -} - - -/* keyboard interrupt routine */ - -static void -ukbd_timeout(void *arg) -{ - keyboard_t *kbd; - ukbd_state_t *state; - int s; - - kbd = (keyboard_t *)arg; - state = (ukbd_state_t *)kbd->kb_data; - s = splusb(); - kbdd_intr(kbd, (void *)USBD_NORMAL_COMPLETION); - callout_reset(&state->ks_timeout_handle, hz / 40, ukbd_timeout, arg); - splx(s); -} - -static int -ukbd_interrupt(keyboard_t *kbd, void *arg) -{ - usbd_status status = (usbd_status)arg; - ukbd_state_t *state; - struct ukbd_data *ud; - struct timeval tv; - u_long now; - int mod, omod; - int key, c; - int i, j; - - DPRINTFN(5, ("ukbd_intr: status=%d\n", status)); - if (status == USBD_CANCELLED) - return 0; - - state = (ukbd_state_t *)kbd->kb_data; - ud = &state->ks_ndata; - - if (status != USBD_NORMAL_COMPLETION) { - DPRINTF(("ukbd_intr: status=%d\n", status)); - if (status == USBD_STALLED) - usbd_clear_endpoint_stall_async(state->ks_intrpipe); - return 0; - } - - if (ud->keycode[0] == KEY_ERROR) - return 0; /* ignore */ - - getmicrouptime(&tv); - now = (u_long)tv.tv_sec*1000 + (u_long)tv.tv_usec/1000; - -#define ADDKEY1(c) \ - if (state->ks_inputs < INPUTBUFSIZE) { \ - state->ks_input[state->ks_inputtail] = (c); \ - ++state->ks_inputs; \ - state->ks_inputtail = (state->ks_inputtail + 1)%INPUTBUFSIZE; \ - } - - mod = ud->modifiers; - omod = state->ks_odata.modifiers; - if (mod != omod) { - for (i = 0; i < NMOD; i++) - if (( mod & ukbd_mods[i].mask) != - (omod & ukbd_mods[i].mask)) - ADDKEY1(ukbd_mods[i].key | - (mod & ukbd_mods[i].mask - ? KEY_PRESS : KEY_RELEASE)); - } - - /* Check for released keys. */ - for (i = 0; i < NKEYCODE; i++) { - key = state->ks_odata.keycode[i]; - if (key == 0) - continue; - for (j = 0; j < NKEYCODE; j++) { - if (ud->keycode[j] == 0) - continue; - if (key == ud->keycode[j]) - goto rfound; - } - ADDKEY1(key | KEY_RELEASE); - rfound: - ; - } - - /* Check for pressed keys. */ - for (i = 0; i < NKEYCODE; i++) { - key = ud->keycode[i]; - if (key == 0) - continue; - state->ks_ntime[i] = now + kbd->kb_delay1; - for (j = 0; j < NKEYCODE; j++) { - if (state->ks_odata.keycode[j] == 0) - continue; - if (key == state->ks_odata.keycode[j]) { - state->ks_ntime[i] = state->ks_otime[j]; - if (state->ks_otime[j] > now) - goto pfound; - state->ks_ntime[i] = now + kbd->kb_delay2; - break; - } - } - ADDKEY1(key | KEY_PRESS); - /* - * If any other key is presently down, force its repeat to be - * well in the future (100s). This makes the last key to be - * pressed do the autorepeat. - */ - for (j = 0; j < NKEYCODE; j++) { - if (j != i) - state->ks_ntime[j] = now + 100 * 1000; - } - pfound: - ; - } - - state->ks_odata = *ud; - bcopy(state->ks_ntime, state->ks_otime, sizeof(state->ks_ntime)); - if (state->ks_inputs <= 0) - return 0; - -#ifdef USB_DEBUG - for (i = state->ks_inputhead, j = 0; j < state->ks_inputs; ++j, - i = (i + 1)%INPUTBUFSIZE) { - c = state->ks_input[i]; - DPRINTF(("0x%x (%d) %s\n", c, c, - (c & KEY_RELEASE) ? "released":"pressed")); - } - if (ud->modifiers) - DPRINTF(("mod:0x%04x ", ud->modifiers)); - for (i = 0; i < NKEYCODE; i++) { - if (ud->keycode[i]) - DPRINTF(("%d ", ud->keycode[i])); - } - DPRINTF(("\n")); -#endif /* USB_DEBUG */ - - if (state->ks_polling) - return 0; - - if (KBD_IS_ACTIVE(kbd) && KBD_IS_BUSY(kbd)) { - /* let the callback function to process the input */ - (*kbd->kb_callback.kc_func)(kbd, KBDIO_KEYINPUT, - kbd->kb_callback.kc_arg); - } else { - /* read and discard the input; no one is waiting for it */ - do { - c = ukbd_read_char(kbd, FALSE); - } while (c != NOKEY); - } - - return 0; -} - -static int -ukbd_getc(ukbd_state_t *state, int wait) -{ - int c; - int s; - - if (state->ks_polling) { - DPRINTFN(1,("ukbd_getc: polling\n")); - s = splusb(); - while (state->ks_inputs <= 0) { - usbd_dopoll(state->ks_iface); - if (wait == FALSE) - break; - } - splx(s); - } - s = splusb(); - if (state->ks_inputs <= 0) { - c = -1; - } else { - c = state->ks_input[state->ks_inputhead]; - --state->ks_inputs; - state->ks_inputhead = (state->ks_inputhead + 1)%INPUTBUFSIZE; - } - splx(s); - return c; -} - -/* test the interface to the device */ -static int -ukbd_test_if(keyboard_t *kbd) -{ - return 0; -} - -/* - * Enable the access to the device; until this function is called, - * the client cannot read from the keyboard. - */ -static int -ukbd_enable(keyboard_t *kbd) -{ - int s; - - s = splusb(); - KBD_ACTIVATE(kbd); - splx(s); - return 0; -} - -/* disallow the access to the device */ -static int -ukbd_disable(keyboard_t *kbd) -{ - int s; - - s = splusb(); - KBD_DEACTIVATE(kbd); - splx(s); - return 0; -} - -/* read one byte from the keyboard if it's allowed */ -static int -ukbd_read(keyboard_t *kbd, int wait) -{ - ukbd_state_t *state; - int usbcode; -#ifdef UKBD_EMULATE_ATSCANCODE - int keycode; - int scancode; -#endif - - state = (ukbd_state_t *)kbd->kb_data; -#ifdef UKBD_EMULATE_ATSCANCODE - if (state->ks_buffered_char[0]) { - scancode = state->ks_buffered_char[0]; - if (scancode & SCAN_PREFIX) { - state->ks_buffered_char[0] = scancode & ~SCAN_PREFIX; - return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); - } else { - state->ks_buffered_char[0] = state->ks_buffered_char[1]; - state->ks_buffered_char[1] = 0; - return scancode; - } - } -#endif /* UKBD_EMULATE_ATSCANCODE */ - - /* XXX */ - usbcode = ukbd_getc(state, wait); - if (!KBD_IS_ACTIVE(kbd) || (usbcode == -1)) - return -1; - ++kbd->kb_count; -#ifdef UKBD_EMULATE_ATSCANCODE - keycode = ukbd_trtab[KEY_INDEX(usbcode)]; - if (keycode == NN) - return -1; - - scancode = keycode2scancode(keycode, state->ks_ndata.modifiers, - usbcode & KEY_RELEASE); - if (scancode & SCAN_PREFIX) { - if (scancode & SCAN_PREFIX_CTL) { - state->ks_buffered_char[0] = - 0x1d | (scancode & SCAN_RELEASE); /* Ctrl */ - state->ks_buffered_char[1] = scancode & ~SCAN_PREFIX; - } else if (scancode & SCAN_PREFIX_SHIFT) { - state->ks_buffered_char[0] = - 0x2a | (scancode & SCAN_RELEASE); /* Shift */ - state->ks_buffered_char[1] = - scancode & ~SCAN_PREFIX_SHIFT; - } else { - state->ks_buffered_char[0] = scancode & ~SCAN_PREFIX; - state->ks_buffered_char[1] = 0; - } - return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); - } - return scancode; -#else /* !UKBD_EMULATE_ATSCANCODE */ - return usbcode; -#endif /* UKBD_EMULATE_ATSCANCODE */ -} - -/* check if data is waiting */ -static int -ukbd_check(keyboard_t *kbd) -{ - if (!KBD_IS_ACTIVE(kbd)) - return FALSE; -#ifdef UKBD_EMULATE_ATSCANCODE - if (((ukbd_state_t *)kbd->kb_data)->ks_buffered_char[0]) - return TRUE; -#endif - if (((ukbd_state_t *)kbd->kb_data)->ks_inputs > 0) - return TRUE; - return FALSE; -} - -/* read char from the keyboard */ -static u_int -ukbd_read_char(keyboard_t *kbd, int wait) -{ - ukbd_state_t *state; - u_int action; - int usbcode; - int keycode; -#ifdef UKBD_EMULATE_ATSCANCODE - int scancode; -#endif - - state = (ukbd_state_t *)kbd->kb_data; -next_code: - /* do we have a composed char to return? */ - if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) { - action = state->ks_composed_char; - state->ks_composed_char = 0; - if (action > UCHAR_MAX) - return ERRKEY; - return action; - } - -#ifdef UKBD_EMULATE_ATSCANCODE - /* do we have a pending raw scan code? */ - if (state->ks_mode == K_RAW) { - if (state->ks_buffered_char[0]) { - scancode = state->ks_buffered_char[0]; - if (scancode & SCAN_PREFIX) { - state->ks_buffered_char[0] = - scancode & ~SCAN_PREFIX; - return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); - } else { - state->ks_buffered_char[0] = - state->ks_buffered_char[1]; - state->ks_buffered_char[1] = 0; - return scancode; - } - } - } -#endif /* UKBD_EMULATE_ATSCANCODE */ - - /* see if there is something in the keyboard port */ - /* XXX */ - usbcode = ukbd_getc(state, wait); - if (usbcode == -1) - return NOKEY; - ++kbd->kb_count; - -#ifdef UKBD_EMULATE_ATSCANCODE - /* USB key index -> key code -> AT scan code */ - keycode = ukbd_trtab[KEY_INDEX(usbcode)]; - if (keycode == NN) - return NOKEY; - - /* return an AT scan code for the K_RAW mode */ - if (state->ks_mode == K_RAW) { - scancode = keycode2scancode(keycode, state->ks_ndata.modifiers, - usbcode & KEY_RELEASE); - if (scancode & SCAN_PREFIX) { - if (scancode & SCAN_PREFIX_CTL) { - state->ks_buffered_char[0] = - 0x1d | (scancode & SCAN_RELEASE); - state->ks_buffered_char[1] = - scancode & ~SCAN_PREFIX; - } else if (scancode & SCAN_PREFIX_SHIFT) { - state->ks_buffered_char[0] = - 0x2a | (scancode & SCAN_RELEASE); - state->ks_buffered_char[1] = - scancode & ~SCAN_PREFIX_SHIFT; - } else { - state->ks_buffered_char[0] = - scancode & ~SCAN_PREFIX; - state->ks_buffered_char[1] = 0; - } - return ((scancode & SCAN_PREFIX_E0) ? 0xe0 : 0xe1); - } - return scancode; - } -#else /* !UKBD_EMULATE_ATSCANCODE */ - /* return the byte as is for the K_RAW mode */ - if (state->ks_mode == K_RAW) - return usbcode; - - /* USB key index -> key code */ - keycode = ukbd_trtab[KEY_INDEX(usbcode)]; - if (keycode == NN) - return NOKEY; -#endif /* UKBD_EMULATE_ATSCANCODE */ - - switch (keycode) { - case 0x38: /* left alt (compose key) */ - if (usbcode & KEY_RELEASE) { - if (state->ks_flags & COMPOSE) { - state->ks_flags &= ~COMPOSE; - if (state->ks_composed_char > UCHAR_MAX) - state->ks_composed_char = 0; - } - } else { - if (!(state->ks_flags & COMPOSE)) { - state->ks_flags |= COMPOSE; - state->ks_composed_char = 0; - } - } - break; - /* XXX: I don't like these... */ - case 0x5c: /* print screen */ - if (state->ks_flags & ALTS) - keycode = 0x54; /* sysrq */ - break; - case 0x68: /* pause/break */ - if (state->ks_flags & CTLS) - keycode = 0x6c; /* break */ - break; - } - - /* return the key code in the K_CODE mode */ - if (usbcode & KEY_RELEASE) - keycode |= SCAN_RELEASE; - if (state->ks_mode == K_CODE) - return keycode; - - /* compose a character code */ - if (state->ks_flags & COMPOSE) { - switch (keycode) { - /* key pressed, process it */ - case 0x47: case 0x48: case 0x49: /* keypad 7,8,9 */ - state->ks_composed_char *= 10; - state->ks_composed_char += keycode - 0x40; - if (state->ks_composed_char > UCHAR_MAX) - return ERRKEY; - goto next_code; - case 0x4B: case 0x4C: case 0x4D: /* keypad 4,5,6 */ - state->ks_composed_char *= 10; - state->ks_composed_char += keycode - 0x47; - if (state->ks_composed_char > UCHAR_MAX) - return ERRKEY; - goto next_code; - case 0x4F: case 0x50: case 0x51: /* keypad 1,2,3 */ - state->ks_composed_char *= 10; - state->ks_composed_char += keycode - 0x4E; - if (state->ks_composed_char > UCHAR_MAX) - return ERRKEY; - goto next_code; - case 0x52: /* keypad 0 */ - state->ks_composed_char *= 10; - if (state->ks_composed_char > UCHAR_MAX) - return ERRKEY; - goto next_code; - - /* key released, no interest here */ - case SCAN_RELEASE | 0x47: - case SCAN_RELEASE | 0x48: - case SCAN_RELEASE | 0x49: /* keypad 7,8,9 */ - case SCAN_RELEASE | 0x4B: - case SCAN_RELEASE | 0x4C: - case SCAN_RELEASE | 0x4D: /* keypad 4,5,6 */ - case SCAN_RELEASE | 0x4F: - case SCAN_RELEASE | 0x50: - case SCAN_RELEASE | 0x51: /* keypad 1,2,3 */ - case SCAN_RELEASE | 0x52: /* keypad 0 */ - goto next_code; - - case 0x38: /* left alt key */ - break; - - default: - if (state->ks_composed_char > 0) { - state->ks_flags &= ~COMPOSE; - state->ks_composed_char = 0; - return ERRKEY; - } - break; - } - } - - /* keycode to key action */ - action = genkbd_keyaction(kbd, SCAN_CHAR(keycode), - keycode & SCAN_RELEASE, &state->ks_state, - &state->ks_accents); - if (action == NOKEY) - goto next_code; - else - return action; -} - -/* check if char is waiting */ -static int -ukbd_check_char(keyboard_t *kbd) -{ - ukbd_state_t *state; - - if (!KBD_IS_ACTIVE(kbd)) - return FALSE; - state = (ukbd_state_t *)kbd->kb_data; - if (!(state->ks_flags & COMPOSE) && (state->ks_composed_char > 0)) - return TRUE; - return ukbd_check(kbd); -} - -/* some useful control functions */ -static int -ukbd_ioctl(keyboard_t *kbd, u_long cmd, caddr_t arg) -{ - /* trasnlate LED_XXX bits into the device specific bits */ - static u_char ledmap[8] = { - 0, 2, 1, 3, 4, 6, 5, 7, - }; - ukbd_state_t *state = kbd->kb_data; - int s; - int i; -#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ - defined(COMPAT_FREEBSD4) || defined(COMPAT_43) - int ival; -#endif - - s = splusb(); - switch (cmd) { - - case KDGKBMODE: /* get keyboard mode */ - *(int *)arg = state->ks_mode; - break; -#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ - defined(COMPAT_FREEBSD4) || defined(COMPAT_43) - case _IO('K', 7): - ival = IOCPARM_IVAL(arg); - arg = (caddr_t)&ival; - /* FALLTHROUGH */ -#endif - case KDSKBMODE: /* set keyboard mode */ - switch (*(int *)arg) { - case K_XLATE: - if (state->ks_mode != K_XLATE) { - /* make lock key state and LED state match */ - state->ks_state &= ~LOCK_MASK; - state->ks_state |= KBD_LED_VAL(kbd); - } - /* FALLTHROUGH */ - case K_RAW: - case K_CODE: - if (state->ks_mode != *(int *)arg) { - ukbd_clear_state(kbd); - state->ks_mode = *(int *)arg; - } - break; - default: - splx(s); - return EINVAL; - } - break; - - case KDGETLED: /* get keyboard LED */ - *(int *)arg = KBD_LED_VAL(kbd); - break; -#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ - defined(COMPAT_FREEBSD4) || defined(COMPAT_43) - case _IO('K', 66): - ival = IOCPARM_IVAL(arg); - arg = (caddr_t)&ival; - /* FALLTHROUGH */ -#endif - case KDSETLED: /* set keyboard LED */ - /* NOTE: lock key state in ks_state won't be changed */ - if (*(int *)arg & ~LOCK_MASK) { - splx(s); - return EINVAL; - } - i = *(int *)arg; - /* replace CAPS LED with ALTGR LED for ALTGR keyboards */ - if (state->ks_mode == K_XLATE && - kbd->kb_keymap->n_keys > ALTGR_OFFSET) { - if (i & ALKED) - i |= CLKED; - else - i &= ~CLKED; - } - if (KBD_HAS_DEVICE(kbd)) { - set_leds(state, ledmap[i & LED_MASK]); - /* XXX: error check? */ - } - KBD_LED_VAL(kbd) = *(int *)arg; - break; - - case KDGKBSTATE: /* get lock key state */ - *(int *)arg = state->ks_state & LOCK_MASK; - break; -#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ - defined(COMPAT_FREEBSD4) || defined(COMPAT_43) - case _IO('K', 20): - ival = IOCPARM_IVAL(arg); - arg = (caddr_t)&ival; - /* FALLTHROUGH */ -#endif - case KDSKBSTATE: /* set lock key state */ - if (*(int *)arg & ~LOCK_MASK) { - splx(s); - return EINVAL; - } - state->ks_state &= ~LOCK_MASK; - state->ks_state |= *(int *)arg; - splx(s); - /* set LEDs and quit */ - return ukbd_ioctl(kbd, KDSETLED, arg); - - case KDSETREPEAT: /* set keyboard repeat rate (new interface) */ - splx(s); - if (!KBD_HAS_DEVICE(kbd)) - return 0; - if (((int *)arg)[1] < 0) - return EINVAL; - if (((int *)arg)[0] < 0) - return EINVAL; - else if (((int *)arg)[0] == 0) /* fastest possible value */ - kbd->kb_delay1 = 200; - else - kbd->kb_delay1 = ((int *)arg)[0]; - kbd->kb_delay2 = ((int *)arg)[1]; - return 0; - -#if defined(COMPAT_FREEBSD6) || defined(COMPAT_FREEBSD5) || \ - defined(COMPAT_FREEBSD4) || defined(COMPAT_43) - case _IO('K', 67): - ival = IOCPARM_IVAL(arg); - arg = (caddr_t)&ival; - /* FALLTHROUGH */ -#endif - case KDSETRAD: /* set keyboard repeat rate (old interface) */ - splx(s); - return set_typematic(kbd, *(int *)arg); - - case PIO_KEYMAP: /* set keyboard translation table */ - case PIO_KEYMAPENT: /* set keyboard translation table entry */ - case PIO_DEADKEYMAP: /* set accent key translation table */ - state->ks_accents = 0; - /* FALLTHROUGH */ - default: - splx(s); - return genkbd_commonioctl(kbd, cmd, arg); - -#ifdef USB_DEBUG - case USB_SETDEBUG: - ukbddebug = *(int *)arg; - break; -#endif - } - - splx(s); - return 0; -} - -/* lock the access to the keyboard */ -static int -ukbd_lock(keyboard_t *kbd, int lock) -{ - /* XXX ? */ - return TRUE; -} - -/* clear the internal state of the keyboard */ -static void -ukbd_clear_state(keyboard_t *kbd) -{ - ukbd_state_t *state; - - state = (ukbd_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; -#ifdef UKBD_EMULATE_ATSCANCODE - state->ks_buffered_char[0] = 0; - state->ks_buffered_char[1] = 0; -#endif - bzero(&state->ks_ndata, sizeof(state->ks_ndata)); - bzero(&state->ks_odata, sizeof(state->ks_odata)); - bzero(&state->ks_ntime, sizeof(state->ks_ntime)); - bzero(&state->ks_otime, sizeof(state->ks_otime)); -} - -/* save the internal state */ -static int -ukbd_get_state(keyboard_t *kbd, void *buf, size_t len) -{ - if (len == 0) - return sizeof(ukbd_state_t); - if (len < sizeof(ukbd_state_t)) - return -1; - bcopy(kbd->kb_data, buf, sizeof(ukbd_state_t)); - return 0; -} - -/* set the internal state */ -static int -ukbd_set_state(keyboard_t *kbd, void *buf, size_t len) -{ - if (len < sizeof(ukbd_state_t)) - return ENOMEM; - bcopy(buf, kbd->kb_data, sizeof(ukbd_state_t)); - return 0; -} - -static int -ukbd_poll(keyboard_t *kbd, int on) -{ - ukbd_state_t *state; - usbd_device_handle dev; - int s; - - state = (ukbd_state_t *)kbd->kb_data; - usbd_interface2device_handle(state->ks_iface, &dev); - - s = splusb(); - if (on) { - ++state->ks_polling; - if (state->ks_polling == 1) - usbd_set_polling(dev, on); - } else { - --state->ks_polling; - if (state->ks_polling == 0) - usbd_set_polling(dev, on); - } - splx(s); - return 0; -} - -/* local functions */ - -static int -probe_keyboard(struct usb_attach_arg *uaa, int flags) -{ - usb_interface_descriptor_t *id; - - if (!uaa->iface) /* we attach to ifaces only */ - return EINVAL; - - /* Check that this is a keyboard that speaks the boot protocol. */ - id = usbd_get_interface_descriptor(uaa->iface); - if (id - && id->bInterfaceClass == UICLASS_HID - && id->bInterfaceSubClass == UISUBCLASS_BOOT - && id->bInterfaceProtocol == UPROTO_BOOT_KEYBOARD) - return 0; /* found it */ - - return EINVAL; -} - -static int -init_keyboard(ukbd_state_t *state, int *type, int flags) -{ - usb_endpoint_descriptor_t *ed; - - *type = KB_OTHER; - - state->ks_ifstate |= DISCONNECTED; - - ed = usbd_interface2endpoint_descriptor(state->ks_iface, 0); - if (!ed) { - printf("ukbd: could not read endpoint descriptor\n"); - return EIO; - } - - DPRINTFN(10,("ukbd:init_keyboard: \ -bLength=%d bDescriptorType=%d bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d bInterval=%d\n", - ed->bLength, ed->bDescriptorType, - UE_GET_ADDR(ed->bEndpointAddress), - UE_GET_DIR(ed->bEndpointAddress) == UE_DIR_IN ? "in":"out", - UE_GET_XFERTYPE(ed->bmAttributes), - UGETW(ed->wMaxPacketSize), ed->bInterval)); - - if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || - UE_GET_XFERTYPE(ed->bmAttributes) != UE_INTERRUPT) { - printf("ukbd: unexpected endpoint\n"); - return EINVAL; - } - - /* Ignore if SETIDLE fails since it is not crucial. */ - usbd_set_idle(state->ks_iface, 0, 0); - - state->ks_ep_addr = ed->bEndpointAddress; - state->ks_ifstate &= ~DISCONNECTED; - - return 0; -} - -static void -set_leds(ukbd_state_t *state, int leds) -{ - - DPRINTF(("ukbd:set_leds: state=%p leds=%d\n", state, leds)); - state->ks_leds = leds; - usbd_set_report_async(state->ks_iface, UHID_OUTPUT_REPORT, 0, - &state->ks_leds, 1); -} - -static int -set_typematic(keyboard_t *kbd, int code) -{ - 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 }; - - if (code & ~0x7f) - return EINVAL; - kbd->kb_delay1 = delays[(code >> 5) & 3]; - kbd->kb_delay2 = rates[code & 0x1f]; - return 0; -} - -#ifdef UKBD_EMULATE_ATSCANCODE -static int -keycode2scancode(int keycode, int shift, int up) -{ - static int scan[] = { - 0x1c, 0x1d, 0x35, - 0x37 | SCAN_PREFIX_SHIFT, /* PrintScreen */ - 0x38, 0x47, 0x48, 0x49, 0x4b, 0x4d, 0x4f, - 0x50, 0x51, 0x52, 0x53, - 0x46, /* XXX Pause/Break */ - 0x5b, 0x5c, 0x5d, - /* SUN TYPE 6 USB KEYBOARD */ - 0x68, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, - 0x64, 0x65, 0x66, 0x67, 0x25, 0x1f, 0x1e, - 0x20, - }; - int scancode; - - scancode = keycode; - if ((keycode >= 89) && (keycode < 89 + sizeof(scan)/sizeof(scan[0]))) - scancode = scan[keycode - 89] | SCAN_PREFIX_E0; - /* Pause/Break */ - if ((keycode == 104) && !(shift & (MOD_CONTROL_L | MOD_CONTROL_R))) - scancode = 0x45 | SCAN_PREFIX_E1 | SCAN_PREFIX_CTL; - if (shift & (MOD_SHIFT_L | MOD_SHIFT_R)) - scancode &= ~SCAN_PREFIX_SHIFT; - return (scancode | (up ? SCAN_RELEASE : SCAN_PRESS)); -} -#endif /* UKBD_EMULATE_ATSCANCODE */ - -static int -ukbd_driver_load(module_t mod, int what, void *arg) -{ - switch (what) { - case MOD_LOAD: - kbd_add_driver(&ukbd_kbd_driver); - break; - case MOD_UNLOAD: - kbd_delete_driver(&ukbd_kbd_driver); - break; - } - return usbd_driver_load(mod, what, arg); -} |