From 719914f7d11cca5a6e29b46198ed50c4f1e1fa27 Mon Sep 17 00:00:00 2001 From: Miod Vallat Date: Sat, 31 Jul 2010 16:04:51 +0000 Subject: Factorization of the bluetooth and usb hid input driver logic, to reduce code duplication and divergence. Thanks to mlarkin@ for bluetooth devices tests. --- sys/dev/bluetooth/btkbd.c | 428 ++----------------------- sys/dev/bluetooth/btms.c | 190 ++--------- sys/dev/bluetooth/files.bluetooth | 6 +- sys/dev/isa/pcppi.c | 16 +- sys/dev/usb/files.usb | 12 +- sys/dev/usb/hidkbd.c | 638 ++++++++++++++++++++++++++++++++++++ sys/dev/usb/hidkbdsc.h | 104 ++++++ sys/dev/usb/hidkbdvar.h | 34 ++ sys/dev/usb/hidms.c | 348 ++++++++++++++++++++ sys/dev/usb/hidmsvar.h | 67 ++++ sys/dev/usb/ukbd.c | 657 ++++---------------------------------- sys/dev/usb/ukbdvar.h | 5 +- sys/dev/usb/ums.c | 341 +++----------------- 13 files changed, 1363 insertions(+), 1483 deletions(-) create mode 100644 sys/dev/usb/hidkbd.c create mode 100644 sys/dev/usb/hidkbdsc.h create mode 100644 sys/dev/usb/hidkbdvar.h create mode 100644 sys/dev/usb/hidms.c create mode 100644 sys/dev/usb/hidmsvar.h (limited to 'sys/dev') diff --git a/sys/dev/bluetooth/btkbd.c b/sys/dev/bluetooth/btkbd.c index 863f6c551ad..ff34824c200 100644 --- a/sys/dev/bluetooth/btkbd.c +++ b/sys/dev/bluetooth/btkbd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: btkbd.c,v 1.5 2009/01/21 21:53:59 grange Exp $ */ +/* $OpenBSD: btkbd.c,v 1.6 2010/07/31 16:04:50 miod Exp $ */ /* $NetBSD: btkbd.c,v 1.10 2008/09/09 03:54:56 cube Exp $ */ /* @@ -62,10 +62,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -/* - * based on dev/usb/ukbd.c - */ - #include #include #include @@ -87,54 +83,14 @@ #include #include -#define MAXKEYCODE 6 -#define MAXMOD 8 /* max 32 */ -#define MAXKEYS (MAXMOD + (2 * MAXKEYCODE)) - -struct btkbd_data { - uint32_t modifiers; - uint8_t keycode[MAXKEYCODE]; -}; - -struct btkbd_mod { - uint32_t mask; - uint8_t key; -}; +#include +#include struct btkbd_softc { - struct bthidev sc_hidev; /* device+ */ - struct device *sc_wskbd; /* child */ - int sc_enabled; - + struct bthidev sc_hidev; /* device */ + struct hidkbd sc_kbd; /* keyboard state */ int (*sc_output) /* output method */ (struct bthidev *, uint8_t *, int); - - /* stored data */ - struct btkbd_data sc_odata; - struct btkbd_data sc_ndata; - - /* input reports */ - int sc_nmod; - struct hid_location sc_modloc[MAXMOD]; - struct btkbd_mod sc_mods[MAXMOD]; - - int sc_nkeycode; - struct hid_location sc_keycodeloc; - - /* output reports */ - struct hid_location sc_numloc; - struct hid_location sc_capsloc; - struct hid_location sc_scroloc; - int sc_leds; - -#ifdef WSDISPLAY_COMPAT_RAWKBD - int sc_rawkbd; -#ifdef BTKBD_REPEAT - struct timeout sc_repeat; - int sc_nrep; - char sc_rep[MAXKEYS]; -#endif -#endif }; /* autoconf(9) methods */ @@ -151,6 +107,7 @@ const struct cfattach btkbd_ca = { btkbd_match, btkbd_attach, btkbd_detach, + /* XXX activate */ }; /* wskbd(4) accessops */ @@ -164,32 +121,8 @@ const struct wskbd_accessops btkbd_accessops = { btkbd_ioctl }; -/* wskbd(4) keymap data */ -extern const struct wscons_keydesc ukbd_keydesctab[]; - -const struct wskbd_mapdata btkbd_keymapdata = { - ukbd_keydesctab, -#if defined(BTKBD_LAYOUT) - BTKBD_LAYOUT, -#elif defined(PCKBD_LAYOUT) - PCKBD_LAYOUT, -#else - KB_US, -#endif -}; - /* bthid methods */ -void btkbd_input(struct bthidev *, uint8_t *, int); - -/* internal prototypes */ -const char *btkbd_parse_desc(struct btkbd_softc *, int, void *, int); - -#ifdef WSDISPLAY_COMPAT_RAWKBD -#ifdef BTKBD_REPEAT -void btkbd_repeat(void *); -#endif -#endif - +void btkbd_input(struct bthidev *, uint8_t *, int); int btkbd_match(struct device *self, void *match, void *aux) @@ -207,379 +140,82 @@ void btkbd_attach(struct device *parent, struct device *self, void *aux) { struct btkbd_softc *sc = (struct btkbd_softc *)self; + struct hidkbd *kbd = &sc->sc_kbd; struct bthidev_attach_args *ba = aux; - struct wskbddev_attach_args wska; - const char *parserr; + kbd_t layout; sc->sc_output = ba->ba_output; - ba->ba_input = btkbd_input; + ba->ba_input = btkbd_input; /* XXX ugly */ - parserr = btkbd_parse_desc(sc, ba->ba_id, ba->ba_desc, ba->ba_dlen); - if (parserr != NULL) { - printf("%s\n", parserr); + if (hidkbd_attach(self, kbd, 0, 0, + ba->ba_id, ba->ba_desc, ba->ba_dlen) != 0) return; - } printf("\n"); -#ifdef WSDISPLAY_COMPAT_RAWKBD -#ifdef BTKBD_REPEAT - timeout_set(&sc->sc_repeat, btkbd_repeat, sc); -#endif +#if defined(BTKBD_LAYOUT) + layout = BTKBD_LAYOUT; +#else + layout = KB_US; #endif - - wska.console = 0; - wska.keymap = &btkbd_keymapdata; - wska.accessops = &btkbd_accessops; - wska.accesscookie = sc; - - sc->sc_wskbd = config_found((struct device *)sc, &wska, wskbddevprint); + hidkbd_attach_wskbd(kbd, layout, &btkbd_accessops); } int btkbd_detach(struct device *self, int flags) { struct btkbd_softc *sc = (struct btkbd_softc *)self; - int err = 0; -#ifdef WSDISPLAY_COMPAT_RAWKBD -#ifdef BTKBD_REPEAT - timeout_del(&sc->sc_repeat); -#endif -#endif - - if (sc->sc_wskbd != NULL) { - err = config_detach(sc->sc_wskbd, flags); - sc->sc_wskbd = NULL; - } - - return err; -} - -const char * -btkbd_parse_desc(struct btkbd_softc *sc, int id, void *desc, int dlen) -{ - struct hid_data *d; - struct hid_item h; - int imod; - - imod = 0; - sc->sc_nkeycode = 0; - d = hid_start_parse(desc, dlen, hid_input); - while (hid_get_item(d, &h)) { - if (h.kind != hid_input || (h.flags & HIO_CONST) || - HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD || - h.report_ID != id) - continue; - - if (h.flags & HIO_VARIABLE) { - if (h.loc.size != 1) - return ("bad modifier size"); - - /* Single item */ - if (imod < MAXMOD) { - sc->sc_modloc[imod] = h.loc; - sc->sc_mods[imod].mask = 1 << imod; - sc->sc_mods[imod].key = HID_GET_USAGE(h.usage); - imod++; - } else - return ("too many modifier keys"); - } else { - /* Array */ - if (h.loc.size != 8) - return ("key code size != 8"); - - if (h.loc.count > MAXKEYCODE) - return ("too many key codes"); - - if (h.loc.pos % 8 != 0) - return ("key codes not on byte boundary"); - - if (sc->sc_nkeycode != 0) - return ("multiple key code arrays\n"); - - sc->sc_keycodeloc = h.loc; - sc->sc_nkeycode = h.loc.count; - } - } - sc->sc_nmod = imod; - hid_end_parse(d); - - hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK), - id, hid_output, &sc->sc_numloc, NULL); - - hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK), - id, hid_output, &sc->sc_capsloc, NULL); - - hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK), - id, hid_output, &sc->sc_scroloc, NULL); - - return (NULL); + return hidkbd_detach(&sc->sc_kbd, flags); } int btkbd_enable(void *self, int on) { struct btkbd_softc *sc = (struct btkbd_softc *)self; + struct hidkbd *kbd = &sc->sc_kbd; - sc->sc_enabled = on; - return 0; + return hidkbd_enable(kbd, on); } void btkbd_set_leds(void *self, int leds) { struct btkbd_softc *sc = (struct btkbd_softc *)self; + struct hidkbd *kbd = &sc->sc_kbd; uint8_t report; - if (sc->sc_leds == leds) - return; - - sc->sc_leds = leds; - - /* - * This is not totally correct, since we did not check the - * report size from the descriptor but for keyboards it should - * just be a single byte with the relevant bits set. - */ - report = 0; - if ((leds & WSKBD_LED_SCROLL) && sc->sc_scroloc.size == 1) - report |= 1 << sc->sc_scroloc.pos; - - if ((leds & WSKBD_LED_NUM) && sc->sc_numloc.size == 1) - report |= 1 << sc->sc_numloc.pos; - - if ((leds & WSKBD_LED_CAPS) && sc->sc_capsloc.size == 1) - report |= 1 << sc->sc_capsloc.pos; - - if (sc->sc_output) - (*sc->sc_output)(&sc->sc_hidev, &report, sizeof(report)); + if (hidkbd_set_leds(kbd, leds, &report) != 0) { + if (sc->sc_output != NULL) + (*sc->sc_output)(&sc->sc_hidev, &report, + sizeof(report)); + } } int btkbd_ioctl(void *self, u_long cmd, caddr_t data, int flag, struct proc *p) { struct btkbd_softc *sc = (struct btkbd_softc *)self; + struct hidkbd *kbd = &sc->sc_kbd; switch (cmd) { case WSKBDIO_GTYPE: *(int *)data = WSKBD_TYPE_BLUETOOTH; return 0; - case WSKBDIO_SETLEDS: btkbd_set_leds(sc, *(int *)data); return 0; - - case WSKBDIO_GETLEDS: - *(int *)data = sc->sc_leds; - return 0; - -#ifdef WSDISPLAY_COMPAT_RAWKBD - case WSKBDIO_SETMODE: - sc->sc_rawkbd = (*(int *)data == WSKBD_RAW); -#ifdef BTKBD_REPEAT - timeout_del(&sc->sc_repeat); -#endif - return 0; -#endif + default: + return hidkbd_ioctl(kbd, cmd, data, flag, p); } - return -1; } -#ifdef WSDISPLAY_COMPAT_RAWKBD -#define NN 0 /* no translation */ -/* - * Translate USB keycodes to US keyboard XT scancodes. - * Scancodes >= 0x80 represent EXTENDED keycodes. - * - * See http://www.microsoft.com/HWDEV/TECH/input/Scancode.asp - */ -const u_int8_t btkbd_trtab[256] = { - NN, NN, NN, NN, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */ - 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */ - 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */ - 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */ - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */ - 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */ - 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */ - 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */ - 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xaa, 0x46, /* 40 - 47 */ - 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */ - 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */ - 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */ - 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, NN, 0x59, /* 60 - 67 */ - 0x5d, 0x5e, 0x5f, NN, NN, NN, NN, NN, /* 68 - 6f */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 70 - 77 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 78 - 7f */ - NN, NN, NN, NN, NN, 0x7e, NN, 0x73, /* 80 - 87 */ - 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN, NN, NN, /* 88 - 8f */ - NN, NN, 0x78, 0x77, 0x76, 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 */ - 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* 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 */ -}; -#endif - -#define KEY_ERROR 0x01 -#define PRESS 0x000 -#define RELEASE 0x100 -#define CODEMASK 0x0ff -#define ADDKEY(c) ibuf[nkeys++] = (c) -#define REP_DELAY1 400 -#define REP_DELAYN 100 - void btkbd_input(struct bthidev *self, uint8_t *data, int len) { struct btkbd_softc *sc = (struct btkbd_softc *)self; - struct btkbd_data *ud = &sc->sc_ndata; - uint16_t ibuf[MAXKEYS]; - uint32_t mod, omod; - int nkeys, i, j; - int key; - int s; - - if (sc->sc_wskbd == NULL || sc->sc_enabled == 0) - return; - - /* extract key modifiers */ - ud->modifiers = 0; - for (i = 0 ; i < sc->sc_nmod ; i++) - if (hid_get_data(data, &sc->sc_modloc[i])) - ud->modifiers |= sc->sc_mods[i].mask; - - /* extract keycodes */ - memcpy(ud->keycode, data + (sc->sc_keycodeloc.pos / 8), - sc->sc_nkeycode); - - if (ud->keycode[0] == KEY_ERROR) - return; /* ignore */ - - nkeys = 0; - mod = ud->modifiers; - omod = sc->sc_odata.modifiers; - if (mod != omod) - for (i = 0 ; i < sc->sc_nmod ; i++) - if ((mod & sc->sc_mods[i].mask) != - (omod & sc->sc_mods[i].mask)) - ADDKEY(sc->sc_mods[i].key | - (mod & sc->sc_mods[i].mask - ? PRESS : RELEASE)); - - if (memcmp(ud->keycode, sc->sc_odata.keycode, sc->sc_nkeycode) != 0) { - /* Check for released keys. */ - for (i = 0 ; i < sc->sc_nkeycode ; i++) { - key = sc->sc_odata.keycode[i]; - if (key == 0) - continue; - - for (j = 0 ; j < sc->sc_nkeycode ; j++) - if (key == ud->keycode[j]) - goto rfound; - - ADDKEY(key | RELEASE); - - rfound: - ; - } - - /* Check for pressed keys. */ - for (i = 0 ; i < sc->sc_nkeycode ; i++) { - key = ud->keycode[i]; - if (key == 0) - continue; - - for (j = 0; j < sc->sc_nkeycode; j++) - if (key == sc->sc_odata.keycode[j]) - goto pfound; - - ADDKEY(key | PRESS); - pfound: - ; - } - } - sc->sc_odata = *ud; - - if (nkeys == 0) - return; - -#ifdef WSDISPLAY_COMPAT_RAWKBD - if (sc->sc_rawkbd) { - u_char cbuf[MAXKEYS * 2]; - int c; - int npress; - - for (npress = i = j = 0 ; i < nkeys ; i++) { - key = ibuf[i]; - c = btkbd_trtab[key & CODEMASK]; - if (c == NN) - continue; - - if (c & 0x80) - cbuf[j++] = 0xe0; - - cbuf[j] = c & 0x7f; - if (key & RELEASE) - cbuf[j] |= 0x80; -#ifdef BTKBD_REPEAT - else { - /* remember pressed keys for autorepeat */ - if (c & 0x80) - sc->sc_rep[npress++] = 0xe0; - - sc->sc_rep[npress++] = c & 0x7f; - } -#endif - - j++; - } - - s = spltty(); - wskbd_rawinput(sc->sc_wskbd, cbuf, j); - splx(s); -#ifdef BTKBD_REPEAT - timeout_del(&sc->sc_repeat); - if (npress != 0) { - sc->sc_nrep = npress; - timeout_add_msec(&sc->sc_repeat, REP_DELAY1); - } -#endif - return; - } -#endif - - s = spltty(); - for (i = 0 ; i < nkeys ; i++) { - key = ibuf[i]; - wskbd_input(sc->sc_wskbd, - key & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN, - key & CODEMASK); - } - splx(s); -} + struct hidkbd *kbd = &sc->sc_kbd; -#ifdef WSDISPLAY_COMPAT_RAWKBD -#ifdef BTKBD_REPEAT -void -btkbd_repeat(void *arg) -{ - struct btkbd_softc *sc = arg; - int s; - - s = spltty(); - wskbd_rawinput(sc->sc_wskbd, sc->sc_rep, sc->sc_nrep); - splx(s); - timeout_add_msec(&sc->sc_repeat, REP_DELAYN); + if (kbd->sc_enabled != 0) + hidkbd_input(kbd, data, len); } -#endif -#endif diff --git a/sys/dev/bluetooth/btms.c b/sys/dev/bluetooth/btms.c index 7ef3d457809..8ae2d02cc6a 100644 --- a/sys/dev/bluetooth/btms.c +++ b/sys/dev/bluetooth/btms.c @@ -1,4 +1,4 @@ -/* $OpenBSD: btms.c,v 1.4 2008/11/22 04:42:58 uwe Exp $ */ +/* $OpenBSD: btms.c,v 1.5 2010/07/31 16:04:50 miod Exp $ */ /* $NetBSD: btms.c,v 1.8 2008/09/09 03:54:56 cube Exp $ */ /* @@ -62,10 +62,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -/* - * based on dev/usb/ums.c - */ - #include #include #include @@ -84,33 +80,13 @@ #include #include -#define MAX_BUTTONS 31 -#define BUTTON(n) (1 << (((n) == 1 || (n) == 2) ? 3 - (n) : (n))) -#define NOTMOUSE(f) (((f) & (HIO_CONST | HIO_RELATIVE)) != HIO_RELATIVE) +#include struct btms_softc { - struct bthidev sc_hidev; /* device+ */ - - struct device *sc_wsmouse; /* child */ - int sc_enabled; - uint16_t sc_flags; - - /* locators */ - struct hid_location sc_loc_x; - struct hid_location sc_loc_y; - struct hid_location sc_loc_z; - struct hid_location sc_loc_w; - struct hid_location sc_loc_button[MAX_BUTTONS]; - - int sc_num_buttons; - uint32_t sc_buttons; + struct bthidev sc_hidev; + struct hidms sc_ms; }; -/* sc_flags */ -#define BTMS_REVZ (1 << 0) /* reverse Z direction */ -#define BTMS_HASZ (1 << 1) /* has Z direction */ -#define BTMS_HASW (1 << 2) /* has W direction */ - /* autoconf(9) methods */ int btms_match(struct device *, void *, void *); void btms_attach(struct device *, struct device *, void *); @@ -125,6 +101,7 @@ const struct cfattach btms_ca = { btms_match, btms_attach, btms_detach, + /* XXX activate */ }; /* wsmouse(4) accessops */ @@ -158,189 +135,66 @@ void btms_attach(struct device *parent, struct device *self, void *aux) { struct btms_softc *sc = (struct btms_softc *)self; + struct hidms *ms = &sc->sc_ms; struct bthidev_attach_args *ba = aux; - struct wsmousedev_attach_args wsma; - struct hid_location *zloc; - uint32_t flags; - int i, hl; - - ba->ba_input = btms_input; - - /* control the horizontal */ - hl = hid_locate(ba->ba_desc, ba->ba_dlen, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), ba->ba_id, hid_input, - &sc->sc_loc_x, &flags); - - if (hl == 0 || NOTMOUSE(flags)) { - printf("\n%s: X report 0x%04x not supported\n", - sc->sc_hidev.sc_dev.dv_xname, flags); - return; - } - - /* control the vertical */ - hl = hid_locate(ba->ba_desc, ba->ba_dlen, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), ba->ba_id, hid_input, - &sc->sc_loc_y, &flags); - - if (hl == 0 || NOTMOUSE(flags)) { - printf("\n%s: Y report 0x%04x not supported\n", - sc->sc_hidev.sc_dev.dv_xname, flags); + ba->ba_input = btms_input; /* XXX ugly */ + if (hidms_setup(self, ms, 0, ba->ba_id, ba->ba_desc, ba->ba_dlen) != 0) return; - } - /* Try the wheel first as the Z activator since it's tradition. */ - hl = hid_locate(ba->ba_desc, ba->ba_dlen, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), ba->ba_id, hid_input, - &sc->sc_loc_z, &flags); - - zloc = &sc->sc_loc_z; - if (hl) { - if (NOTMOUSE(flags)) { - printf("\n%s: Wheel report 0x%04x ignored\n", - sc->sc_hidev.sc_dev.dv_xname, flags); - - /* ignore Bad Z coord */ - sc->sc_loc_z.size = 0; - } else { - sc->sc_flags |= BTMS_HASZ; - /* Wheels need the Z axis reversed. */ - sc->sc_flags ^= BTMS_REVZ; - /* Put Z on the W coordinate */ - zloc = &sc->sc_loc_w; - } - } - - hl = hid_locate(ba->ba_desc, ba->ba_dlen, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), ba->ba_id, hid_input, - zloc, &flags); - - /* - * The horizontal component of the scrollball can also be given by - * Application Control Pan in the Consumer page, so if we didnt see - * any Z then check that. - */ - if (!hl) { - hl = hid_locate(ba->ba_desc, ba->ba_dlen, - HID_USAGE2(HUP_CONSUMER, HUC_AC_PAN), ba->ba_id, hid_input, - zloc, &flags); - } - - if (hl) { - if (NOTMOUSE(flags)) - zloc->size = 0; /* ignore Z */ - else { - if (sc->sc_flags & BTMS_HASZ) - sc->sc_flags |= BTMS_HASW; - else - sc->sc_flags |= BTMS_HASZ; - } - } - - for (i = 1 ; i <= MAX_BUTTONS ; i++) { - hl = hid_locate(ba->ba_desc, ba->ba_dlen, - HID_USAGE2(HUP_BUTTON, i), ba->ba_id, hid_input, - &sc->sc_loc_button[i - 1], NULL); - - if (hl == 0) - break; - } - sc->sc_num_buttons = i - 1; - - printf(": %d button%s%s%s%s.\n", sc->sc_num_buttons, - sc->sc_num_buttons == 1 ? "" : "s", - sc->sc_flags & BTMS_HASW ? ", W" : "", - sc->sc_flags & BTMS_HASZ ? " and Z dir" : "", - sc->sc_flags & BTMS_HASW ? "s" : ""); - - wsma.accessops = &btms_wsmouse_accessops; - wsma.accesscookie = sc; - - sc->sc_wsmouse = config_found((struct device *)sc, - &wsma, wsmousedevprint); + hidms_attach(ms, &btms_wsmouse_accessops); } int btms_detach(struct device *self, int flags) { struct btms_softc *sc = (struct btms_softc *)self; - int err = 0; - - if (sc->sc_wsmouse != NULL) { - err = config_detach(sc->sc_wsmouse, flags); - sc->sc_wsmouse = NULL; - } + struct hidms *ms = &sc->sc_ms; - return err; + return hidms_detach(ms, flags); } int btms_wsmouse_enable(void *self) { struct btms_softc *sc = (struct btms_softc *)self; + struct hidms *ms = &sc->sc_ms; - if (sc->sc_enabled) - return EBUSY; - - sc->sc_enabled = 1; - return 0; + return hidms_enable(ms); } int btms_wsmouse_ioctl(void *self, u_long cmd, caddr_t data, int flag, struct proc *p) { - /* struct btms_softc *sc = (struct btms_softc *)self; */ + struct btms_softc *sc = (struct btms_softc *)self; + struct hidms *ms = &sc->sc_ms; switch (cmd) { case WSMOUSEIO_GTYPE: *(u_int *)data = WSMOUSE_TYPE_BLUETOOTH; return 0; + default: + return hidms_ioctl(ms, cmd, data, flag, p); } - - return -1; } void btms_wsmouse_disable(void *self) { struct btms_softc *sc = (struct btms_softc *)self; + struct hidms *ms = &sc->sc_ms; - sc->sc_enabled = 0; + hidms_disable(ms); } void btms_input(struct bthidev *self, uint8_t *data, int len) { struct btms_softc *sc = (struct btms_softc *)self; - int dx, dy, dz, dw; - uint32_t buttons; - int i, s; - - if (sc->sc_wsmouse == NULL || sc->sc_enabled == 0) - return; - - dx = hid_get_data(data, &sc->sc_loc_x); - dy = -hid_get_data(data, &sc->sc_loc_y); - dz = hid_get_data(data, &sc->sc_loc_z); - dw = hid_get_data(data, &sc->sc_loc_w); + struct hidms *ms = &sc->sc_ms; - if (sc->sc_flags & BTMS_REVZ) - dz = -dz; - - buttons = 0; - for (i = 0 ; i < sc->sc_num_buttons ; i++) - if (hid_get_data(data, &sc->sc_loc_button[i])) - buttons |= BUTTON(i); - - if (dx != 0 || dy != 0 || dz != 0 || dw != 0 || - buttons != sc->sc_buttons) { - sc->sc_buttons = buttons; - - s = spltty(); - wsmouse_input(sc->sc_wsmouse, buttons, dx, dy, dz, dw, - WSMOUSE_INPUT_DELTA); - splx(s); - } + if (ms->sc_enabled != 0) + hidms_input(ms, data, len); } diff --git a/sys/dev/bluetooth/files.bluetooth b/sys/dev/bluetooth/files.bluetooth index e204487c77b..7f3678bf4a1 100644 --- a/sys/dev/bluetooth/files.bluetooth +++ b/sys/dev/bluetooth/files.bluetooth @@ -1,4 +1,4 @@ -# $OpenBSD: files.bluetooth,v 1.6 2008/11/24 22:31:19 uwe Exp $ +# $OpenBSD: files.bluetooth,v 1.7 2010/07/31 16:04:50 miod Exp $ # # Config file and device description for machine-independent Bluetooth code. # Included by ports that support Bluetooth host controllers. @@ -17,12 +17,12 @@ attach bthidev at bthub file dev/bluetooth/bthidev.c bthidev # HID Mice -device btms: hid, wsmousedev +device btms: hid, hidms, wsmousedev attach btms at bthidbus file dev/bluetooth/btms.c btms # HID Keyboard -device btkbd: hid, wskbddev +device btkbd: hid, hidkbd, wskbddev attach btkbd at bthidbus file dev/bluetooth/btkbd.c btkbd diff --git a/sys/dev/isa/pcppi.c b/sys/dev/isa/pcppi.c index 57349b16018..74582d37c4f 100644 --- a/sys/dev/isa/pcppi.c +++ b/sys/dev/isa/pcppi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pcppi.c,v 1.8 2009/10/13 20:55:41 miod Exp $ */ +/* $OpenBSD: pcppi.c,v 1.9 2010/07/31 16:04:50 miod Exp $ */ /* $NetBSD: pcppi.c,v 1.1 1998/04/15 20:26:18 drochner Exp $ */ /* @@ -45,11 +45,11 @@ #include #include "pckbd.h" -#include "ukbd.h" -#if NPCKBD > 0 || NUKBD > 0 +#include "hidkbd.h" +#if NPCKBD > 0 || NHIDKBD > 0 #include #include -#include +#include void pcppi_kbd_bell(void *, u_int, u_int, u_int, int); #endif @@ -174,8 +174,8 @@ pcppi_attach(parent, self, aux) #if NPCKBD > 0 pckbd_hookup_bell(pcppi_kbd_bell, sc); #endif -#if NUKBD > 0 - ukbd_hookup_bell(pcppi_kbd_bell, sc); +#if NHIDKBD > 0 + hidkbd_hookup_bell(pcppi_kbd_bell, sc); #endif pa.pa_cookie = sc; @@ -259,7 +259,7 @@ pcppi_bell_stop(arg) splx(s); } -#if NPCKBD > 0 || NUKBD > 0 +#if NPCKBD > 0 || NHIDKBD > 0 void pcppi_kbd_bell(arg, pitch, period, volume, poll) void *arg; @@ -272,4 +272,4 @@ pcppi_kbd_bell(arg, pitch, period, volume, poll) pcppi_bell(arg, volume ? pitch : 0, (period * hz) / 1000, poll ? PCPPI_BELL_POLL : 0); } -#endif /* NPCKBD > 0 || NUKBD > 0 */ +#endif /* NPCKBD > 0 || NHIDKBD > 0 */ diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb index 741ed827d35..a7e092a3eff 100644 --- a/sys/dev/usb/files.usb +++ b/sys/dev/usb/files.usb @@ -1,4 +1,4 @@ -# $OpenBSD: files.usb,v 1.91 2010/07/03 03:59:17 krw Exp $ +# $OpenBSD: files.usb,v 1.92 2010/07/31 16:04:50 miod Exp $ # $NetBSD: files.usb,v 1.16 2000/02/14 20:29:54 augustss Exp $ # # Config file and device description for machine-independent USB code. @@ -80,13 +80,17 @@ attach uhid at uhidbus file dev/usb/uhid.c uhid needs-flag # Keyboards -device ukbd: hid, wskbddev +define hidkbd +file dev/usb/hidkbd.c hidkbd needs-flag +file dev/usb/ukbdmap.c hidkbd +device ukbd: hid, hidkbd, wskbddev attach ukbd at uhidbus file dev/usb/ukbd.c ukbd needs-flag -file dev/usb/ukbdmap.c ukbd | btkbd # Mice -device ums: hid, wsmousedev +define hidms +file dev/usb/hidms.c hidms +device ums: hid, hidms, wsmousedev attach ums at uhidbus file dev/usb/ums.c ums diff --git a/sys/dev/usb/hidkbd.c b/sys/dev/usb/hidkbd.c new file mode 100644 index 00000000000..687790dbd0a --- /dev/null +++ b/sys/dev/usb/hidkbd.c @@ -0,0 +1,638 @@ +/* $OpenBSD: hidkbd.c,v 1.1 2010/07/31 16:04:50 miod Exp $ */ +/* $NetBSD: ukbd.c,v 1.85 2003/03/11 16:44:00 augustss Exp $ */ + +/* + * 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. + * + * 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. + */ + +/* + * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include + +#ifdef HIDKBD_DEBUG +#define DPRINTF(x) do { if (hidkbddebug) printf x; } while (0) +#define DPRINTFN(n,x) do { if (hidkbddebug>(n)) printf x; } while (0) +int hidkbddebug = 0; +#else +#define DPRINTF(x) +#define DPRINTFN(n,x) +#endif + +#define PRESS 0x000 +#define RELEASE 0x100 +#define CODEMASK 0x0ff + +#if defined(WSDISPLAY_COMPAT_RAWKBD) +#define NN 0 /* no translation */ +/* + * Translate USB keycodes to US keyboard XT scancodes. + * Scancodes >= 0x80 represent EXTENDED keycodes. + * + * See http://www.microsoft.com/whdc/device/input/Scancode.mspx + */ +const u_int8_t hidkbd_trtab[256] = { + NN, NN, NN, NN, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */ + 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */ + 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */ + 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */ + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */ + 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */ + 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */ + 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */ + 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xaa, 0x46, /* 40 - 47 */ + 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */ + 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */ + 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */ + 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, 0x84, 0x59, /* 60 - 67 */ + 0x5d, 0x5e, 0x5f, NN, NN, NN, NN, NN, /* 68 - 6f */ + NN, NN, NN, NN, 0x97, NN, 0x93, 0x95, /* 70 - 77 */ + 0x91, 0x92, 0x94, 0x9a, 0x96, 0x98, 0x99, 0xa0, /* 78 - 7f */ + 0xb0, 0xae, NN, NN, NN, 0x7e, NN, 0x73, /* 80 - 87 */ + 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN, NN, NN, /* 88 - 8f */ + NN, NN, 0x78, 0x77, 0x76, 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 */ + 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* 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 */ +}; +#endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */ + +#define KEY_ERROR 0x01 + +#ifdef HIDKBD_DEBUG +#define HIDKBDTRACESIZE 64 +struct hidkbdtraceinfo { + int unit; + struct timeval tv; + struct hidkbd_data ud; +}; +struct hidkbdtraceinfo hidkbdtracedata[HIDKBDTRACESIZE]; +int hidkbdtraceindex = 0; +int hidkbdtrace = 0; +void hidkbdtracedump(void); +void +hidkbdtracedump(void) +{ + int i; + for (i = 0; i < HIDKBDTRACESIZE; i++) { + struct hidkbdtraceinfo *p = + &hidkbdtracedata[(i+hidkbdtraceindex)%HIDKBDTRACESIZE]; + printf("%lu.%06lu: mod=0x%02x key0=0x%02x key1=0x%02x " + "key2=0x%02x key3=0x%02x\n", + p->tv.tv_sec, p->tv.tv_usec, + p->ud.modifiers, p->ud.keycode[0], p->ud.keycode[1], + p->ud.keycode[2], p->ud.keycode[3]); + } +} +#endif + +int hidkbd_is_console; + +const char *hidkbd_parse_desc(struct hidkbd *, int, void *, int); + +void (*hidkbd_bell_fn)(void *, u_int, u_int, u_int, int); +void *hidkbd_bell_fn_arg; + +void hidkbd_decode(struct hidkbd *, struct hidkbd_data *); +void hidkbd_delayed_decode(void *addr); + +#ifdef WSDISPLAY_COMPAT_RAWKBD +void hidkbd_rawrepeat(void *); +#endif + +extern const struct wscons_keydesc ukbd_keydesctab[]; + +struct wskbd_mapdata ukbd_keymapdata = { + ukbd_keydesctab +}; + +int +hidkbd_attach(struct device *self, struct hidkbd *kbd, int console, + uint32_t qflags, int id, void *desc, int dlen) +{ + const char *parserr; + + parserr = hidkbd_parse_desc(kbd, id, desc, dlen); + if (parserr != NULL) { + printf(": %s\n", parserr); + return ENXIO; + } + +#ifdef DIAGNOSTIC + printf(": %d modifier keys, %d key codes", + kbd->sc_nmod, kbd->sc_nkeycode); +#endif + + kbd->sc_device = self; + kbd->sc_debounce = (qflags & UQ_SPUR_BUT_UP) != 0; + /* + * Remember if we're the console keyboard. + * + * XXX This always picks the first (USB) keyboard to attach, + * but what else can we really do? + */ + if (console) { + kbd->sc_console_keyboard = hidkbd_is_console; + /* Don't let any other keyboard have it. */ + hidkbd_is_console = 0; + } + +#ifdef WSDISPLAY_COMPAT_RAWKBD + timeout_set(&kbd->sc_rawrepeat_ch, hidkbd_rawrepeat, kbd); +#endif + timeout_set(&kbd->sc_delay, hidkbd_delayed_decode, kbd); + + return 0; +} + +void +hidkbd_attach_wskbd(struct hidkbd *kbd, kbd_t layout, + const struct wskbd_accessops *accessops) +{ + struct wskbddev_attach_args a; + + ukbd_keymapdata.layout = layout; + + a.console = kbd->sc_console_keyboard; + a.keymap = &ukbd_keymapdata; + a.accessops = accessops; + a.accesscookie = kbd->sc_device; + kbd->sc_wskbddev = config_found(kbd->sc_device, &a, wskbddevprint); +} + +int +hidkbd_detach(struct hidkbd *kbd, int flags) +{ + int rv = 0; + + DPRINTF(("hidkbd_detach: sc=%p flags=%d\n", sc, flags)); + +#ifdef WSDISPLAY_COMPAT_RAWKBD + timeout_del(&kbd->sc_rawrepeat_ch); +#endif + + if (kbd->sc_console_keyboard) { +#if 0 + /* + * XXX Should probably disconnect our consops, + * XXX and either notify some other keyboard that + * XXX it can now be the console, or if there aren't + * XXX any more USB keyboards, set hidkbd_is_console + * XXX back to 1 so that the next USB keyboard attached + * XXX to the system will get it. + */ + panic("hidkbd_detach: console keyboard"); +#else + /* + * Disconnect our consops and set hidkbd_is_console + * back to 1 so that the next USB keyboard attached + * to the system will get it. + * XXX Should notify some other keyboard that it can be + * XXX console, if there are any other keyboards. + */ + printf("%s: was console keyboard\n", + kbd->sc_device->dv_xname); + wskbd_cndetach(); + hidkbd_is_console = 1; +#endif + } + /* No need to do reference counting of hidkbd, wskbd has all the goo */ + if (kbd->sc_wskbddev != NULL) + rv = config_detach(kbd->sc_wskbddev, flags); + + return (rv); +} + +void +hidkbd_input(struct hidkbd *kbd, uint8_t *data, u_int len) +{ + struct hidkbd_data *ud = &kbd->sc_ndata; + int i; + +#ifdef HIDKBD_DEBUG + if (hidkbddebug > 5) { + printf("hidkbd_input: data"); + for (i = 0; i < len; i++) + printf(" 0x%02x", data[i]); + printf("\n"); + } +#endif + + /* extract key modifiers */ + ud->modifiers = 0; + for (i = 0; i < kbd->sc_nmod; i++) + if (hid_get_data(data, &kbd->sc_modloc[i])) + ud->modifiers |= kbd->sc_mods[i].mask; + + /* extract keycodes */ + memcpy(ud->keycode, data + kbd->sc_keycodeloc.pos / 8, + kbd->sc_nkeycode); + + if (kbd->sc_debounce && !kbd->sc_polling) { + /* + * Some keyboards have a peculiar quirk. They sometimes + * generate a key up followed by a key down for the same + * key after about 10 ms. + * We avoid this bug by holding off decoding for 20 ms. + */ + kbd->sc_data = *ud; + timeout_add_msec(&kbd->sc_delay, 20); +#ifdef DDB + } else if (kbd->sc_console_keyboard && !kbd->sc_polling) { + /* + * For the console keyboard we can't deliver CTL-ALT-ESC + * from the interrupt routine. Doing so would start + * polling from inside the interrupt routine and that + * loses bigtime. + */ + /* if (!timeout_pending(&kbd->sc_delay)) */ { + kbd->sc_data = *ud; + timeout_add(&kbd->sc_delay, 1); + } +#endif + } else { + hidkbd_decode(kbd, ud); + } +} + +void +hidkbd_delayed_decode(void *addr) +{ + struct hidkbd *kbd = addr; + + hidkbd_decode(kbd, &kbd->sc_data); +} + +void +hidkbd_decode(struct hidkbd *kbd, struct hidkbd_data *ud) +{ + uint32_t mod, omod; + u_int16_t ibuf[MAXKEYS]; /* chars events */ + int s; + int nkeys, i, j; + int key; +#define ADDKEY(c) ibuf[nkeys++] = (c) + +#ifdef HIDKBD_DEBUG + /* + * Keep a trace of the last events. Using printf changes the + * timing, so this can be useful sometimes. + */ + if (hidkbdtrace) { + struct hidkbdtraceinfo *p = &hidkbdtracedata[hidkbdtraceindex]; + p->unit = kbd->sc_hdev.sc_dev.dv_unit; + microtime(&p->tv); + p->ud = *ud; + if (++hidkbdtraceindex >= HIDKBDTRACESIZE) + hidkbdtraceindex = 0; + } + if (hidkbddebug > 5) { + struct timeval tv; + microtime(&tv); + DPRINTF((" at %lu.%06lu mod=0x%02x key0=0x%02x key1=0x%02x " + "key2=0x%02x key3=0x%02x\n", + tv.tv_sec, tv.tv_usec, + ud->modifiers, ud->keycode[0], ud->keycode[1], + ud->keycode[2], ud->keycode[3])); + } +#endif + + if (ud->keycode[0] == KEY_ERROR) { + DPRINTF(("hidkbd_input: KEY_ERROR\n")); + return; /* ignore */ + } + nkeys = 0; + mod = ud->modifiers; + omod = kbd->sc_odata.modifiers; + if (mod != omod) + for (i = 0; i < kbd->sc_nmod; i++) + if (( mod & kbd->sc_mods[i].mask) != + (omod & kbd->sc_mods[i].mask)) + ADDKEY(kbd->sc_mods[i].key | + (mod & kbd->sc_mods[i].mask + ? PRESS : RELEASE)); + if (memcmp(ud->keycode, kbd->sc_odata.keycode, kbd->sc_nkeycode) != 0) { + /* Check for released keys. */ + for (i = 0; i < kbd->sc_nkeycode; i++) { + key = kbd->sc_odata.keycode[i]; + if (key == 0) + continue; + for (j = 0; j < kbd->sc_nkeycode; j++) + if (key == ud->keycode[j]) + goto rfound; + DPRINTFN(3,("hidkbd_decode: relse key=0x%02x\n", key)); + ADDKEY(key | RELEASE); + rfound: + ; + } + + /* Check for pressed keys. */ + for (i = 0; i < kbd->sc_nkeycode; i++) { + key = ud->keycode[i]; + if (key == 0) + continue; + for (j = 0; j < kbd->sc_nkeycode; j++) + if (key == kbd->sc_odata.keycode[j]) + goto pfound; + DPRINTFN(2,("hidkbd_decode: press key=0x%02x\n", key)); + ADDKEY(key | PRESS); + pfound: + ; + } + } + kbd->sc_odata = *ud; + + if (nkeys == 0) + return; + + if (kbd->sc_polling) { + DPRINTFN(1,("hidkbd_decode: pollchar = 0x%03x\n", ibuf[0])); + memcpy(kbd->sc_pollchars, ibuf, nkeys * sizeof(u_int16_t)); + kbd->sc_npollchar = nkeys; + return; + } + + if (kbd->sc_wskbddev == NULL) + return; + +#ifdef WSDISPLAY_COMPAT_RAWKBD + if (kbd->sc_rawkbd) { + u_char cbuf[MAXKEYS * 2]; + int c; + int npress; + + for (npress = i = j = 0; i < nkeys; i++) { + key = ibuf[i]; + c = hidkbd_trtab[key & CODEMASK]; + if (c == NN) + continue; + if (c & 0x80) + cbuf[j++] = 0xe0; + cbuf[j] = c & 0x7f; + if (key & RELEASE) + cbuf[j] |= 0x80; + else { + /* remember pressed keys for autorepeat */ + if (c & 0x80) + kbd->sc_rep[npress++] = 0xe0; + kbd->sc_rep[npress++] = c & 0x7f; + } + DPRINTFN(1,("hidkbd_decode: raw = %s0x%02x\n", + c & 0x80 ? "0xe0 " : "", + cbuf[j])); + j++; + } + s = spltty(); + wskbd_rawinput(kbd->sc_wskbddev, cbuf, j); + if (npress != 0) { + kbd->sc_nrep = npress; + timeout_add_msec(&kbd->sc_rawrepeat_ch, REP_DELAY1); + } else + timeout_del(&kbd->sc_rawrepeat_ch); + + /* + * Pass audio keys to wskbd_input anyway. + */ + for (i = 0; i < nkeys; i++) { + key = ibuf[i]; + switch (key & CODEMASK) { + case 127: + case 128: + case 129: + wskbd_input(kbd->sc_wskbddev, + key & RELEASE ? WSCONS_EVENT_KEY_UP : + WSCONS_EVENT_KEY_DOWN, key & CODEMASK); + break; + } + } + splx(s); + + return; + } +#endif + + s = spltty(); + for (i = 0; i < nkeys; i++) { + key = ibuf[i]; + wskbd_input(kbd->sc_wskbddev, + key&RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN, + key&CODEMASK); + } + splx(s); +#undef ADDKEY +} + +int +hidkbd_enable(struct hidkbd *kbd, int on) +{ + if (kbd->sc_enabled == on) + return EBUSY; + + kbd->sc_enabled = on; + return 0; +} + +int +hidkbd_set_leds(struct hidkbd *kbd, int leds, uint8_t *report) +{ + if (kbd->sc_leds == leds) + return 0; + + kbd->sc_leds = leds; + + /* + * This is not totally correct, since we did not check the + * report size from the descriptor but for keyboards it should + * just be a single byte with the relevant bits set. + */ + *report = 0; + if ((leds & WSKBD_LED_SCROLL) && kbd->sc_scroloc.size == 1) + *report |= 1 << kbd->sc_scroloc.pos; + if ((leds & WSKBD_LED_NUM) && kbd->sc_numloc.size == 1) + *report |= 1 << kbd->sc_numloc.pos; + if ((leds & WSKBD_LED_CAPS) && kbd->sc_capsloc.size == 1) + *report |= 1 << kbd->sc_capsloc.pos; + + return 1; +} + +int +hidkbd_ioctl(struct hidkbd *kbd, u_long cmd, caddr_t data, int flag, + struct proc *p) +{ + switch (cmd) { + case WSKBDIO_GETLEDS: + *(int *)data = kbd->sc_leds; + return (0); + case WSKBDIO_COMPLEXBELL: +#define d ((struct wskbd_bell_data *)data) + hidkbd_bell(d->pitch, d->period, d->volume, 0); +#undef d + return (0); +#ifdef WSDISPLAY_COMPAT_RAWKBD + case WSKBDIO_SETMODE: + DPRINTF(("hidkbd_ioctl: set raw = %d\n", *(int *)data)); + kbd->sc_rawkbd = *(int *)data == WSKBD_RAW; + timeout_del(&kbd->sc_rawrepeat_ch); + return (0); +#endif + } + return (-1); +} + +#ifdef WSDISPLAY_COMPAT_RAWKBD +void +hidkbd_rawrepeat(void *v) +{ + struct hidkbd *kbd = v; + int s; + + s = spltty(); + wskbd_rawinput(kbd->sc_wskbddev, kbd->sc_rep, kbd->sc_nrep); + splx(s); + timeout_add_msec(&kbd->sc_rawrepeat_ch, REP_DELAYN); +} +#endif + +void +hidkbd_cngetc(struct hidkbd *kbd, u_int *type, int *data) +{ + int c; + + c = kbd->sc_pollchars[0]; + kbd->sc_npollchar--; + memcpy(kbd->sc_pollchars, kbd->sc_pollchars+1, + kbd->sc_npollchar * sizeof(u_int16_t)); + *type = c & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; + *data = c & CODEMASK; +} + +void +hidkbd_bell(u_int pitch, u_int period, u_int volume, int poll) +{ + if (hidkbd_bell_fn != NULL) + (*hidkbd_bell_fn)(hidkbd_bell_fn_arg, pitch, period, + volume, poll); +} + +void +hidkbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg) +{ + if (hidkbd_bell_fn == NULL) { + hidkbd_bell_fn = fn; + hidkbd_bell_fn_arg = arg; + } +} + +const char * +hidkbd_parse_desc(struct hidkbd *kbd, int id, void *desc, int dlen) +{ + struct hid_data *d; + struct hid_item h; + int imod; + + imod = 0; + kbd->sc_nkeycode = 0; + d = hid_start_parse(desc, dlen, hid_input); + while (hid_get_item(d, &h)) { + if (h.kind != hid_input || (h.flags & HIO_CONST) || + HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD || + h.report_ID != id) + continue; + + DPRINTF(("hidkbd: imod=%d usage=0x%x flags=0x%x pos=%d size=%d " + "cnt=%d\n", imod, + h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count)); + if (h.flags & HIO_VARIABLE) { + if (h.loc.size != 1) + return ("bad modifier size"); + /* Single item */ + if (imod < MAXMOD) { + kbd->sc_modloc[imod] = h.loc; + kbd->sc_mods[imod].mask = 1 << imod; + kbd->sc_mods[imod].key = HID_GET_USAGE(h.usage); + imod++; + } else + return ("too many modifier keys"); + } else { + /* Array */ + if (h.loc.size != 8) + return ("key code size != 8"); + if (h.loc.count > MAXKEYCODE) + return ("too many key codes"); + if (h.loc.pos % 8 != 0) + return ("key codes not on byte boundary"); + if (kbd->sc_nkeycode != 0) + return ("multiple key code arrays\n"); + kbd->sc_keycodeloc = h.loc; + kbd->sc_nkeycode = h.loc.count; + } + } + kbd->sc_nmod = imod; + hid_end_parse(d); + + hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK), + id, hid_output, &kbd->sc_numloc, NULL); + hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK), + id, hid_output, &kbd->sc_capsloc, NULL); + hid_locate(desc, dlen, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK), + id, hid_output, &kbd->sc_scroloc, NULL); + + return (NULL); +} diff --git a/sys/dev/usb/hidkbdsc.h b/sys/dev/usb/hidkbdsc.h new file mode 100644 index 00000000000..484bc25642b --- /dev/null +++ b/sys/dev/usb/hidkbdsc.h @@ -0,0 +1,104 @@ +/* $OpenBSD: hidkbdsc.h,v 1.1 2010/07/31 16:04:50 miod Exp $ */ +/* $NetBSD: ukbd.c,v 1.85 2003/03/11 16:44:00 augustss Exp $ */ + +/* + * 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. + * + * 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. + */ + +#define MAXKEYCODE 6 +#define MAXMOD 8 /* max 32 */ + +#define MAXKEYS (MAXMOD+2*MAXKEYCODE) + +struct hidkbd_data { + u_int32_t modifiers; + u_int8_t keycode[MAXKEYCODE]; +}; + +struct hidkbd { + /* stored data */ + struct hidkbd_data sc_ndata; + struct hidkbd_data sc_odata; + + /* input reports */ + struct hid_location sc_modloc[MAXMOD]; + u_int sc_nmod; + struct { + u_int32_t mask; + u_int8_t key; + } sc_mods[MAXMOD]; + + struct hid_location sc_keycodeloc; + u_int sc_nkeycode; + + /* output reports */ + struct hid_location sc_numloc; + struct hid_location sc_capsloc; + struct hid_location sc_scroloc; + int sc_leds; + + /* state information */ + struct device *sc_device; + struct device *sc_wskbddev; + char sc_enabled; + + char sc_console_keyboard; /* we are the console keyboard */ + + char sc_debounce; /* for quirk handling */ + struct timeout sc_delay; /* for quirk handling */ + struct hidkbd_data sc_data; /* for quirk handling */ + + /* key repeat logic */ + struct timeout sc_rawrepeat_ch; +#if defined(WSDISPLAY_COMPAT_RAWKBD) +#define REP_DELAY1 400 +#define REP_DELAYN 100 + int sc_rawkbd; + int sc_nrep; + char sc_rep[MAXKEYS]; +#endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */ + + int sc_polling; + int sc_npollchar; + u_int16_t sc_pollchars[MAXKEYS]; +}; + +int hidkbd_attach(struct device *, struct hidkbd *, int, uint32_t, + int, void *, int); +void hidkbd_attach_wskbd(struct hidkbd *, kbd_t, + const struct wskbd_accessops *); +void hidkbd_bell(u_int, u_int, u_int, int); +void hidkbd_cngetc(struct hidkbd *, u_int *, int *); +int hidkbd_detach(struct hidkbd *, int); +int hidkbd_enable(struct hidkbd *, int); +void hidkbd_input(struct hidkbd *, uint8_t *, u_int); +int hidkbd_ioctl(struct hidkbd *, u_long, caddr_t, int, struct proc *); +int hidkbd_set_leds(struct hidkbd *, int, uint8_t *); + +extern int hidkbd_is_console; diff --git a/sys/dev/usb/hidkbdvar.h b/sys/dev/usb/hidkbdvar.h new file mode 100644 index 00000000000..44b3d6408c2 --- /dev/null +++ b/sys/dev/usb/hidkbdvar.h @@ -0,0 +1,34 @@ +/* $OpenBSD: hidkbdvar.h,v 1.1 2010/07/31 16:04:50 miod Exp $ */ +/* $NetBSD: ukbd.c,v 1.85 2003/03/11 16:44:00 augustss Exp $ */ + +/* + * 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. + * + * 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. + */ + +void hidkbd_hookup_bell(void (*)(void *, u_int, u_int, u_int, int), void *); diff --git a/sys/dev/usb/hidms.c b/sys/dev/usb/hidms.c new file mode 100644 index 00000000000..f076c503bd4 --- /dev/null +++ b/sys/dev/usb/hidms.c @@ -0,0 +1,348 @@ +/* $OpenBSD: hidms.c,v 1.1 2010/07/31 16:04:50 miod Exp $ */ +/* $NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $ */ + +/* + * 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. + * + * 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. + */ + +/* + * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#ifdef HIDMS_DEBUG +#define DPRINTF(x) do { if (hidmsdebug) printf x; } while (0) +#define DPRINTFN(n,x) do { if (hidmsdebug>(n)) printf x; } while (0) +int hidmsdebug = 0; +#else +#define DPRINTF(x) +#define DPRINTFN(n,x) +#endif + +#define HIDMS_BUT(i) ((i) == 1 || (i) == 2 ? 3 - (i) : i) + +#define NOTMOUSE(f) (((f) & (HIO_CONST | HIO_RELATIVE)) != HIO_RELATIVE) + +int +hidms_setup(struct device *self, struct hidms *ms, uint32_t quirks, + int id, void *desc, int dlen) +{ + uint32_t flags; + int i, wheel, twheel; + + ms->sc_device = self; + + if (quirks & UQ_MS_REVZ) + ms->sc_flags |= HIDMS_REVZ; + if (quirks & UQ_SPUR_BUT_UP) + ms->sc_flags |= HIDMS_SPUR_BUT_UP; + if (quirks & UQ_MS_LEADING_BYTE) + ms->sc_flags |= HIDMS_LEADINGBYTE; + + if (!hid_locate(desc, dlen, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), id, + hid_input, &ms->sc_loc_x, &flags)) { + printf("\n%s: mouse has no X report\n", self->dv_xname); + return ENXIO; + } + if (NOTMOUSE(flags)) { + printf("\n%s: X report 0x%04x not supported\n", + self->dv_xname, flags); + return ENXIO; + } + + if (!hid_locate(desc, dlen, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), id, + hid_input, &ms->sc_loc_y, &flags)) { + printf("\n%s: mouse has no Y report\n", self->dv_xname); + return ENXIO; + } + if (NOTMOUSE(flags)) { + printf("\n%s: Y report 0x%04x not supported\n", + self->dv_xname, flags); + return ENXIO; + } + + /* + * Try to guess the Z activator: check WHEEL, TWHEEL, and Z, + * in that order. + */ + + wheel = hid_locate(desc, dlen, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), id, + hid_input, &ms->sc_loc_z, &flags); + if (wheel == 0) + twheel = hid_locate(desc, dlen, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_TWHEEL), id, + hid_input, &ms->sc_loc_z, &flags); + else + twheel = 0; + + if (wheel || twheel) { + if (NOTMOUSE(flags)) { + DPRINTF(("\n%s: Wheel report 0x%04x not supported\n", + self->dv_xname, flags)); + ms->sc_loc_z.size = 0; /* Bad Z coord, ignore it */ + } else { + ms->sc_flags |= HIDMS_Z; + /* Wheels need the Z axis reversed. */ + ms->sc_flags ^= HIDMS_REVZ; + } + /* + * We might have both a wheel and Z direction; in this case, + * report the Z direction on the W axis. + */ + if (hid_locate(desc, dlen, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), id, + hid_input, &ms->sc_loc_w, &flags)) { + if (NOTMOUSE(flags)) { + DPRINTF(("\n%s: Z report 0x%04x not supported\n", + self->dv_xname, flags)); + /* Bad Z coord, ignore it */ + ms->sc_loc_w.size = 0; + } + else + ms->sc_flags |= HIDMS_W; + } + } else if (hid_locate(desc, dlen, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), id, + hid_input, &ms->sc_loc_z, &flags)) { + if (NOTMOUSE(flags)) { + DPRINTF(("\n%s: Z report 0x%04x not supported\n", + self->dv_xname, flags)); + ms->sc_loc_z.size = 0; /* Bad Z coord, ignore it */ + } else { + ms->sc_flags |= HIDMS_Z; + } + } + + /* + * The Microsoft Wireless Intellimouse 2.0 reports its wheel + * using 0x0048 (I've called it HUG_TWHEEL) and seems to expect + * us to know that the byte after the wheel is the tilt axis. + * There are no other HID axis descriptors other than X, Y and + * TWHEEL, so we report TWHEEL on the W axis. + */ + if (twheel) { + ms->sc_loc_w = ms->sc_loc_z; + ms->sc_loc_w.pos = ms->sc_loc_w.pos + 8; + ms->sc_flags |= HIDMS_W | HIDMS_LEADINGBYTE; + /* Wheels need their axis reversed. */ + ms->sc_flags ^= HIDMS_REVW; + } + + /* figure out the number of buttons */ + for (i = 1; i <= MAX_BUTTONS; i++) + if (!hid_locate(desc, dlen, HID_USAGE2(HUP_BUTTON, i), id, + hid_input, &ms->sc_loc_btn[i - 1], 0)) + break; + ms->sc_num_buttons = i - 1; + + /* + * The Microsoft Wireless Notebook Optical Mouse seems to be in worse + * shape than the Wireless Intellimouse 2.0, as its X, Y, wheel, and + * all of its other button positions are all off. It also reports that + * it has two addional buttons and a tilt wheel. + */ + if (quirks & UQ_MS_BAD_CLASS) { + /* HIDMS_LEADINGBYTE cleared on purpose */ + ms->sc_flags = HIDMS_Z | HIDMS_SPUR_BUT_UP; + ms->sc_num_buttons = 3; + /* XXX change sc_hdev isize to 5? */ + /* 1st byte of descriptor report contains garbage */ + ms->sc_loc_x.pos = 16; + ms->sc_loc_y.pos = 24; + ms->sc_loc_z.pos = 32; + ms->sc_loc_btn[0].pos = 8; + ms->sc_loc_btn[1].pos = 9; + ms->sc_loc_btn[2].pos = 10; + } + + return 0; +} + +void +hidms_attach(struct hidms *ms, const struct wsmouse_accessops *ops) +{ + struct wsmousedev_attach_args a; +#ifdef HIDMS_DEBUG + int i; +#endif + + printf(": %d button%s", + ms->sc_num_buttons, ms->sc_num_buttons <= 1 ? "" : "s"); + switch (ms->sc_flags & (HIDMS_Z | HIDMS_W)) { + case HIDMS_Z: + printf(", Z dir"); + break; + case HIDMS_W: + printf(", W dir"); + break; + case HIDMS_Z | HIDMS_W: + printf(", Z and W dir"); + break; + } + printf("\n"); + +#ifdef HIDMS_DEBUG + DPRINTF(("hidms_attach: sc=%p\n", sc)); + DPRINTF(("hidms_attach: X\t%d/%d\n", + ms->sc_loc_x.pos, ms->sc_loc_x.size)); + DPRINTF(("hidms_attach: Y\t%d/%d\n", + ms->sc_loc_y.pos, ms->sc_loc_y.size)); + if (ms->sc_flags & HIDMS_Z) + DPRINTF(("hidms_attach: Z\t%d/%d\n", + ms->sc_loc_z.pos, ms->sc_loc_z.size)); + if (ms->sc_flags & HIDMS_W) + DPRINTF(("hidms_attach: W\t%d/%d\n", + ms->sc_loc_w.pos, ms->sc_loc_w.size)); + for (i = 1; i <= ms->sc_num_buttons; i++) { + DPRINTF(("hidms_attach: B%d\t%d/%d\n", + i, ms->sc_loc_btn[i - 1].pos, ms->sc_loc_btn[i - 1].size)); + } +#endif + + a.accessops = ops; + a.accesscookie = ms->sc_device; + ms->sc_wsmousedev = config_found(ms->sc_device, &a, wsmousedevprint); +} + +int +hidms_detach(struct hidms *ms, int flags) +{ + int rv = 0; + + DPRINTF(("hidms_detach: sc=%p flags=%d\n", sc, flags)); + + /* No need to do reference counting of hidms, wsmouse has all the goo */ + if (ms->sc_wsmousedev != NULL) + rv = config_detach(ms->sc_wsmousedev, flags); + + return (rv); +} + +void +hidms_input(struct hidms *ms, uint8_t *data, u_int len) +{ + int dx, dy, dz, dw; + u_int32_t buttons = 0; + int i, s; + + DPRINTFN(5,("hidms_input: len=%d\n", len)); + + /* + * The Microsoft Wireless Intellimouse 2.0 sends one extra leading + * byte of data compared to most USB mice. This byte frequently + * switches from 0x01 (usual state) to 0x02. It may be used to + * report non-standard events (such as battery life). However, + * at the same time, it generates a left click event on the + * button byte, where there shouldn't be any. We simply discard + * the packet in this case. + * + * This problem affects the MS Wireless Notebook Optical Mouse, too. + * However, the leading byte for this mouse is normally 0x11, and + * the phantom mouse click occurs when it's 0x14. + */ + if (ms->sc_flags & HIDMS_LEADINGBYTE) { + if (*data++ == 0x02) + return; + /* len--; */ + } else if (ms->sc_flags & HIDMS_SPUR_BUT_UP) { + if (*data == 0x14 || *data == 0x15) + return; + } + + dx = hid_get_data(data, &ms->sc_loc_x); + dy = -hid_get_data(data, &ms->sc_loc_y); + dz = hid_get_data(data, &ms->sc_loc_z); + dw = hid_get_data(data, &ms->sc_loc_w); + + if (ms->sc_flags & HIDMS_REVZ) + dz = -dz; + if (ms->sc_flags & HIDMS_REVW) + dw = -dw; + + for (i = 0; i < ms->sc_num_buttons; i++) + if (hid_get_data(data, &ms->sc_loc_btn[i])) + buttons |= (1 << HIDMS_BUT(i)); + + if (dx != 0 || dy != 0 || dz != 0 || dw != 0 || + buttons != ms->sc_buttons) { + DPRINTFN(10, ("hidms_input: x:%d y:%d z:%d w:%d buttons:0x%x\n", + dx, dy, dz, dw, buttons)); + ms->sc_buttons = buttons; + if (ms->sc_wsmousedev != NULL) { + s = spltty(); + wsmouse_input(ms->sc_wsmousedev, buttons, + dx, dy, dz, dw, WSMOUSE_INPUT_DELTA); + splx(s); + } + } +} + +int +hidms_enable(struct hidms *ms) +{ + if (ms->sc_enabled) + return EBUSY; + + ms->sc_enabled = 1; + ms->sc_buttons = 0; + return 0; +} + +int +hidms_ioctl(struct hidms *ms, u_long cmd, caddr_t data, int flag, + struct proc *p) +{ + switch (cmd) { + default: + return -1; + } +} + +void +hidms_disable(struct hidms *ms) +{ + ms->sc_enabled = 0; +} diff --git a/sys/dev/usb/hidmsvar.h b/sys/dev/usb/hidmsvar.h new file mode 100644 index 00000000000..bf032f25254 --- /dev/null +++ b/sys/dev/usb/hidmsvar.h @@ -0,0 +1,67 @@ +/* $OpenBSD: hidmsvar.h,v 1.1 2010/07/31 16:04:50 miod Exp $ */ +/* $NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $ */ + +/* + * 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. + * + * 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. + */ + +#define MAX_BUTTONS 31 /* must not exceed size of sc_buttons */ + +struct hidms { + int sc_enabled; + int sc_flags; /* device configuration */ +#define HIDMS_SPUR_BUT_UP 0x01 /* spurious button up events */ +#define HIDMS_Z 0x02 /* Z direction available */ +#define HIDMS_REVZ 0x04 /* Z-axis is reversed */ +#define HIDMS_W 0x08 /* W direction available */ +#define HIDMS_REVW 0x10 /* W-axis is reversed */ +#define HIDMS_LEADINGBYTE 0x20 /* Unknown leading byte */ + + int sc_num_buttons; + u_int32_t sc_buttons; /* mouse button status */ + + struct device *sc_device; + struct device *sc_wsmousedev; + + /* locators */ + struct hid_location sc_loc_x; + struct hid_location sc_loc_y; + struct hid_location sc_loc_z; + struct hid_location sc_loc_w; + struct hid_location sc_loc_btn[MAX_BUTTONS]; +}; + +void hidms_attach(struct hidms *, const struct wsmouse_accessops *); +int hidms_detach(struct hidms *, int); +void hidms_disable(struct hidms *); +int hidms_enable(struct hidms *); +void hidms_input(struct hidms *, uint8_t *, u_int); +int hidms_ioctl(struct hidms *, u_long, caddr_t, int, struct proc *); +int hidms_setup(struct device *, struct hidms *, uint32_t, int, void *, + int); diff --git a/sys/dev/usb/ukbd.c b/sys/dev/usb/ukbd.c index 8fa1e46d89a..6f63447b085 100644 --- a/sys/dev/usb/ukbd.c +++ b/sys/dev/usb/ukbd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ukbd.c,v 1.51 2010/02/22 17:24:20 miod Exp $ */ +/* $OpenBSD: ukbd.c,v 1.52 2010/07/31 16:04:50 miod Exp $ */ /* $NetBSD: ukbd.c,v 1.85 2003/03/11 16:44:00 augustss Exp $ */ /* @@ -41,12 +41,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include #include #include @@ -64,6 +58,9 @@ #include #include +#include +#include + #ifdef UKBD_DEBUG #define DPRINTF(x) do { if (ukbddebug) printf x; } while (0) #define DPRINTFN(n,x) do { if (ukbddebug>(n)) printf x; } while (0) @@ -73,62 +70,6 @@ int ukbddebug = 0; #define DPRINTFN(n,x) #endif -#define MAXKEYCODE 6 -#define MAXMOD 8 /* max 32 */ - -struct ukbd_data { - u_int32_t modifiers; - u_int8_t keycode[MAXKEYCODE]; -}; - -#define PRESS 0x000 -#define RELEASE 0x100 -#define CODEMASK 0x0ff - -#if defined(WSDISPLAY_COMPAT_RAWKBD) -#define NN 0 /* no translation */ -/* - * Translate USB keycodes to US keyboard XT scancodes. - * Scancodes >= 0x80 represent EXTENDED keycodes. - * - * See http://www.microsoft.com/whdc/device/input/Scancode.mspx - */ -const u_int8_t ukbd_trtab[256] = { - NN, NN, NN, NN, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */ - 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */ - 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */ - 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */ - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */ - 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */ - 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */ - 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */ - 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xaa, 0x46, /* 40 - 47 */ - 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */ - 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */ - 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */ - 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, 0x84, 0x59, /* 60 - 67 */ - 0x5d, 0x5e, 0x5f, NN, NN, NN, NN, NN, /* 68 - 6f */ - NN, NN, NN, NN, 0x97, NN, 0x93, 0x95, /* 70 - 77 */ - 0x91, 0x92, 0x94, 0x9a, 0x96, 0x98, 0x99, 0xa0, /* 78 - 7f */ - 0xb0, 0xae, NN, NN, NN, 0x7e, NN, 0x73, /* 80 - 87 */ - 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN, NN, NN, /* 88 - 8f */ - NN, NN, 0x78, 0x77, 0x76, 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 */ - 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* 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 */ -}; -#endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */ - const kbd_t ukbd_countrylayout[1 + HCC_MAX] = { (kbd_t)-1, (kbd_t)-1, /* arabic */ @@ -168,90 +109,13 @@ const kbd_t ukbd_countrylayout[1 + HCC_MAX] = { (kbd_t)-1 /* turkish F */ }; -#define KEY_ERROR 0x01 - -#define MAXKEYS (MAXMOD+2*MAXKEYCODE) - struct ukbd_softc { - struct uhidev sc_hdev; - - struct ukbd_data sc_ndata; - struct ukbd_data sc_odata; - struct hid_location sc_modloc[MAXMOD]; - u_int sc_nmod; - struct { - u_int32_t mask; - u_int8_t key; - } sc_mods[MAXMOD]; - - struct hid_location sc_keycodeloc; - u_int sc_nkeycode; - - char sc_enabled; - - int sc_console_keyboard; /* we are the console keyboard */ - - char sc_debounce; /* for quirk handling */ - struct timeout sc_delay; /* for quirk handling */ - struct ukbd_data sc_data; /* for quirk handling */ - - struct hid_location sc_numloc; - struct hid_location sc_capsloc; - struct hid_location sc_scroloc; - int sc_leds; - - struct timeout sc_rawrepeat_ch; - - struct device *sc_wskbddev; -#if defined(WSDISPLAY_COMPAT_RAWKBD) -#define REP_DELAY1 400 -#define REP_DELAYN 100 - int sc_rawkbd; - int sc_nrep; - char sc_rep[MAXKEYS]; -#endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */ - - int sc_spl; - int sc_polling; - int sc_npollchar; - u_int16_t sc_pollchars[MAXKEYS]; - - u_char sc_dying; + struct uhidev sc_hdev; + struct hidkbd sc_kbd; + u_char sc_dying; + int sc_spl; }; -#ifdef UKBD_DEBUG -#define UKBDTRACESIZE 64 -struct ukbdtraceinfo { - int unit; - struct timeval tv; - struct ukbd_data ud; -}; -struct ukbdtraceinfo ukbdtracedata[UKBDTRACESIZE]; -int ukbdtraceindex = 0; -int ukbdtrace = 0; -void ukbdtracedump(void); -void -ukbdtracedump(void) -{ - int i; - for (i = 0; i < UKBDTRACESIZE; i++) { - struct ukbdtraceinfo *p = - &ukbdtracedata[(i+ukbdtraceindex)%UKBDTRACESIZE]; - printf("%lu.%06lu: mod=0x%02x key0=0x%02x key1=0x%02x " - "key2=0x%02x key3=0x%02x\n", - p->tv.tv_sec, p->tv.tv_usec, - p->ud.modifiers, p->ud.keycode[0], p->ud.keycode[1], - p->ud.keycode[2], p->ud.keycode[3]); - } -} -#endif - -#define UKBDUNIT(dev) (minor(dev)) -#define UKBD_CHUNK 128 /* chunk size for read */ -#define UKBD_BSIZE 1020 /* buffer size */ - -int ukbd_is_console; - void ukbd_cngetc(void *, u_int *, int *); void ukbd_cnpollc(void *, int); void ukbd_cnbell(void *, u_int, u_int, u_int); @@ -262,24 +126,11 @@ const struct wskbd_consops ukbd_consops = { ukbd_cnbell, }; -const char *ukbd_parse_desc(struct ukbd_softc *sc); - -void (*ukbd_bell_fn)(void *, u_int, u_int, u_int, int); -void *ukbd_bell_fn_arg; - -void ukbd_bell(u_int, u_int, u_int, int); - void ukbd_intr(struct uhidev *addr, void *ibuf, u_int len); -void ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud); -void ukbd_delayed_decode(void *addr); int ukbd_enable(void *, int); void ukbd_set_leds(void *, int); - int ukbd_ioctl(void *, u_long, caddr_t, int, struct proc *); -#ifdef WSDISPLAY_COMPAT_RAWKBD -void ukbd_rawrepeat(void *v); -#endif const struct wskbd_accessops ukbd_accessops = { ukbd_enable, @@ -287,12 +138,6 @@ const struct wskbd_accessops ukbd_accessops = { ukbd_ioctl, }; -extern const struct wscons_keydesc ukbd_keydesctab[]; - -struct wskbd_mapdata ukbd_keymapdata = { - ukbd_keydesctab -}; - int ukbd_match(struct device *, void *, void *); void ukbd_attach(struct device *, struct device *, void *); int ukbd_detach(struct device *, int); @@ -330,50 +175,30 @@ void ukbd_attach(struct device *parent, struct device *self, void *aux) { struct ukbd_softc *sc = (struct ukbd_softc *)self; + struct hidkbd *kbd = &sc->sc_kbd; struct usb_attach_arg *uaa = aux; struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; usb_hid_descriptor_t *hid; u_int32_t qflags; - const char *parseerr; + int dlen; + void *desc; kbd_t layout = (kbd_t)-1; - struct wskbddev_attach_args a; sc->sc_hdev.sc_intr = ukbd_intr; sc->sc_hdev.sc_parent = uha->parent; sc->sc_hdev.sc_report_id = uha->reportid; - parseerr = ukbd_parse_desc(sc); - if (parseerr != NULL) { - printf("\n%s: attach failed, %s\n", - sc->sc_hdev.sc_dev.dv_xname, parseerr); - return; - } - - hid = usbd_get_hid_descriptor(uha->uaa->iface); - -#ifdef DIAGNOSTIC - printf(": %d modifier keys, %d key codes", - sc->sc_nmod, sc->sc_nkeycode); -#endif - + uhidev_get_report_desc(uha->parent, &desc, &dlen); qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags; - sc->sc_debounce = (qflags & UQ_SPUR_BUT_UP) != 0; - - /* - * Remember if we're the console keyboard. - * - * XXX This always picks the first keyboard on the - * first USB bus, but what else can we really do? - */ - if ((sc->sc_console_keyboard = ukbd_is_console) != 0) { - /* Don't let any other keyboard have it. */ - ukbd_is_console = 0; - } + if (hidkbd_attach(self, kbd, 1, qflags, uha->reportid, desc, dlen) != 0) + return; if (uha->uaa->vendor == USB_VENDOR_TOPRE && uha->uaa->product == USB_PRODUCT_TOPRE_HHKB) { /* ignore country code on purpose */ } else { + hid = usbd_get_hid_descriptor(uha->uaa->iface); + if (hid->bCountryCode <= HCC_MAX) layout = ukbd_countrylayout[hid->bCountryCode]; #ifdef DIAGNOSTIC @@ -388,65 +213,31 @@ ukbd_attach(struct device *parent, struct device *self, void *aux) layout = KB_US; #endif } - ukbd_keymapdata.layout = layout; printf("\n"); - if (sc->sc_console_keyboard) { + if (kbd->sc_console_keyboard) { + extern struct wskbd_mapdata ukbd_keymapdata; + DPRINTF(("ukbd_attach: console keyboard sc=%p\n", sc)); + ukbd_keymapdata.layout = layout; wskbd_cnattach(&ukbd_consops, sc, &ukbd_keymapdata); ukbd_enable(sc, 1); } - a.console = sc->sc_console_keyboard; - - a.keymap = &ukbd_keymapdata; - - a.accessops = &ukbd_accessops; - a.accesscookie = sc; - -#ifdef WSDISPLAY_COMPAT_RAWKBD - timeout_set(&sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc); -#endif - timeout_set(&sc->sc_delay, ukbd_delayed_decode, sc); - /* Flash the leds; no real purpose, just shows we're alive. */ ukbd_set_leds(sc, WSKBD_LED_SCROLL | WSKBD_LED_NUM | WSKBD_LED_CAPS); usbd_delay_ms(uha->parent->sc_udev, 400); ukbd_set_leds(sc, 0); - sc->sc_wskbddev = config_found(self, &a, wskbddevprint); -} - -int -ukbd_enable(void *v, int on) -{ - struct ukbd_softc *sc = v; - - if (on && sc->sc_dying) - return (EIO); - - /* Should only be called to change state */ - if (sc->sc_enabled == on) { - DPRINTF(("ukbd_enable: %s: bad call on=%d\n", - sc->sc_hdev.sc_dev.dv_xname, on)); - return (EBUSY); - } - - DPRINTF(("ukbd_enable: sc=%p on=%d\n", sc, on)); - sc->sc_enabled = on; - if (on) { - return (uhidev_open(&sc->sc_hdev)); - } else { - uhidev_close(&sc->sc_hdev); - return (0); - } + hidkbd_attach_wskbd(kbd, layout, &ukbd_accessops); } int ukbd_activate(struct device *self, int act) { struct ukbd_softc *sc = (struct ukbd_softc *)self; + struct hidkbd *kbd = &sc->sc_kbd; int rv = 0; switch (act) { @@ -454,8 +245,8 @@ ukbd_activate(struct device *self, int act) break; case DVACT_DEACTIVATE: - if (sc->sc_wskbddev != NULL) - rv = config_deactivate(sc->sc_wskbddev); + if (kbd->sc_wskbddev != NULL) + rv = config_deactivate(kbd->sc_wskbddev); sc->sc_dying = 1; break; } @@ -466,38 +257,10 @@ int ukbd_detach(struct device *self, int flags) { struct ukbd_softc *sc = (struct ukbd_softc *)self; - int rv = 0; + struct hidkbd *kbd = &sc->sc_kbd; + int rv; - DPRINTF(("ukbd_detach: sc=%p flags=%d\n", sc, flags)); - - if (sc->sc_console_keyboard) { -#if 0 - /* - * XXX Should probably disconnect our consops, - * XXX and either notify some other keyboard that - * XXX it can now be the console, or if there aren't - * XXX any more USB keyboards, set ukbd_is_console - * XXX back to 1 so that the next USB keyboard attached - * XXX to the system will get it. - */ - panic("ukbd_detach: console keyboard"); -#else - /* - * Disconnect our consops and set ukbd_is_console - * back to 1 so that the next USB keyboard attached - * to the system will get it. - * XXX Should notify some other keyboard that it can be - * XXX console, if there are any other keyboards. - */ - printf("%s: was console keyboard\n", - sc->sc_hdev.sc_dev.dv_xname); - wskbd_cndetach(); - ukbd_is_console = 1; -#endif - } - /* No need to do reference counting of ukbd, wskbd has all the goo. */ - if (sc->sc_wskbddev != NULL) - rv = config_detach(sc->sc_wskbddev, flags); + rv = hidkbd_detach(kbd, flags); /* The console keyboard does not get a disable call, so check pipe. */ if (sc->sc_hdev.sc_state & UHIDEV_OPEN) @@ -510,258 +273,53 @@ void ukbd_intr(struct uhidev *addr, void *ibuf, u_int len) { struct ukbd_softc *sc = (struct ukbd_softc *)addr; - struct ukbd_data *ud = &sc->sc_ndata; - int i; - -#ifdef UKBD_DEBUG - if (ukbddebug > 5) { - printf("ukbd_intr: data"); - for (i = 0; i < len; i++) - printf(" 0x%02x", ((u_char *)ibuf)[i]); - printf("\n"); - } -#endif + struct hidkbd *kbd = &sc->sc_kbd; - ud->modifiers = 0; - for (i = 0; i < sc->sc_nmod; i++) - if (hid_get_data(ibuf, &sc->sc_modloc[i])) - ud->modifiers |= sc->sc_mods[i].mask; - memcpy(ud->keycode, (char *)ibuf + sc->sc_keycodeloc.pos / 8, - sc->sc_nkeycode); - - if (sc->sc_debounce && !sc->sc_polling) { - /* - * Some keyboards have a peculiar quirk. They sometimes - * generate a key up followed by a key down for the same - * key after about 10 ms. - * We avoid this bug by holding off decoding for 20 ms. - */ - sc->sc_data = *ud; - timeout_add_msec(&sc->sc_delay, 20); -#ifdef DDB - } else if (sc->sc_console_keyboard && !sc->sc_polling) { - /* - * For the console keyboard we can't deliver CTL-ALT-ESC - * from the interrupt routine. Doing so would start - * polling from inside the interrupt routine and that - * loses bigtime. - */ - /* if (!timeout_pending(&sc->sc_delay)) */ { - sc->sc_data = *ud; - timeout_add(&sc->sc_delay, 1); - } -#endif - } else { - ukbd_decode(sc, ud); - } + if (kbd->sc_enabled != 0) + hidkbd_input(kbd, (uint8_t *)ibuf, len); } -void -ukbd_delayed_decode(void *addr) -{ - struct ukbd_softc *sc = addr; - - ukbd_decode(sc, &sc->sc_data); -} - -void -ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) +int +ukbd_enable(void *v, int on) { - int mod, omod; - u_int16_t ibuf[MAXKEYS]; /* chars events */ - int s; - int nkeys, i, j; - int key; -#define ADDKEY(c) ibuf[nkeys++] = (c) - -#ifdef UKBD_DEBUG - /* - * Keep a trace of the last events. Using printf changes the - * timing, so this can be useful sometimes. - */ - if (ukbdtrace) { - struct ukbdtraceinfo *p = &ukbdtracedata[ukbdtraceindex]; - p->unit = sc->sc_hdev.sc_dev.dv_unit; - microtime(&p->tv); - p->ud = *ud; - if (++ukbdtraceindex >= UKBDTRACESIZE) - ukbdtraceindex = 0; - } - if (ukbddebug > 5) { - struct timeval tv; - microtime(&tv); - DPRINTF((" at %lu.%06lu mod=0x%02x key0=0x%02x key1=0x%02x " - "key2=0x%02x key3=0x%02x\n", - tv.tv_sec, tv.tv_usec, - ud->modifiers, ud->keycode[0], ud->keycode[1], - ud->keycode[2], ud->keycode[3])); - } -#endif - - if (ud->keycode[0] == KEY_ERROR) { - DPRINTF(("ukbd_intr: KEY_ERROR\n")); - return; /* ignore */ - } - nkeys = 0; - mod = ud->modifiers; - omod = sc->sc_odata.modifiers; - if (mod != omod) - for (i = 0; i < sc->sc_nmod; i++) - if (( mod & sc->sc_mods[i].mask) != - (omod & sc->sc_mods[i].mask)) - ADDKEY(sc->sc_mods[i].key | - (mod & sc->sc_mods[i].mask - ? PRESS : RELEASE)); - if (memcmp(ud->keycode, sc->sc_odata.keycode, sc->sc_nkeycode) != 0) { - /* Check for released keys. */ - for (i = 0; i < sc->sc_nkeycode; i++) { - key = sc->sc_odata.keycode[i]; - if (key == 0) - continue; - for (j = 0; j < sc->sc_nkeycode; j++) - if (key == ud->keycode[j]) - goto rfound; - DPRINTFN(3,("ukbd_intr: relse key=0x%02x\n", key)); - ADDKEY(key | RELEASE); - rfound: - ; - } - - /* Check for pressed keys. */ - for (i = 0; i < sc->sc_nkeycode; i++) { - key = ud->keycode[i]; - if (key == 0) - continue; - for (j = 0; j < sc->sc_nkeycode; j++) - if (key == sc->sc_odata.keycode[j]) - goto pfound; - DPRINTFN(2,("ukbd_intr: press key=0x%02x\n", key)); - ADDKEY(key | PRESS); - pfound: - ; - } - } - sc->sc_odata = *ud; - - if (nkeys == 0) - return; + struct ukbd_softc *sc = v; + struct hidkbd *kbd = &sc->sc_kbd; + int rv; - if (sc->sc_polling) { - DPRINTFN(1,("ukbd_intr: pollchar = 0x%03x\n", ibuf[0])); - memcpy(sc->sc_pollchars, ibuf, nkeys * sizeof(u_int16_t)); - sc->sc_npollchar = nkeys; - return; - } -#ifdef WSDISPLAY_COMPAT_RAWKBD - if (sc->sc_rawkbd) { - u_char cbuf[MAXKEYS * 2]; - int c; - int npress; - - for (npress = i = j = 0; i < nkeys; i++) { - key = ibuf[i]; - c = ukbd_trtab[key & CODEMASK]; - if (c == NN) - continue; - if (c & 0x80) - cbuf[j++] = 0xe0; - cbuf[j] = c & 0x7f; - if (key & RELEASE) - cbuf[j] |= 0x80; - else { - /* remember pressed keys for autorepeat */ - if (c & 0x80) - sc->sc_rep[npress++] = 0xe0; - sc->sc_rep[npress++] = c & 0x7f; - } - DPRINTFN(1,("ukbd_intr: raw = %s0x%02x\n", - c & 0x80 ? "0xe0 " : "", - cbuf[j])); - j++; - } - s = spltty(); - wskbd_rawinput(sc->sc_wskbddev, cbuf, j); - if (npress != 0) { - sc->sc_nrep = npress; - timeout_add_msec(&sc->sc_rawrepeat_ch, REP_DELAY1); - } else - timeout_del(&sc->sc_rawrepeat_ch); - - /* - * Pass audio keys to wskbd_input anyway. - */ - for (i = 0; i < nkeys; i++) { - key = ibuf[i]; - switch (key & CODEMASK) { - case 127: - case 128: - case 129: - wskbd_input(sc->sc_wskbddev, - key & RELEASE ? WSCONS_EVENT_KEY_UP : - WSCONS_EVENT_KEY_DOWN, key & CODEMASK); - break; - } - } - splx(s); + if (on && sc->sc_dying) + return EIO; - return; - } -#endif + if ((rv = hidkbd_enable(kbd, on)) != 0) + return rv; - s = spltty(); - for (i = 0; i < nkeys; i++) { - key = ibuf[i]; - wskbd_input(sc->sc_wskbddev, - key&RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN, - key&CODEMASK); + if (on) { + return uhidev_open(&sc->sc_hdev); + } else { + uhidev_close(&sc->sc_hdev); + return 0; } - splx(s); } void ukbd_set_leds(void *v, int leds) { struct ukbd_softc *sc = v; + struct hidkbd *kbd = &sc->sc_kbd; u_int8_t res; - DPRINTF(("ukbd_set_leds: sc=%p leds=%d, sc_leds=%d\n", - sc, leds, sc->sc_leds)); - if (sc->sc_dying) return; - if (sc->sc_leds == leds) - return; - sc->sc_leds = leds; - res = 0; - /* XXX not really right */ - if ((leds & WSKBD_LED_SCROLL) && sc->sc_scroloc.size == 1) - res |= 1 << sc->sc_scroloc.pos; - if ((leds & WSKBD_LED_NUM) && sc->sc_numloc.size == 1) - res |= 1 << sc->sc_numloc.pos; - if ((leds & WSKBD_LED_CAPS) && sc->sc_capsloc.size == 1) - res |= 1 << sc->sc_capsloc.pos; - uhidev_set_report_async(&sc->sc_hdev, UHID_OUTPUT_REPORT, &res, 1); + if (hidkbd_set_leds(kbd, leds, &res) != 0) + uhidev_set_report_async(&sc->sc_hdev, UHID_OUTPUT_REPORT, + &res, 1); } -#ifdef WSDISPLAY_COMPAT_RAWKBD -void -ukbd_rawrepeat(void *v) -{ - struct ukbd_softc *sc = v; - int s; - - s = spltty(); - wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep); - splx(s); - timeout_add_msec(&sc->sc_rawrepeat_ch, REP_DELAYN); -} -#endif - int ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) { struct ukbd_softc *sc = v; + struct hidkbd *kbd = &sc->sc_kbd; switch (cmd) { case WSKBDIO_GTYPE: @@ -770,39 +328,8 @@ ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) case WSKBDIO_SETLEDS: ukbd_set_leds(v, *(int *)data); return (0); - case WSKBDIO_GETLEDS: - *(int *)data = sc->sc_leds; - return (0); - case WSKBDIO_COMPLEXBELL: -#define d ((struct wskbd_bell_data *)data) - ukbd_bell(d->pitch, d->period, d->volume, 0); -#undef d - return (0); -#ifdef WSDISPLAY_COMPAT_RAWKBD - case WSKBDIO_SETMODE: - DPRINTF(("ukbd_ioctl: set raw = %d\n", *(int *)data)); - sc->sc_rawkbd = *(int *)data == WSKBD_RAW; - timeout_del(&sc->sc_rawrepeat_ch); - return (0); -#endif - } - return (-1); -} - -void -ukbd_bell(u_int pitch, u_int period, u_int volume, int poll) -{ - if (ukbd_bell_fn != NULL) - (*ukbd_bell_fn)(ukbd_bell_fn_arg, pitch, period, - volume, poll); -} - -void -ukbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg) -{ - if (ukbd_bell_fn == NULL) { - ukbd_bell_fn = fn; - ukbd_bell_fn_arg = arg; + default: + return hidkbd_ioctl(kbd, cmd, data, flag, p); } } @@ -811,20 +338,15 @@ void ukbd_cngetc(void *v, u_int *type, int *data) { struct ukbd_softc *sc = v; - int c; + struct hidkbd *kbd = &sc->sc_kbd; DPRINTFN(0,("ukbd_cngetc: enter\n")); - sc->sc_polling = 1; - while(sc->sc_npollchar <= 0) + kbd->sc_polling = 1; + while (kbd->sc_npollchar <= 0) usbd_dopoll(sc->sc_hdev.sc_parent->sc_iface); - sc->sc_polling = 0; - c = sc->sc_pollchars[0]; - sc->sc_npollchar--; - memcpy(sc->sc_pollchars, sc->sc_pollchars+1, - sc->sc_npollchar * sizeof(u_int16_t)); - *type = c & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; - *data = c & CODEMASK; - DPRINTFN(0,("ukbd_cngetc: return 0x%02x\n", c)); + kbd->sc_polling = 0; + hidkbd_cngetc(kbd, type, data); + DPRINTFN(0,("ukbd_cngetc: return 0x%02x\n", *data)); } void @@ -846,7 +368,7 @@ ukbd_cnpollc(void *v, int on) void ukbd_cnbell(void *v, u_int pitch, u_int period, u_int volume) { - ukbd_bell(pitch, period, volume, 1); + hidkbd_bell(pitch, period, volume, 1); } int @@ -858,67 +380,6 @@ ukbd_cnattach(void) * XXX in order to work, so we can't do much for the console * XXX keyboard until autconfiguration has run its course. */ - ukbd_is_console = 1; + hidkbd_is_console = 1; return (0); } - -const char * -ukbd_parse_desc(struct ukbd_softc *sc) -{ - struct hid_data *d; - struct hid_item h; - int size; - void *desc; - int imod; - - uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size); - imod = 0; - sc->sc_nkeycode = 0; - d = hid_start_parse(desc, size, hid_input); - while (hid_get_item(d, &h)) { - /*printf("ukbd: id=%d kind=%d usage=0x%x flags=0x%x pos=%d size=%d cnt=%d\n", - h.report_ID, h.kind, h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count);*/ - if (h.kind != hid_input || (h.flags & HIO_CONST) || - HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD || - h.report_ID != sc->sc_hdev.sc_report_id) - continue; - DPRINTF(("ukbd: imod=%d usage=0x%x flags=0x%x pos=%d size=%d " - "cnt=%d\n", imod, - h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count)); - if (h.flags & HIO_VARIABLE) { - if (h.loc.size != 1) - return ("bad modifier size"); - /* Single item */ - if (imod < MAXMOD) { - sc->sc_modloc[imod] = h.loc; - sc->sc_mods[imod].mask = 1 << imod; - sc->sc_mods[imod].key = HID_GET_USAGE(h.usage); - imod++; - } else - return ("too many modifier keys"); - } else { - /* Array */ - if (h.loc.size != 8) - return ("key code size != 8"); - if (h.loc.count > MAXKEYCODE) - return ("too many key codes"); - if (h.loc.pos % 8 != 0) - return ("key codes not on byte boundary"); - if (sc->sc_nkeycode != 0) - return ("multiple key code arrays\n"); - sc->sc_keycodeloc = h.loc; - sc->sc_nkeycode = h.loc.count; - } - } - sc->sc_nmod = imod; - hid_end_parse(d); - - hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_NUM_LOCK), - sc->sc_hdev.sc_report_id, hid_output, &sc->sc_numloc, NULL); - hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_CAPS_LOCK), - sc->sc_hdev.sc_report_id, hid_output, &sc->sc_capsloc, NULL); - hid_locate(desc, size, HID_USAGE2(HUP_LEDS, HUD_LED_SCROLL_LOCK), - sc->sc_hdev.sc_report_id, hid_output, &sc->sc_scroloc, NULL); - - return (NULL); -} diff --git a/sys/dev/usb/ukbdvar.h b/sys/dev/usb/ukbdvar.h index e3613477644..7c2251f63e6 100644 --- a/sys/dev/usb/ukbdvar.h +++ b/sys/dev/usb/ukbdvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ukbdvar.h,v 1.4 2008/06/26 05:42:18 ray Exp $ */ +/* $OpenBSD: ukbdvar.h,v 1.5 2010/07/31 16:04:50 miod Exp $ */ /* $NetBSD: ukbdvar.h,v 1.2 2000/06/01 14:29:00 augustss Exp $ */ /*- @@ -36,7 +36,4 @@ int ukbd_cnattach(void); -void ukbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), - void *); - #endif /* _DEV_USB_UKBDVAR_H_ */ diff --git a/sys/dev/usb/ums.c b/sys/dev/usb/ums.c index 00b3b5fd06c..2a72197acb1 100644 --- a/sys/dev/usb/ums.c +++ b/sys/dev/usb/ums.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ums.c,v 1.31 2009/10/13 19:33:19 pirofti Exp $ */ +/* $OpenBSD: ums.c,v 1.32 2010/07/31 16:04:50 miod Exp $ */ /* $NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $ */ /* @@ -40,12 +40,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include #include #include @@ -60,48 +54,14 @@ #include #include -#ifdef USB_DEBUG -#define DPRINTF(x) do { if (umsdebug) printf x; } while (0) -#define DPRINTFN(n,x) do { if (umsdebug>(n)) printf x; } while (0) -int umsdebug = 0; -#else -#define DPRINTF(x) -#define DPRINTFN(n,x) -#endif - -#define UMS_BUT(i) ((i) == 1 || (i) == 2 ? 3 - (i) : i) - -#define UMSUNIT(s) (minor(s)) - -#define MAX_BUTTONS 16 /* must not exceed size of sc_buttons */ +#include struct ums_softc { - struct uhidev sc_hdev; - - struct hid_location sc_loc_x, sc_loc_y, sc_loc_z, sc_loc_w; - struct hid_location sc_loc_btn[MAX_BUTTONS]; - - int sc_enabled; - - int flags; /* device configuration */ -#define UMS_Z 0x01 /* Z direction available */ -#define UMS_SPUR_BUT_UP 0x02 /* spurious button up events */ -#define UMS_REVZ 0x04 /* Z-axis is reversed */ -#define UMS_W 0x08 /* W direction available */ -#define UMS_REVW 0x10 /* W-axis is reversed */ -#define UMS_LEADINGBYTE 0x20 /* Unknown leading byte */ - - int nbuttons; - - u_int32_t sc_buttons; /* mouse button status */ - struct device *sc_wsmousedev; - - char sc_dying; + struct uhidev sc_hdev; + struct hidms sc_ms; + char sc_dying; }; -#define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE) -#define MOUSE_FLAGS (HIO_RELATIVE) - void ums_intr(struct uhidev *addr, void *ibuf, u_int len); int ums_enable(void *); @@ -151,146 +111,22 @@ void ums_attach(struct device *parent, struct device *self, void *aux) { struct ums_softc *sc = (struct ums_softc *)self; + struct hidms *ms = &sc->sc_ms; struct usb_attach_arg *uaa = aux; struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; - struct wsmousedev_attach_args a; int size; void *desc; - u_int32_t flags, quirks; - int i, wheel, twheel; + u_int32_t quirks; sc->sc_hdev.sc_intr = ums_intr; sc->sc_hdev.sc_parent = uha->parent; sc->sc_hdev.sc_report_id = uha->reportid; quirks = usbd_get_quirks(uha->parent->sc_udev)->uq_flags; - if (quirks & UQ_MS_REVZ) - sc->flags |= UMS_REVZ; - if (quirks & UQ_SPUR_BUT_UP) - sc->flags |= UMS_SPUR_BUT_UP; - if (quirks & UQ_MS_LEADING_BYTE) - sc->flags |= UMS_LEADINGBYTE; - uhidev_get_report_desc(uha->parent, &desc, &size); - if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), - uha->reportid, hid_input, &sc->sc_loc_x, &flags)) { - printf("\n%s: mouse has no X report\n", - sc->sc_hdev.sc_dev.dv_xname); - return; - } - if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { - printf("\n%s: X report 0x%04x not supported\n", - sc->sc_hdev.sc_dev.dv_xname, flags); - return; - } - - if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), - uha->reportid, hid_input, &sc->sc_loc_y, &flags)) { - printf("\n%s: mouse has no Y report\n", - sc->sc_hdev.sc_dev.dv_xname); - return; - } - if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { - printf("\n%s: Y report 0x%04x not supported\n", - sc->sc_hdev.sc_dev.dv_xname, flags); + if (hidms_setup(self, ms, quirks, uha->reportid, desc, size) != 0) return; - } - - /* - * Try to guess the Z activator: check WHEEL, TWHEEL, and Z, - * in that order. - */ - - wheel = hid_locate(desc, size, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), - uha->reportid, hid_input, &sc->sc_loc_z, &flags); - if (wheel == 0) - twheel = hid_locate(desc, size, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_TWHEEL), - uha->reportid, hid_input, &sc->sc_loc_z, &flags); - else - twheel = 0; - - if (wheel || twheel) { - if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { - DPRINTF(("\n%s: Wheel report 0x%04x not supported\n", - sc->sc_hdev.sc_dev.dv_xname, flags)); - sc->sc_loc_z.size = 0; /* Bad Z coord, ignore it */ - } else { - sc->flags |= UMS_Z; - /* Wheels need the Z axis reversed. */ - sc->flags ^= UMS_REVZ; - } - /* - * We might have both a wheel and Z direction; in this case, - * report the Z direction on the W axis. - */ - if (hid_locate(desc, size, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), - uha->reportid, hid_input, &sc->sc_loc_w, &flags)) { - if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { - DPRINTF(("\n%s: Z report 0x%04x not supported\n", - sc->sc_hdev.sc_dev.dv_xname, flags)); - /* Bad Z coord, ignore it */ - sc->sc_loc_w.size = 0; - } - else - sc->flags |= UMS_W; - } - } else if (hid_locate(desc, size, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), - uha->reportid, hid_input, &sc->sc_loc_z, &flags)) { - if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { - DPRINTF(("\n%s: Z report 0x%04x not supported\n", - sc->sc_hdev.sc_dev.dv_xname, flags)); - sc->sc_loc_z.size = 0; /* Bad Z coord, ignore it */ - } else { - sc->flags |= UMS_Z; - } - } - - /* - * The Microsoft Wireless Intellimouse 2.0 reports its wheel - * using 0x0048 (I've called it HUG_TWHEEL) and seems to expect - * us to know that the byte after the wheel is the tilt axis. - * There are no other HID axis descriptors other than X, Y and - * TWHEEL, so we report TWHEEL on the W axis. - */ - if (twheel) { - sc->sc_loc_w = sc->sc_loc_z; - sc->sc_loc_w.pos = sc->sc_loc_w.pos + 8; - sc->flags |= UMS_W | UMS_LEADINGBYTE; - /* Wheels need their axis reversed. */ - sc->flags ^= UMS_REVW; - } - - /* figure out the number of buttons */ - for (i = 1; i <= MAX_BUTTONS; i++) - if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i), - uha->reportid, hid_input, &sc->sc_loc_btn[i - 1], 0)) - break; - sc->nbuttons = i - 1; - - /* - * The Microsoft Wireless Notebook Optical Mouse seems to be in worse - * shape than the Wireless Intellimouse 2.0, as its X, Y, wheel, and - * all of its other button positions are all off. It also reports that - * it has two addional buttons and a tilt wheel. - */ - if (quirks & UQ_MS_BAD_CLASS) { - /* UMS_LEADINGBYTE cleared on purpose */ - sc->flags = UMS_Z | UMS_SPUR_BUT_UP; - sc->nbuttons = 3; - /* XXX change sc_hdev isize to 5? */ - /* 1st byte of descriptor report contains garbage */ - sc->sc_loc_x.pos = 16; - sc->sc_loc_y.pos = 24; - sc->sc_loc_z.pos = 32; - sc->sc_loc_btn[0].pos = 8; - sc->sc_loc_btn[1].pos = 9; - sc->sc_loc_btn[2].pos = 10; - } /* * The Microsoft Wireless Notebook Optical Mouse 3000 Model 1049 has @@ -301,60 +137,25 @@ ums_attach(struct device *parent, struct device *self, void *aux) */ if (uaa->vendor == USB_VENDOR_MICROSOFT && uaa->product == USB_PRODUCT_MICROSOFT_WLNOTEBOOK3) { - sc->flags = UMS_Z; - sc->nbuttons = 3; + ms->sc_flags = HIDMS_Z; + ms->sc_num_buttons = 3; /* XXX change sc_hdev isize to 5? */ - sc->sc_loc_x.pos = 8; - sc->sc_loc_y.pos = 16; - sc->sc_loc_z.pos = 24; - sc->sc_loc_btn[0].pos = 0; - sc->sc_loc_btn[1].pos = 1; - sc->sc_loc_btn[2].pos = 2; + ms->sc_loc_x.pos = 8; + ms->sc_loc_y.pos = 16; + ms->sc_loc_z.pos = 24; + ms->sc_loc_btn[0].pos = 0; + ms->sc_loc_btn[1].pos = 1; + ms->sc_loc_btn[2].pos = 2; } - printf(": %d button%s", - sc->nbuttons, sc->nbuttons <= 1 ? "" : "s"); - switch (sc->flags & (UMS_Z | UMS_W)) { - case UMS_Z: - printf(", Z dir"); - break; - case UMS_W: - printf(", W dir"); - break; - case UMS_Z | UMS_W: - printf(", Z and W dir"); - break; - } - printf("\n"); - -#ifdef USB_DEBUG - DPRINTF(("ums_attach: sc=%p\n", sc)); - DPRINTF(("ums_attach: X\t%d/%d\n", - sc->sc_loc_x.pos, sc->sc_loc_x.size)); - DPRINTF(("ums_attach: Y\t%d/%d\n", - sc->sc_loc_y.pos, sc->sc_loc_y.size)); - if (sc->flags & UMS_Z) - DPRINTF(("ums_attach: Z\t%d/%d\n", - sc->sc_loc_z.pos, sc->sc_loc_z.size)); - if (sc->flags & UMS_W) - DPRINTF(("ums_attach: W\t%d/%d\n", - sc->sc_loc_w.pos, sc->sc_loc_w.size)); - for (i = 1; i <= sc->nbuttons; i++) { - DPRINTF(("ums_attach: B%d\t%d/%d\n", - i, sc->sc_loc_btn[i - 1].pos, sc->sc_loc_btn[i - 1].size)); - } -#endif - - a.accessops = &ums_accessops; - a.accesscookie = sc; - - sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); + hidms_attach(ms, &ums_accessops); } int ums_activate(struct device *self, int act) { struct ums_softc *sc = (struct ums_softc *)self; + struct hidms *ms = &sc->sc_ms; int rv = 0; switch (act) { @@ -362,8 +163,8 @@ ums_activate(struct device *self, int act) break; case DVACT_DEACTIVATE: - if (sc->sc_wsmousedev != NULL) - rv = config_deactivate(sc->sc_wsmousedev); + if (ms->sc_wsmousedev != NULL) + rv = config_deactivate(ms->sc_wsmousedev); sc->sc_dying = 1; break; } @@ -374,122 +175,58 @@ int ums_detach(struct device *self, int flags) { struct ums_softc *sc = (struct ums_softc *)self; - int rv = 0; + struct hidms *ms = &sc->sc_ms; - DPRINTF(("ums_detach: sc=%p flags=%d\n", sc, flags)); - - /* No need to do reference counting of ums, wsmouse has all the goo. */ - if (sc->sc_wsmousedev != NULL) - rv = config_detach(sc->sc_wsmousedev, flags); - - return (rv); + return hidms_detach(ms, flags); } void ums_intr(struct uhidev *addr, void *buf, u_int len) { struct ums_softc *sc = (struct ums_softc *)addr; - u_char *ibuf = (u_char *)buf; - int dx, dy, dz, dw; - u_int32_t buttons = 0; - int i; - int s; + struct hidms *ms = &sc->sc_ms; - DPRINTFN(5,("ums_intr: len=%d\n", len)); - - /* - * The Microsoft Wireless Intellimouse 2.0 sends one extra leading - * byte of data compared to most USB mice. This byte frequently - * switches from 0x01 (usual state) to 0x02. It may be used to - * report non-standard events (such as battery life). However, - * at the same time, it generates a left click event on the - * button byte, where there shouldn't be any. We simply discard - * the packet in this case. - * - * This problem affects the MS Wireless Notebook Optical Mouse, too. - * However, the leading byte for this mouse is normally 0x11, and - * the phantom mouse click occurs when it's 0x14. - */ - if (sc->flags & UMS_LEADINGBYTE) { - if (*ibuf++ == 0x02) - return; - /* len--; */ - } else if (sc->flags & UMS_SPUR_BUT_UP) { - if (*ibuf == 0x14 || *ibuf == 0x15) - return; - } - - dx = hid_get_data(ibuf, &sc->sc_loc_x); - dy = -hid_get_data(ibuf, &sc->sc_loc_y); - dz = hid_get_data(ibuf, &sc->sc_loc_z); - dw = hid_get_data(ibuf, &sc->sc_loc_w); - if (sc->flags & UMS_REVZ) - dz = -dz; - if (sc->flags & UMS_REVW) - dw = -dw; - for (i = 0; i < sc->nbuttons; i++) - if (hid_get_data(ibuf, &sc->sc_loc_btn[i])) - buttons |= (1 << UMS_BUT(i)); - - if (dx != 0 || dy != 0 || dz != 0 || dw != 0 || - buttons != sc->sc_buttons) { - DPRINTFN(10, ("ums_intr: x:%d y:%d z:%d w:%d buttons:0x%x\n", - dx, dy, dz, dw, buttons)); - sc->sc_buttons = buttons; - if (sc->sc_wsmousedev != NULL) { - s = spltty(); - wsmouse_input(sc->sc_wsmousedev, buttons, - dx, dy, dz, dw, WSMOUSE_INPUT_DELTA); - splx(s); - } - } + if (ms->sc_enabled != 0) + hidms_input(ms, (uint8_t *)buf, len); } int ums_enable(void *v) { struct ums_softc *sc = v; - - DPRINTFN(1,("ums_enable: sc=%p\n", sc)); + struct hidms *ms = &sc->sc_ms; + int rv; if (sc->sc_dying) - return (EIO); - - if (sc->sc_enabled) - return (EBUSY); + return EIO; - sc->sc_enabled = 1; - sc->sc_buttons = 0; + if ((rv = hidms_enable(ms)) != 0) + return rv; - return (uhidev_open(&sc->sc_hdev)); + return uhidev_open(&sc->sc_hdev); } void ums_disable(void *v) { struct ums_softc *sc = v; + struct hidms *ms = &sc->sc_ms; - DPRINTFN(1,("ums_disable: sc=%p\n", sc)); -#ifdef DIAGNOSTIC - if (!sc->sc_enabled) { - printf("ums_disable: not enabled\n"); - return; - } -#endif - - sc->sc_enabled = 0; + hidms_disable(ms); uhidev_close(&sc->sc_hdev); } int ums_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) - { + struct ums_softc *sc = v; + struct hidms *ms = &sc->sc_ms; + switch (cmd) { case WSMOUSEIO_GTYPE: *(u_int *)data = WSMOUSE_TYPE_USB; - return (0); + return 0; + default: + return hidms_ioctl(ms, cmd, data, flag, p); } - - return (-1); } -- cgit v1.2.3