diff options
author | Nathan Binkert <nate@cvs.openbsd.org> | 2002-05-09 15:06:30 +0000 |
---|---|---|
committer | Nathan Binkert <nate@cvs.openbsd.org> | 2002-05-09 15:06:30 +0000 |
commit | 23dcee9d39acf0acbda3ed2e33b4038f9d5e8132 (patch) | |
tree | c27e422c42192be2a5812b0859e70bb3754bd8b5 /sys/dev/usb | |
parent | 02a2153e2ea77635df4c6b97678b0749f66bee42 (diff) |
Sync hid stuff including ukbd, ums, and uhid with NetBSD
This adds a uhidev device which can be thought of as something like a
uhid bus. It allows more than one ukbd, ums, or uhid to attach to the same
device instance. This functionality is found on many of the newer keyboards
that have extra buttons. (The extra buttons show up as uhid device(s)).
Tested by me on i386, dale on macppc, and jason on sparc64
Diffstat (limited to 'sys/dev/usb')
-rw-r--r-- | sys/dev/usb/files.usb | 43 | ||||
-rw-r--r-- | sys/dev/usb/hid.c | 143 | ||||
-rw-r--r-- | sys/dev/usb/hid.h | 21 | ||||
-rw-r--r-- | sys/dev/usb/uhid.c | 349 | ||||
-rw-r--r-- | sys/dev/usb/uhidev.c | 513 | ||||
-rw-r--r-- | sys/dev/usb/uhidev.h | 91 | ||||
-rw-r--r-- | sys/dev/usb/ukbd.c | 492 | ||||
-rw-r--r-- | sys/dev/usb/ums.c | 197 | ||||
-rw-r--r-- | sys/dev/usb/usb.h | 3 | ||||
-rw-r--r-- | sys/dev/usb/usb_port.h | 5 | ||||
-rw-r--r-- | sys/dev/usb/usbhid.h | 19 |
11 files changed, 1121 insertions, 755 deletions
diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb index 5936f8fc971..f5fd7406e34 100644 --- a/sys/dev/usb/files.usb +++ b/sys/dev/usb/files.usb @@ -1,4 +1,4 @@ -# $OpenBSD: files.usb,v 1.24 2002/05/07 19:32:49 nate Exp $ +# $OpenBSD: files.usb,v 1.25 2002/05/09 15:06:29 nate 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. @@ -7,7 +7,6 @@ device usb { } attach usb at usbus -file dev/usb/hid.c usb file dev/usb/usb.c usb needs-flag file dev/usb/usbdi.c usb file dev/usb/usbdi_util.c usb @@ -45,16 +44,35 @@ device ugen attach ugen at uhub file dev/usb/ugen.c ugen needs-flag -# Generic HID devices -device uhid -attach uhid at uhub -file dev/usb/uhid.c uhid needs-flag +# HID +# HID "bus" +define uhidbus {[ reportid = -1 ]} + +# HID processing +define hid +file dev/usb/hid.c hid +# HID root device for multiple report IDs +device uhidev: hid, uhidbus +attach uhidev at uhub +file dev/usb/uhidev.c uhidev + +# Generic HID devices +device uhid: hid +attach uhid at uhidbus +file dev/usb/uhid.c uhid needs-flag + # Keyboards -device ukbd: wskbddev -attach ukbd at uhub -file dev/usb/ukbd.c ukbd needs-flag -file dev/usb/ukbdmap.c ukbd +device ukbd: hid, wskbddev +attach ukbd at uhidbus +file dev/usb/ukbd.c ukbd needs-flag +file dev/usb/ukbdmap.c ukbd + +# Mice +device ums: hid, wsmousedev +attach ums at uhidbus +file dev/usb/ums.c ums + # Printers device ulpt @@ -71,11 +89,6 @@ device umodem: ucombus attach umodem at uhub file dev/usb/umodem.c umodem -# Mice -device ums: wsmousedev -attach ums at uhub -file dev/usb/ums.c ums - # Diamond Multimedia Rio 500 device urio attach urio at uhub diff --git a/sys/dev/usb/hid.c b/sys/dev/usb/hid.c index d14721fe107..81deacbd866 100644 --- a/sys/dev/usb/hid.c +++ b/sys/dev/usb/hid.c @@ -1,5 +1,5 @@ -/* $OpenBSD: hid.c,v 1.11 2002/05/07 18:29:18 nate Exp $ */ -/* $NetBSD: hid.c,v 1.16 2000/06/01 14:28:57 augustss Exp $ */ +/* $OpenBSD: hid.c,v 1.12 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: hid.c,v 1.22 2002/01/12 17:11:03 tsutsui Exp $ */ /* $FreeBSD: src/sys/dev/usb/hid.c,v 1.11 1999/11/17 22:33:39 n_hibma Exp $ */ /* @@ -51,10 +51,10 @@ #include <dev/usb/hid.h> -#ifdef UHID_DEBUG -#define DPRINTF(x) if (usbdebug) logprintf x -#define DPRINTFN(n,x) if (usbdebug>(n)) logprintf x -extern int usbdebug; +#ifdef UHIDEV_DEBUG +#define DPRINTF(x) if (uhidevdebug) logprintf x +#define DPRINTFN(n,x) if (uhidevdebug>(n)) logprintf x +extern int uhidevdebug; #else #define DPRINTF(x) #define DPRINTFN(n,x) @@ -62,7 +62,7 @@ extern int usbdebug; Static void hid_clear_local(struct hid_item *); -#define MAXUSAGE 100 +#define MAXUSAGE 256 struct hid_data { u_char *start; u_char *end; @@ -73,13 +73,14 @@ struct hid_data { int minset; int multi; int multimax; - int kindset; + enum hid_kind kind; }; Static void hid_clear_local(struct hid_item *c) { + DPRINTFN(5,("hid_clear_local\n")); c->usage = 0; c->usage_minimum = 0; c->usage_maximum = 0; @@ -93,15 +94,18 @@ hid_clear_local(struct hid_item *c) } struct hid_data * -hid_start_parse(void *d, int len, int kindset) +hid_start_parse(void *d, int len, enum hid_kind kind) { struct hid_data *s; s = malloc(sizeof *s, M_TEMP, M_WAITOK); + if (s == NULL) + panic("hid_start_parse"); memset(s, 0, sizeof *s); + s->start = s->p = d; s->end = (char *)d + len; - s->kindset = kindset; + s->kind = kind; return (s); } @@ -128,15 +132,19 @@ hid_get_item(struct hid_data *s, struct hid_item *h) u_char *p; struct hid_item *hi; int i; + enum hid_kind retkind; top: + DPRINTFN(5,("hid_get_item: multi=%d multimax=%d\n", + s->multi, s->multimax)); if (s->multimax != 0) { if (s->multi < s->multimax) { c->usage = s->usages[min(s->multi, s->nu-1)]; s->multi++; *h = *c; c->loc.pos += c->loc.size; - h->next = 0; + h->next = NULL; + DPRINTFN(5,("return multi\n")); return (1); } else { c->loc.count = s->multimax; @@ -174,12 +182,12 @@ hid_get_item(struct hid_data *s, struct hid_item *h) dval = 0; break; case 1: - dval = (int8_t)*data++; + dval = /*(int8_t)*/ *data++; break; case 2: dval = *data++; dval |= *data++ << 8; - dval = (int16_t)dval; + dval = /*(int16_t)*/ dval; break; case 4: dval = *data++; @@ -192,15 +200,22 @@ hid_get_item(struct hid_data *s, struct hid_item *h) continue; } + DPRINTFN(5,("hid_get_item: bType=%d bTag=%d dval=%d\n", + bType, bTag, dval)); switch (bType) { case 0: /* Main */ switch (bTag) { case 8: /* Input */ - if (!(s->kindset & (1 << hid_input))) + retkind = hid_input; + ret: + if (s->kind != retkind) { + s->minset = 0; + s->nu = 0; + hid_clear_local(c); continue; - c->kind = hid_input; + } + c->kind = retkind; c->flags = dval; - ret: if (c->flags & HIO_VARIABLE) { s->multimax = c->loc.count; s->multi = 0; @@ -217,19 +232,18 @@ hid_get_item(struct hid_data *s, struct hid_item *h) } goto top; } else { + c->usage = c->_usage_page; /* XXX */ *h = *c; - h->next = 0; + h->next = NULL; c->loc.pos += - c->loc.size * c->loc.count; - hid_clear_local(c); + c->loc.size * c->loc.count; s->minset = 0; + s->nu = 0; + hid_clear_local(c); return (1); } case 9: /* Output */ - if (!(s->kindset & (1 << hid_output))) - continue; - c->kind = hid_output; - c->flags = dval; + retkind = hid_output; goto ret; case 10: /* Collection */ c->kind = hid_collection; @@ -240,16 +254,12 @@ hid_get_item(struct hid_data *s, struct hid_item *h) s->nu = 0; return (1); case 11: /* Feature */ - if (!(s->kindset & (1 << hid_feature))) - continue; - c->kind = hid_feature; - c->flags = dval; + retkind = hid_feature; goto ret; case 12: /* End collection */ c->kind = hid_endcollection; c->collevel--; *h = *c; - hid_clear_local(c); s->nu = 0; return (1); default: @@ -285,6 +295,7 @@ hid_get_item(struct hid_data *s, struct hid_item *h) break; case 8: c->report_ID = dval; + c->loc.pos = 0; break; case 9: c->loc.count = dval; @@ -367,35 +378,51 @@ hid_get_item(struct hid_data *s, struct hid_item *h) } int -hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t *idp) +hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t id) { struct hid_data *d; struct hid_item h; - int size, id; + int lo, hi; - id = 0; - for (d = hid_start_parse(buf, len, 1<<k); hid_get_item(d, &h); ) - if (h.report_ID != 0) - id = h.report_ID; + h.report_ID = 0; + lo = hi = -1; + DPRINTFN(2,("hid_report_size: kind=%d id=%d\n", k, id)); + for (d = hid_start_parse(buf, len, k); hid_get_item(d, &h); ) { + DPRINTFN(2,("hid_report_size: item kind=%d id=%d pos=%d " + "size=%d count=%d\n", + h.kind, h.report_ID, h.loc.pos, h.loc.size, + h.loc.count)); + if (h.report_ID == id && h.kind == k) { + if (lo < 0) { + lo = h.loc.pos; +#ifdef DIAGNOSTIC + if (lo != 0) { + printf("hid_report_size: lo != 0\n"); + } +#endif + } + hi = h.loc.pos + h.loc.size * h.loc.count; + DPRINTFN(2,("hid_report_size: lo=%d hi=%d\n", lo, hi)); + } + } hid_end_parse(d); - size = h.loc.pos; - if (id != 0) { - size += 8; - *idp = id; /* XXX wrong */ - } else - *idp = 0; - return ((size + 7) / 8); + return ((hi - lo + 7) / 8); } int -hid_locate(void *desc, int size, u_int32_t u, enum hid_kind k, +hid_locate(void *desc, int size, u_int32_t u, u_int8_t id, enum hid_kind k, struct hid_location *loc, u_int32_t *flags) { struct hid_data *d; struct hid_item h; - for (d = hid_start_parse(desc, size, 1<<k); hid_get_item(d, &h); ) { - if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) { + h.report_ID = 0; + DPRINTFN(5,("hid_locate: enter usage=0x%x kind=%d id=%d\n", u, k, id)); + for (d = hid_start_parse(desc, size, k); hid_get_item(d, &h); ) { + DPRINTFN(5,("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n", + h.usage, h.kind, h.report_ID, h.flags)); + if (h.kind == k && !(h.flags & HIO_CONST) && + h.usage == u && h.report_ID == id) { if (loc != NULL) *loc = h.loc; if (flags != NULL) @@ -437,19 +464,33 @@ hid_get_data(u_char *buf, struct hid_location *loc) } int -hid_is_collection(void *desc, int size, u_int32_t usage) +hid_is_collection(void *desc, int size, u_int8_t id, u_int32_t usage) { struct hid_data *hd; struct hid_item hi; - int err; + u_int32_t coll_usage = ~0; - hd = hid_start_parse(desc, size, hid_input); + hd = hid_start_parse(desc, size, hid_none); if (hd == NULL) return (0); - err = hid_get_item(hd, &hi) && - hi.kind == hid_collection && - hi.usage == usage; + DPRINTFN(2,("hid_is_collection: id=%d usage=0x%x\n", id, usage)); + while (hid_get_item(hd, &hi)) { + DPRINTFN(2,("hid_is_collection: kind=%d id=%d usage=0x%x" + "(0x%x)\n", + hi.kind, hi.report_ID, hi.usage, coll_usage)); + if (hi.kind == hid_collection && + hi.collection == HCOLL_APPLICATION) + coll_usage = hi.usage; + if (hi.kind == hid_endcollection && + coll_usage == usage && + hi.report_ID == id) { + DPRINTFN(2,("hid_is_collection: found\n")); + hid_end_parse(hd); + return (1); + } + } + DPRINTFN(2,("hid_is_collection: not found\n")); hid_end_parse(hd); - return (err); + return (0); } diff --git a/sys/dev/usb/hid.h b/sys/dev/usb/hid.h index 096a34e270f..18dac5988e5 100644 --- a/sys/dev/usb/hid.h +++ b/sys/dev/usb/hid.h @@ -1,5 +1,5 @@ -/* $OpenBSD: hid.h,v 1.6 2002/05/07 18:29:18 nate Exp $ */ -/* $NetBSD: hid.h,v 1.6 2000/06/01 14:28:57 augustss Exp $ */ +/* $OpenBSD: hid.h,v 1.7 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: hid.h,v 1.7 2001/12/28 17:32:36 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/hid.h,v 1.7 1999/11/17 22:33:40 n_hibma Exp $ */ /* @@ -40,7 +40,12 @@ */ enum hid_kind { - hid_input, hid_output, hid_feature, hid_collection, hid_endcollection + hid_input, + hid_output, + hid_feature, + hid_collection, + hid_endcollection, + hid_none }; struct hid_location { @@ -81,11 +86,11 @@ struct hid_item { struct hid_item *next; }; -struct hid_data *hid_start_parse(void *d, int len, int kindset); +struct hid_data *hid_start_parse(void *d, int len, enum hid_kind kind); void hid_end_parse(struct hid_data *s); int hid_get_item(struct hid_data *s, struct hid_item *h); -int hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t *id); -int hid_locate(void *desc, int size, u_int32_t usage, enum hid_kind kind, - struct hid_location *loc, u_int32_t *flags); +int hid_report_size(void *buf, int len, enum hid_kind k, u_int8_t id); +int hid_locate(void *desc, int size, u_int32_t usage, u_int8_t id, + enum hid_kind kind, struct hid_location *loc, u_int32_t *flags); u_long hid_get_data(u_char *buf, struct hid_location *loc); -int hid_is_collection(void *desc, int size, u_int32_t usage); +int hid_is_collection(void *desc, int size, u_int8_t id, u_int32_t usage); diff --git a/sys/dev/usb/uhid.c b/sys/dev/usb/uhid.c index 968af28c593..146a6ad44c7 100644 --- a/sys/dev/usb/uhid.c +++ b/sys/dev/usb/uhid.c @@ -1,6 +1,5 @@ -/* $OpenBSD: uhid.c,v 1.18 2002/05/07 18:29:18 nate Exp $ */ -/* $NetBSD: uhid.c,v 1.45 2001/10/26 17:58:21 augustss Exp $ */ -/* $FreeBSD: src/sys/dev/usb/uhid.c,v 1.22 1999/11/17 22:33:43 n_hibma Exp $ */ +/* $OpenBSD: uhid.c,v 1.19 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: uhid.c,v 1.51 2002/03/17 18:02:53 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -48,16 +47,8 @@ #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/signalvar.h> -#if defined(__NetBSD__) || defined(__OpenBSD__) #include <sys/device.h> #include <sys/ioctl.h> -#elif defined(__FreeBSD__) -#include <sys/ioccom.h> -#include <sys/filio.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/ioccom.h> -#endif #include <sys/conf.h> #include <sys/tty.h> #include <sys/file.h> @@ -75,8 +66,7 @@ #include <dev/usb/hid.h> #include <dev/usb/usb_quirks.h> -/* Report descriptor for broken Wacom Graphire */ -#include <dev/usb/ugraphire_rdesc.h> +#include <dev/usb/uhidev.h> #ifdef UHID_DEBUG #define DPRINTF(x) if (uhiddebug) logprintf x @@ -88,33 +78,20 @@ int uhiddebug = 0; #endif struct uhid_softc { - USBBASEDEVICE sc_dev; /* base device */ - usbd_device_handle sc_udev; - usbd_interface_handle sc_iface; /* interface */ - usbd_pipe_handle sc_intrpipe; /* interrupt pipe */ - int sc_ep_addr; + struct uhidev sc_hdev; int sc_isize; int sc_osize; int sc_fsize; - u_int8_t sc_iid; - u_int8_t sc_oid; - u_int8_t sc_fid; - u_char *sc_ibuf; u_char *sc_obuf; - void *sc_repdesc; - int sc_repdesc_size; - struct clist sc_q; struct selinfo sc_rsel; - struct proc *sc_async; /* process that wants SIGIO */ + usb_proc_ptr sc_async; /* process that wants SIGIO */ u_char sc_state; /* driver state */ -#define UHID_OPEN 0x01 /* device is open */ -#define UHID_ASLP 0x02 /* waiting for device data */ -#define UHID_NEEDCLEAR 0x04 /* needs clearing endpoint stall */ -#define UHID_IMMED 0x08 /* return read data immediately */ +#define UHID_ASLP 0x01 /* waiting for device data */ +#define UHID_IMMED 0x02 /* return read data immediately */ int sc_refcnt; u_char sc_dying; @@ -124,153 +101,52 @@ struct uhid_softc { #define UHID_CHUNK 128 /* chunk size for read */ #define UHID_BSIZE 1020 /* buffer size */ -#if defined(__NetBSD__) || defined(__OpenBSD__) cdev_decl(uhid); -#elif defined(__FreeBSD__) -d_open_t uhidopen; -d_close_t uhidclose; -d_read_t uhidread; -d_write_t uhidwrite; -d_ioctl_t uhidioctl; -d_poll_t uhidpoll; - -#define UHID_CDEV_MAJOR 122 - -Static struct cdevsw uhid_cdevsw = { - /* open */ uhidopen, - /* close */ uhidclose, - /* read */ uhidread, - /* write */ uhidwrite, - /* ioctl */ uhidioctl, - /* poll */ uhidpoll, - /* mmap */ nommap, - /* strategy */ nostrategy, - /* name */ "uhid", - /* maj */ UHID_CDEV_MAJOR, - /* dump */ nodump, - /* psize */ nopsize, - /* flags */ 0, - /* bmaj */ -1 -}; -#endif -Static void uhid_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); +Static void uhid_intr(struct uhidev *, void *, u_int len); Static int uhid_do_read(struct uhid_softc *, struct uio *uio, int); Static int uhid_do_write(struct uhid_softc *, struct uio *uio, int); -Static int uhid_do_ioctl(struct uhid_softc*, u_long, caddr_t, int,struct proc*); +Static int uhid_do_ioctl(struct uhid_softc*, u_long, caddr_t, int, + usb_proc_ptr); USB_DECLARE_DRIVER(uhid); USB_MATCH(uhid) { USB_MATCH_START(uhid, uaa); - usb_interface_descriptor_t *id; - - if (uaa->iface == NULL) - return (UMATCH_NONE); - id = usbd_get_interface_descriptor(uaa->iface); - if (id == NULL || id->bInterfaceClass != UICLASS_HID) - return (UMATCH_NONE); - if (uaa->matchlvl) - return (uaa->matchlvl); + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; + + DPRINTF(("uhid_match: report=%d\n", uha->reportid)); + + if (uha->matchlvl) + return (uha->matchlvl); return (UMATCH_IFACECLASS_GENERIC); } USB_ATTACH(uhid) { USB_ATTACH_START(uhid, sc, uaa); - usbd_interface_handle iface = uaa->iface; - usb_interface_descriptor_t *id; - usb_endpoint_descriptor_t *ed; - int size; + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; + int size, repid; void *desc; - usbd_status err; - char devinfo[1024]; - - sc->sc_udev = uaa->device; - sc->sc_iface = iface; - id = usbd_get_interface_descriptor(iface); - usbd_devinfo(uaa->device, 0, devinfo); - USB_ATTACH_SETUP; - printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), - devinfo, id->bInterfaceClass, id->bInterfaceSubClass); - - ed = usbd_interface2endpoint_descriptor(iface, 0); - if (ed == NULL) { - printf("%s: could not read endpoint descriptor\n", - USBDEVNAME(sc->sc_dev)); - sc->sc_dying = 1; - USB_ATTACH_ERROR_RETURN; - } - - DPRINTFN(10,("uhid_attach: bLength=%d bDescriptorType=%d " - "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" - " bInterval=%d\n", - ed->bLength, ed->bDescriptorType, - ed->bEndpointAddress & UE_ADDR, - UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", - ed->bmAttributes & UE_XFERTYPE, - UGETW(ed->wMaxPacketSize), ed->bInterval)); - - if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || - (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { - printf("%s: unexpected endpoint\n", USBDEVNAME(sc->sc_dev)); - sc->sc_dying = 1; - USB_ATTACH_ERROR_RETURN; - } - - sc->sc_ep_addr = ed->bEndpointAddress; - - if (uaa->vendor == USB_VENDOR_WACOM && - uaa->product == USB_PRODUCT_WACOM_GRAPHIRE /* && - uaa->revision == 0x???? */) { /* XXX should use revision */ - /* The report descriptor for the Wacom Graphire is broken. */ - size = sizeof uhid_graphire_report_descr; - desc = malloc(size, M_USBDEV, M_NOWAIT); - if (desc == NULL) - err = USBD_NOMEM; - else { - err = USBD_NORMAL_COMPLETION; - memcpy(desc, uhid_graphire_report_descr, size); - } - } else { - desc = NULL; - err = usbd_read_report_desc(uaa->iface, &desc, &size,M_USBDEV); - } - if (err) { - printf("%s: no report descriptor\n", USBDEVNAME(sc->sc_dev)); - sc->sc_dying = 1; - USB_ATTACH_ERROR_RETURN; - } - (void)usbd_set_idle(iface, 0, 0); - - sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid); - sc->sc_osize = hid_report_size(desc, size, hid_output, &sc->sc_oid); - sc->sc_fsize = hid_report_size(desc, size, hid_feature, &sc->sc_fid); + sc->sc_hdev.sc_intr = uhid_intr; + sc->sc_hdev.sc_parent = uha->parent; + sc->sc_hdev.sc_report_id = uha->reportid; - sc->sc_repdesc = desc; - sc->sc_repdesc_size = size; + uhidev_get_report_desc(uha->parent, &desc, &size); + repid = uha->reportid; + sc->sc_isize = hid_report_size(desc, size, hid_input, repid); + sc->sc_osize = hid_report_size(desc, size, hid_output, repid); + sc->sc_fsize = hid_report_size(desc, size, hid_feature, repid); -#ifdef __FreeBSD__ - { - static int global_init_done = 0; - - if (!global_init_done) { - cdevsw_add(&uhid_cdevsw); - global_init_done = 1; - } - } -#endif - - usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, - USBDEV(sc->sc_dev)); + printf(": input=%d, output=%d, feature=%d\n", + sc->sc_isize, sc->sc_osize, sc->sc_fsize); USB_ATTACH_SUCCESS_RETURN; } -#if defined(__NetBSD__) || defined(__OpenBSD__) int uhid_activate(device_ptr_t self, enum devact act) { @@ -287,36 +163,28 @@ uhid_activate(device_ptr_t self, enum devact act) } return (0); } -#endif USB_DETACH(uhid) { USB_DETACH_START(uhid, sc); int s; -#if defined(__NetBSD__) || defined(__OpenBSD__) int maj, mn; DPRINTF(("uhid_detach: sc=%p flags=%d\n", sc, flags)); -#else - DPRINTF(("uhid_detach: sc=%p\n", sc)); -#endif sc->sc_dying = 1; - if (sc->sc_intrpipe != NULL) - usbd_abort_pipe(sc->sc_intrpipe); - if (sc->sc_state & UHID_OPEN) { + if (sc->sc_hdev.sc_state & UHIDEV_OPEN) { s = splusb(); if (--sc->sc_refcnt >= 0) { /* Wake everyone */ wakeup(&sc->sc_q); /* Wait for processes to go away. */ - usb_detach_wait(USBDEV(sc->sc_dev)); + usb_detach_wait(USBDEV(sc->sc_hdev.sc_dev)); } splx(s); } -#if defined(__NetBSD__) || defined(__OpenBSD__) /* locate the major number */ for (maj = 0; maj < nchrdev; maj++) if (cdevsw[maj].d_open == uhidopen) @@ -325,47 +193,33 @@ USB_DETACH(uhid) /* Nuke the vnodes for any open instances (calls close). */ mn = self->dv_unit; vdevgone(maj, mn, mn, VCHR); -#elif defined(__FreeBSD__) - /* XXX not implemented yet */ -#endif - if (sc->sc_repdesc) - free(sc->sc_repdesc, M_USBDEV); - - usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, - USBDEV(sc->sc_dev)); +#if 0 + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, + sc->sc_hdev.sc_parent->sc_udev, + USBDEV(sc->sc_hdev.sc_dev)); +#endif return (0); } void -uhid_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) +uhid_intr(struct uhidev *addr, void *data, u_int len) { - struct uhid_softc *sc = addr; + struct uhid_softc *sc = (struct uhid_softc *)addr; #ifdef UHID_DEBUG if (uhiddebug > 5) { - u_int32_t cc, i; + u_int32_t i; - usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL); - DPRINTF(("uhid_intr: status=%d cc=%d\n", status, cc)); DPRINTF(("uhid_intr: data =")); - for (i = 0; i < cc; i++) - DPRINTF((" %02x", sc->sc_ibuf[i])); + for (i = 0; i < len; i++) + DPRINTF((" %02x", ((u_char *)data)[i])); DPRINTF(("\n")); } #endif - if (status == USBD_CANCELLED) - return; - - if (status != USBD_NORMAL_COMPLETION) { - DPRINTF(("uhid_intr: status=%d\n", status)); - sc->sc_state |= UHID_NEEDCLEAR; - return; - } - - (void) b_to_q(sc->sc_ibuf, sc->sc_isize, &sc->sc_q); + (void)b_to_q(data, len, &sc->sc_q); if (sc->sc_state & UHID_ASLP) { sc->sc_state &= ~UHID_ASLP; @@ -380,10 +234,10 @@ uhid_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) } int -uhidopen(dev_t dev, int flag, int mode, struct proc *p) +uhidopen(dev_t dev, int flag, int mode, usb_proc_ptr p) { struct uhid_softc *sc; - usbd_status err; + int error; USB_GET_SC_OPEN(uhid, UHIDUNIT(dev), sc); @@ -392,40 +246,23 @@ uhidopen(dev_t dev, int flag, int mode, struct proc *p) if (sc->sc_dying) return (ENXIO); - if (sc->sc_state & UHID_OPEN) - return (EBUSY); - sc->sc_state |= UHID_OPEN; + error = uhidev_open(&sc->sc_hdev); + if (error) + return (error); if (clalloc(&sc->sc_q, UHID_BSIZE, 0) == -1) { - sc->sc_state &= ~UHID_OPEN; + uhidev_close(&sc->sc_hdev); return (ENOMEM); } - - sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK); - - /* Set up interrupt pipe. */ - err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, - USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, sc->sc_ibuf, - sc->sc_isize, uhid_intr, USBD_DEFAULT_INTERVAL); - if (err) { - DPRINTF(("uhidopen: usbd_open_pipe_intr failed, " - "error=%d\n",err)); - free(sc->sc_ibuf, M_USBDEV); - free(sc->sc_obuf, M_USBDEV); - sc->sc_state &= ~UHID_OPEN; - return (EIO); - } - sc->sc_state &= ~UHID_IMMED; - - sc->sc_async = 0; + sc->sc_async = NULL; return (0); } int -uhidclose(dev_t dev, int flag, int mode, struct proc *p) +uhidclose(dev_t dev, int flag, int mode, usb_proc_ptr p) { struct uhid_softc *sc; @@ -433,19 +270,10 @@ uhidclose(dev_t dev, int flag, int mode, struct proc *p) DPRINTF(("uhidclose: sc=%p\n", sc)); - /* Disable interrupts. */ - usbd_abort_pipe(sc->sc_intrpipe); - usbd_close_pipe(sc->sc_intrpipe); - sc->sc_intrpipe = 0; - clfree(&sc->sc_q); - - free(sc->sc_ibuf, M_USBDEV); free(sc->sc_obuf, M_USBDEV); - - sc->sc_state &= ~UHID_OPEN; - - sc->sc_async = 0; + sc->sc_async = NULL; + uhidev_close(&sc->sc_hdev); return (0); } @@ -455,6 +283,7 @@ uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag) { int s; int error = 0; + int extra; size_t length; u_char buffer[UHID_CHUNK]; usbd_status err; @@ -462,12 +291,12 @@ uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag) DPRINTFN(1, ("uhidread\n")); if (sc->sc_state & UHID_IMMED) { DPRINTFN(1, ("uhidread immed\n")); - - err = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT, - sc->sc_iid, buffer, sc->sc_isize); + extra = sc->sc_hdev.sc_report_id != 0; + err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, + buffer, sc->sc_isize + extra); if (err) return (EIO); - return (uiomove(buffer, sc->sc_isize, uio)); + return (uiomove(buffer+extra, sc->sc_isize, uio)); } s = splusb(); @@ -486,11 +315,6 @@ uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag) sc->sc_state &= ~UHID_ASLP; break; } - if (sc->sc_state & UHID_NEEDCLEAR) { - DPRINTFN(-1,("uhidread: clearing stall\n")); - sc->sc_state &= ~UHID_NEEDCLEAR; - usbd_clear_endpoint_stall(sc->sc_intrpipe); - } } splx(s); @@ -523,7 +347,7 @@ uhidread(dev_t dev, struct uio *uio, int flag) sc->sc_refcnt++; error = uhid_do_read(sc, uio, flag); if (--sc->sc_refcnt < 0) - usb_detach_wakeup(USBDEV(sc->sc_dev)); + usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev)); return (error); } @@ -545,12 +369,8 @@ uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag) return (EINVAL); error = uiomove(sc->sc_obuf, size, uio); if (!error) { - if (sc->sc_oid) - err = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT, - sc->sc_obuf[0], sc->sc_obuf+1, size-1); - else - err = usbd_set_report(sc->sc_iface, UHID_OUTPUT_REPORT, - 0, sc->sc_obuf, size); + err = uhidev_set_report(&sc->sc_hdev, UHID_OUTPUT_REPORT, + sc->sc_obuf, size); if (err) error = EIO; } @@ -569,18 +389,20 @@ uhidwrite(dev_t dev, struct uio *uio, int flag) sc->sc_refcnt++; error = uhid_do_write(sc, uio, flag); if (--sc->sc_refcnt < 0) - usb_detach_wakeup(USBDEV(sc->sc_dev)); + usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev)); return (error); } int uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, - int flag, struct proc *p) + int flag, usb_proc_ptr p) { struct usb_ctl_report_desc *rd; struct usb_ctl_report *re; - int size, id; + u_char buffer[UHID_CHUNK]; + int size, extra; usbd_status err; + void *desc; DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd)); @@ -611,17 +433,18 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, break; case USB_GET_REPORT_DESC: + uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size); rd = (struct usb_ctl_report_desc *)addr; - size = min(sc->sc_repdesc_size, sizeof rd->ucrd_data); + size = min(size, sizeof rd->ucrd_data); rd->ucrd_size = size; - memcpy(rd->ucrd_data, sc->sc_repdesc, size); + memcpy(rd->ucrd_data, desc, size); break; case USB_SET_IMMED: if (*(int *)addr) { - /* XXX should read into ibuf, but does it matter? */ - err = usbd_get_report(sc->sc_iface, UHID_INPUT_REPORT, - sc->sc_iid, sc->sc_ibuf, sc->sc_isize); + extra = sc->sc_hdev.sc_report_id != 0; + err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT, + buffer, sc->sc_isize + extra); if (err) return (EOPNOTSUPP); @@ -635,21 +458,21 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, switch (re->ucr_report) { case UHID_INPUT_REPORT: size = sc->sc_isize; - id = sc->sc_iid; break; case UHID_OUTPUT_REPORT: size = sc->sc_osize; - id = sc->sc_oid; break; case UHID_FEATURE_REPORT: size = sc->sc_fsize; - id = sc->sc_fid; break; default: return (EINVAL); } - err = usbd_get_report(sc->sc_iface, re->ucr_report, id, - re->ucr_data, size); + extra = sc->sc_hdev.sc_report_id != 0; + err = uhidev_get_report(&sc->sc_hdev, re->ucr_report, + re->ucr_data, size + extra); + if (extra) + memcpy(re->ucr_data, re->ucr_data+1, size); if (err) return (EIO); break; @@ -659,26 +482,26 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, switch (re->ucr_report) { case UHID_INPUT_REPORT: size = sc->sc_isize; - id = sc->sc_iid; break; case UHID_OUTPUT_REPORT: size = sc->sc_osize; - id = sc->sc_oid; break; case UHID_FEATURE_REPORT: size = sc->sc_fsize; - id = sc->sc_fid; break; default: return (EINVAL); } - err = usbd_set_report(sc->sc_iface, re->ucr_report, id, - re->ucr_data, - size); + err = uhidev_set_report(&sc->sc_hdev, re->ucr_report, + re->ucr_data, size); if (err) return (EIO); break; + case USB_GET_REPORT_ID: + *(int *)addr = sc->sc_hdev.sc_report_id; + break; + default: return (EINVAL); } @@ -686,7 +509,7 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr, } int -uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) +uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, usb_proc_ptr p) { struct uhid_softc *sc; int error; @@ -696,12 +519,12 @@ uhidioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p) sc->sc_refcnt++; error = uhid_do_ioctl(sc, cmd, addr, flag, p); if (--sc->sc_refcnt < 0) - usb_detach_wakeup(USBDEV(sc->sc_dev)); + usb_detach_wakeup(USBDEV(sc->sc_hdev.sc_dev)); return (error); } int -uhidpoll(dev_t dev, int events, struct proc *p) +uhidpoll(dev_t dev, int events, usb_proc_ptr p) { struct uhid_softc *sc; int revents = 0; @@ -725,7 +548,3 @@ uhidpoll(dev_t dev, int events, struct proc *p) splx(s); return (revents); } - -#if defined(__FreeBSD__) -DRIVER_MODULE(uhid, uhub, uhid_driver, uhid_devclass, usbd_driver_load, 0); -#endif diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c new file mode 100644 index 00000000000..c7af847f017 --- /dev/null +++ b/sys/dev/usb/uhidev.c @@ -0,0 +1,513 @@ +/* $OpenBSD: uhidev.c,v 1.3 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: uhidev.c,v 1.5 2002/02/27 01:30:50 augustss Exp $ */ + +/* + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * HID spec: http://www.usb.org/developers/data/devclass/hid1_1.pdf + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/signalvar.h> +#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/conf.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbhid.h> + +#include <dev/usb/usbdevs.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdi_util.h> +#include <dev/usb/hid.h> +#include <dev/usb/usb_quirks.h> + +#include <dev/usb/uhidev.h> + +/* Report descriptor for broken Wacom Graphire */ +#include <dev/usb/ugraphire_rdesc.h> + +#ifdef UHIDEV_DEBUG +#define DPRINTF(x) if (uhidevdebug) logprintf x +#define DPRINTFN(n,x) if (uhidevdebug>(n)) logprintf x +int uhidevdebug = 0; +#else +#define DPRINTF(x) +#define DPRINTFN(n,x) +#endif + +Static void uhidev_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); + +Static int uhidev_maxrepid(void *buf, int len); +Static int uhidevprint(void *aux, const char *pnp); +#if defined(__NetBSD__) +Static int uhidevsubmatch(struct device *parent, struct cfdata *cf, void *aux); +#else +Static int uhidevsubmatch(struct device *parent, void *cf, void *aux); +#endif + +USB_DECLARE_DRIVER(uhidev); + +USB_MATCH(uhidev) +{ + USB_MATCH_START(uhidev, uaa); + usb_interface_descriptor_t *id; + + if (uaa->iface == NULL) + return (UMATCH_NONE); + id = usbd_get_interface_descriptor(uaa->iface); + if (id == NULL || id->bInterfaceClass != UICLASS_HID) + return (UMATCH_NONE); + if (uaa->matchlvl) + return (uaa->matchlvl); + return (UMATCH_IFACECLASS_GENERIC); +} + +int repproto = 1; + +USB_ATTACH(uhidev) +{ + USB_ATTACH_START(uhidev, sc, uaa); + usbd_interface_handle iface = uaa->iface; + usb_interface_descriptor_t *id; + usb_endpoint_descriptor_t *ed; + struct uhidev_attach_arg uha; + struct uhidev *dev; + int size, nrepid, repid, repsz; + int repsizes[256]; + void *desc; + usbd_status err; + char devinfo[1024]; + + sc->sc_udev = uaa->device; + sc->sc_iface = iface; + id = usbd_get_interface_descriptor(iface); + usbd_devinfo(uaa->device, 0, devinfo); + USB_ATTACH_SETUP; + printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), + devinfo, id->bInterfaceClass, id->bInterfaceSubClass); + + (void)usbd_set_idle(iface, 0, 0); +#if 0 + + qflags = usbd_get_quirks(sc->sc_udev)->uq_flags; + if ((qflags & UQ_NO_SET_PROTO) == 0 && + id->bInterfaceSubClass != UISUBCLASS_BOOT) + (void)usbd_set_protocol(iface, 1); +#endif + + ed = usbd_interface2endpoint_descriptor(iface, 0); + if (ed == NULL) { + printf("%s: could not read endpoint descriptor\n", + USBDEVNAME(sc->sc_dev)); + sc->sc_dying = 1; + USB_ATTACH_ERROR_RETURN; + } + + DPRINTFN(10,("uhidev_attach: bLength=%d bDescriptorType=%d " + "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" + " bInterval=%d\n", + ed->bLength, ed->bDescriptorType, + ed->bEndpointAddress & UE_ADDR, + UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", + ed->bmAttributes & UE_XFERTYPE, + UGETW(ed->wMaxPacketSize), ed->bInterval)); + + if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || + (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { + printf("%s: unexpected endpoint\n", USBDEVNAME(sc->sc_dev)); + sc->sc_dying = 1; + USB_ATTACH_ERROR_RETURN; + } + + sc->sc_ep_addr = ed->bEndpointAddress; + + /* XXX need to extend this */ + if (uaa->vendor == USB_VENDOR_WACOM && + uaa->product == USB_PRODUCT_WACOM_GRAPHIRE /* && + uaa->revision == 0x???? */) { /* XXX should use revision */ + /* The report descriptor for the Wacom Graphire is broken. */ + size = sizeof uhid_graphire_report_descr; + desc = malloc(size, M_USBDEV, M_NOWAIT); + if (desc == NULL) + err = USBD_NOMEM; + else { + err = USBD_NORMAL_COMPLETION; + memcpy(desc, uhid_graphire_report_descr, size); + } + } else { + desc = NULL; + err = usbd_read_report_desc(uaa->iface, &desc, &size, M_USBDEV); + } + if (err) { + printf("%s: no report descriptor\n", USBDEVNAME(sc->sc_dev)); + sc->sc_dying = 1; + USB_ATTACH_ERROR_RETURN; + } + + sc->sc_repdesc = desc; + sc->sc_repdesc_size = size; + + uha.uaa = uaa; + nrepid = uhidev_maxrepid(desc, size); + if (nrepid < 0) + USB_ATTACH_SUCCESS_RETURN; + if (nrepid > 0) + printf("%s: %d report ids\n", USBDEVNAME(sc->sc_dev), nrepid); + nrepid++; + sc->sc_subdevs = malloc(nrepid * sizeof(device_ptr_t), + M_USBDEV, M_NOWAIT); + bzero(sc->sc_subdevs, nrepid * sizeof(device_ptr_t)); + if (sc->sc_subdevs == NULL) { + printf("%s: no memory\n", USBDEVNAME(sc->sc_dev)); + USB_ATTACH_ERROR_RETURN; + } + sc->sc_nrepid = nrepid; + sc->sc_isize = 0; + + usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + + for (repid = 0; repid < nrepid; repid++) { + repsz = hid_report_size(desc, size, hid_input, repid); + DPRINTF(("uhidev_match: repid=%d, repsz=%d\n", repid, repsz)); + repsizes[repid] = repsz; + if (repsz > 0) { + if (repsz > sc->sc_isize) + sc->sc_isize = repsz; + } + } + sc->sc_isize += nrepid != 1; /* space for report ID */ + DPRINTF(("uhidev_attach: isize=%d\n", sc->sc_isize)); + + uha.parent = sc; + for (repid = 0; repid < nrepid; repid++) { + DPRINTF(("uhidev_match: try repid=%d\n", repid)); + if (hid_report_size(desc, size, hid_input, repid) == 0 && + hid_report_size(desc, size, hid_output, repid) == 0 && + hid_report_size(desc, size, hid_feature, repid) == 0) { + ; /* already NULL in sc->sc_subdevs[repid] */ + } else { + uha.reportid = repid; + dev = (struct uhidev *)config_found_sm(self, &uha, + uhidevprint, uhidevsubmatch); + sc->sc_subdevs[repid] = dev; + if (dev != NULL) { + dev->sc_in_rep_size = repsizes[repid]; +#ifdef DIAGNOSTIC + DPRINTF(("uhidev_match: repid=%d dev=%p\n", + repid, dev)); + if (dev->sc_intr == NULL) { + printf("%s: sc_intr == NULL\n", + USBDEVNAME(sc->sc_dev)); + USB_ATTACH_ERROR_RETURN; + } +#endif + } + } + } + + USB_ATTACH_SUCCESS_RETURN; +} + +int +uhidev_maxrepid(void *buf, int len) +{ + struct hid_data *d; + struct hid_item h; + int maxid; + + maxid = -1; + h.report_ID = 0; + for (d = hid_start_parse(buf, len, hid_none); hid_get_item(d, &h); ) + if (h.report_ID > maxid) + maxid = h.report_ID; + hid_end_parse(d); + return (maxid); +} + +int +uhidevprint(void *aux, const char *pnp) +{ + struct uhidev_attach_arg *uha = aux; + + if (pnp) + printf("uhid at %s", pnp); + if (uha->reportid != 0) + printf(" reportid %d", uha->reportid); + return (UNCONF); +} + +#if defined(__NetBSD__) +Static int uhidevsubmatch(struct device *parent, struct cfdata *cf, void *aux) +#else +Static int uhidevsubmatch(struct device *parent, void *match, void *aux) +#endif +{ + struct uhidev_attach_arg *uha = aux; +#if defined(__OpenBSD__) + struct cfdata *cf = match; +#endif + + if (cf->uhidevcf_reportid != UHIDEV_UNK_REPORTID && + cf->uhidevcf_reportid != uha->reportid) + return (0); + if (cf->uhidevcf_reportid == uha->reportid) + uha->matchlvl = UMATCH_VENDOR_PRODUCT; + else + uha->matchlvl = 0; + return ((*cf->cf_attach->ca_match)(parent, cf, aux)); +} + +int +uhidev_activate(device_ptr_t self, enum devact act) +{ + struct uhidev_softc *sc = (struct uhidev_softc *)self; + int i, rv; + + switch (act) { + case DVACT_ACTIVATE: + return (EOPNOTSUPP); + break; + + case DVACT_DEACTIVATE: + rv = 0; + for (i = 0; i < sc->sc_nrepid; i++) + if (sc->sc_subdevs[i] != NULL) + rv |= config_deactivate( + &sc->sc_subdevs[i]->sc_dev); + sc->sc_dying = 1; + break; + } + return (rv); +} + +USB_DETACH(uhidev) +{ + USB_DETACH_START(uhidev, sc); + int i, rv; + + DPRINTF(("uhidev_detach: sc=%p flags=%d\n", sc, flags)); + + sc->sc_dying = 1; + if (sc->sc_intrpipe != NULL) + usbd_abort_pipe(sc->sc_intrpipe); + + if (sc->sc_repdesc != NULL) + free(sc->sc_repdesc, M_USBDEV); + + rv = 0; + for (i = 0; i < sc->sc_nrepid; i++) { + if (sc->sc_subdevs[i] != NULL) { + rv |= config_detach(&sc->sc_subdevs[i]->sc_dev, flags); + sc->sc_subdevs[i] = NULL; + } + } + + usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, + USBDEV(sc->sc_dev)); + + return (rv); +} + +void +uhidev_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) +{ + struct uhidev_softc *sc = addr; + struct uhidev *scd; + u_char *p; + u_int rep; + u_int32_t cc; + + usbd_get_xfer_status(xfer, NULL, NULL, &cc, NULL); + +#ifdef UHIDEV_DEBUG + if (uhidevdebug > 5) { + u_int32_t i; + + DPRINTF(("uhidev_intr: status=%d cc=%d\n", status, cc)); + DPRINTF(("uhidev_intr: data =")); + for (i = 0; i < cc; i++) + DPRINTF((" %02x", sc->sc_ibuf[i])); + DPRINTF(("\n")); + } +#endif + + if (status == USBD_CANCELLED) + return; + + if (status != USBD_NORMAL_COMPLETION) { + DPRINTF(("%s: interrupt status=%d\n", USBDEVNAME(sc->sc_dev), + status)); + usbd_clear_endpoint_stall_async(sc->sc_intrpipe); + return; + } + + p = sc->sc_ibuf; + if (sc->sc_nrepid != 1) + rep = *p++, cc--; + else + rep = 0; + if (rep >= sc->sc_nrepid) { + printf("uhidev_intr: bad repid %d\n", rep); + return; + } + scd = sc->sc_subdevs[rep]; + DPRINTFN(5,("uhidev_intr: rep=%d, scd=%p state=0x%x\n", + rep, scd, scd ? scd->sc_state : 0)); + if (scd == NULL || !(scd->sc_state & UHIDEV_OPEN)) + return; +#ifdef DIAGNOSTIC + if (scd->sc_in_rep_size != cc) + printf("%s: bad input length %d != %d\n",USBDEVNAME(sc->sc_dev), + scd->sc_in_rep_size, cc); +#endif + scd->sc_intr(scd, p, cc); +} + +void +uhidev_get_report_desc(struct uhidev_softc *sc, void **desc, int *size) +{ + *desc = sc->sc_repdesc; + *size = sc->sc_repdesc_size; +} + +int +uhidev_open(struct uhidev *scd) +{ + struct uhidev_softc *sc = scd->sc_parent; + usbd_status err; + + DPRINTF(("uhidev_open: open pipe, state=%d refcnt=%d\n", + scd->sc_state, sc->sc_refcnt)); + + if (scd->sc_state & UHIDEV_OPEN) + return (EBUSY); + scd->sc_state |= UHIDEV_OPEN; + if (sc->sc_refcnt++) + return (0); + + if (sc->sc_isize == 0) + return (0); + + sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_WAITOK); + + /* Set up interrupt pipe. */ + DPRINTF(("uhidev_open: isize=%d, ep=0x%02x\n", sc->sc_isize, + sc->sc_ep_addr)); + err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, + USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, sc->sc_ibuf, + sc->sc_isize, uhidev_intr, USBD_DEFAULT_INTERVAL); + if (err) { + DPRINTF(("uhidopen: usbd_open_pipe_intr failed, " + "error=%d\n",err)); + free(sc->sc_ibuf, M_USBDEV); + scd->sc_state &= ~UHIDEV_OPEN; + sc->sc_refcnt = 0; + sc->sc_intrpipe = NULL; + return (EIO); + } + return (0); +} + +void +uhidev_close(struct uhidev *scd) +{ + struct uhidev_softc *sc = scd->sc_parent; + + if (!(scd->sc_state & UHIDEV_OPEN)) + return; + scd->sc_state &= ~UHIDEV_OPEN; + if (--sc->sc_refcnt) + return; + DPRINTF(("uhidev_close: close pipe\n")); + + /* Disable interrupts. */ + if (sc->sc_intrpipe != NULL) { + usbd_abort_pipe(sc->sc_intrpipe); + usbd_close_pipe(sc->sc_intrpipe); + sc->sc_intrpipe = NULL; + } + + if (sc->sc_ibuf != NULL) { + free(sc->sc_ibuf, M_USBDEV); + sc->sc_ibuf = NULL; + } +} + +usbd_status +uhidev_set_report(struct uhidev *scd, int type, void *data, int len) +{ + /* XXX */ + char buf[100]; + if (scd->sc_report_id) { + buf[0] = scd->sc_report_id; + memcpy(buf+1, data, len); + len++; + data = buf; + } + + return usbd_set_report(scd->sc_parent->sc_iface, type, + scd->sc_report_id, data, len); +} + +void +uhidev_set_report_async(struct uhidev *scd, int type, void *data, int len) +{ + /* XXX */ + char buf[100]; + if (scd->sc_report_id) { + buf[0] = scd->sc_report_id; + memcpy(buf+1, data, len); + len++; + data = buf; + } + + usbd_set_report_async(scd->sc_parent->sc_iface, type, + scd->sc_report_id, data, len); +} + +usbd_status +uhidev_get_report(struct uhidev *scd, int type, void *data, int len) +{ + return usbd_get_report(scd->sc_parent->sc_iface, type, + scd->sc_report_id, data, len); +} diff --git a/sys/dev/usb/uhidev.h b/sys/dev/usb/uhidev.h new file mode 100644 index 00000000000..360eae75784 --- /dev/null +++ b/sys/dev/usb/uhidev.h @@ -0,0 +1,91 @@ +/* $OpenBSD: uhidev.h,v 1.3 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: uhidev.h,v 1.2 2001/12/29 18:56:52 augustss Exp $ */ + +/* + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Lennart Augustsson (lennart@augustsson.net) at + * Carlstedt Research & Technology. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(__NetBSD__) +#include "locators.h" +#endif + +#define uhidevcf_reportid cf_loc[UHIDBUSCF_REPORTID] +#define UHIDEV_UNK_REPORTID UHIDBUSCF_REPORTID_DEFAULT + +struct uhidev_softc { + USBBASEDEVICE sc_dev; /* base device */ + usbd_device_handle sc_udev; + usbd_interface_handle sc_iface; /* interface */ + usbd_pipe_handle sc_intrpipe; /* interrupt pipe */ + int sc_ep_addr; + + u_char *sc_ibuf; + u_int sc_isize; + + void *sc_repdesc; + int sc_repdesc_size; + + u_int sc_nrepid; + struct uhidev **sc_subdevs; + + int sc_refcnt; + u_char sc_dying; +}; + +struct uhidev { + USBBASEDEVICE sc_dev; /* base device */ + struct uhidev_softc *sc_parent; + uByte sc_report_id; + u_int8_t sc_state; + int sc_in_rep_size; +#define UHIDEV_OPEN 0x01 /* device is open */ + void (*sc_intr)(struct uhidev *, void *, u_int); +}; + +struct uhidev_attach_arg { + struct usb_attach_arg *uaa; + struct uhidev_softc *parent; + int reportid; + int reportsize; + int matchlvl; +}; + +void uhidev_get_report_desc(struct uhidev_softc *, void **, int *); +int uhidev_open(struct uhidev *); +void uhidev_close(struct uhidev *); +usbd_status uhidev_set_report(struct uhidev *scd, int type, void *data,int len); +void uhidev_set_report_async(struct uhidev *scd, int type, void *data, int len); +usbd_status uhidev_get_report(struct uhidev *scd, int type, void *data,int len); diff --git a/sys/dev/usb/ukbd.c b/sys/dev/usb/ukbd.c index 0843bd9392d..3c8c6ca9dec 100644 --- a/sys/dev/usb/ukbd.c +++ b/sys/dev/usb/ukbd.c @@ -1,5 +1,5 @@ -/* $OpenBSD: ukbd.c,v 1.13 2002/05/07 18:29:18 nate Exp $ */ -/* $NetBSD: ukbd.c,v 1.69 2001/10/24 21:02:18 augustss Exp $ */ +/* $OpenBSD: ukbd.c,v 1.14 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: ukbd.c,v 1.79 2001/12/30 19:37:43 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -66,6 +66,7 @@ #include <dev/usb/usbdi_util.h> #include <dev/usb/usbdevs.h> #include <dev/usb/usb_quirks.h> +#include <dev/usb/uhidev.h> #include <dev/usb/hid.h> #include <dev/usb/ukbdvar.h> @@ -88,119 +89,96 @@ int ukbddebug = 0; #define DPRINTFN(n,x) #endif -#define NKEYCODE 6 - -#define NUM_LOCK 0x01 -#define CAPS_LOCK 0x02 -#define SCROLL_LOCK 0x04 +#define MAXKEYCODE 6 +#define MAXMOD 8 /* max 32 */ struct ukbd_data { - u_int8_t modifiers; -#define MOD_CONTROL_L 0x01 -#define MOD_CONTROL_R 0x10 -#define MOD_SHIFT_L 0x02 -#define MOD_SHIFT_R 0x20 -#define MOD_ALT_L 0x04 -#define MOD_ALT_R 0x40 -#define MOD_WIN_L 0x08 -#define MOD_WIN_R 0x80 - u_int8_t reserved; - u_int8_t keycode[NKEYCODE]; + u_int32_t modifiers; + u_int8_t keycode[MAXKEYCODE]; }; #define PRESS 0x000 #define RELEASE 0x100 #define CODEMASK 0x0ff -/* Translate USB bitmap to USB keycode. */ -#define NMOD 8 -Static const struct { - int mask, key; -} ukbd_mods[NMOD] = { - { MOD_CONTROL_L, 224 }, - { MOD_CONTROL_R, 228 }, - { MOD_SHIFT_L, 225 }, - { MOD_SHIFT_R, 229 }, - { MOD_ALT_L, 226 }, - { MOD_ALT_R, 230 }, - { MOD_WIN_L, 227 }, - { MOD_WIN_R, 231 }, -}; - #if defined(WSDISPLAY_COMPAT_RAWKBD) #define NN 0 /* no translation */ /* * Translate USB keycodes to US keyboard XT scancodes. - * Scancodes >= 128 represent EXTENDED keycodes. + * Scancodes >= 0x80 represent EXTENDED keycodes. + * + * See http://www.microsoft.com/HWDEV/TECH/input/Scancode.asp */ Static const u_int8_t ukbd_trtab[256] = { - NN, NN, NN, NN, 30, 48, 46, 32, /* 00 - 07 */ - 18, 33, 34, 35, 23, 36, 37, 38, /* 08 - 0F */ - 50, 49, 24, 25, 16, 19, 31, 20, /* 10 - 17 */ - 22, 47, 17, 45, 21, 44, 2, 3, /* 18 - 1F */ - 4, 5, 6, 7, 8, 9, 10, 11, /* 20 - 27 */ - 28, 1, 14, 15, 57, 12, 13, 26, /* 28 - 2F */ - 27, 43, 43, 39, 40, 41, 51, 52, /* 30 - 37 */ - 53, 58, 59, 60, 61, 62, 63, 64, /* 38 - 3F */ - 65, 66, 67, 68, 87, 88, 170, 70, /* 40 - 47 */ - 127, 210, 199, 201, 211, 207, 209, 205, /* 48 - 4F */ - 203, 208, 200, 69, 181, 55, 74, 78, /* 50 - 57 */ - 156, 79, 80, 81, 75, 76, 77, 71, /* 58 - 5F */ - 72, 73, 82, 83, 86, 221, NN, NN, /* 60 - 67 */ - NN, NN, NN, 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, NN, NN, NN, /* 80 - 87 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 88 - 8F */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 90 - 97 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9F */ - NN, NN, NN, NN, NN, NN, NN, NN, /* A0 - A7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* A8 - AF */ - NN, NN, NN, NN, NN, NN, NN, NN, /* B0 - B7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* B8 - BF */ - NN, NN, NN, NN, NN, NN, NN, NN, /* C0 - C7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* C8 - CF */ - NN, NN, NN, NN, NN, NN, NN, NN, /* D0 - D7 */ - NN, NN, NN, NN, NN, NN, NN, NN, /* D8 - DF */ - 29, 42, 56, 219, 157, 54, 184,220, /* 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 */ + 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 /* defined(WSDISPLAY_COMPAT_RAWKBD) */ #define KEY_ERROR 0x01 -#define MAXKEYS (NMOD+2*NKEYCODE) +#define MAXKEYS (MAXMOD+2*MAXKEYCODE) struct ukbd_softc { - USBBASEDEVICE sc_dev; /* base device */ - usbd_device_handle sc_udev; - usbd_interface_handle sc_iface; /* interface */ - usbd_pipe_handle sc_intrpipe; /* interrupt pipe */ - int sc_ep_addr; + 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 */ + usb_callout_t 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; -#if defined(__OpenBSD__) - struct timeout sc_delay; /* for quirk handling */ - struct timeout sc_rawrepeat_ch; -#else - struct callout sc_delay; /* for quirk handling */ - struct callout sc_rawrepeat_ch; -#endif + usb_callout_t sc_rawrepeat_ch; -#if defined(__NetBSD__) || defined(__OpenBSD__) struct device *sc_wskbddev; #if defined(WSDISPLAY_COMPAT_RAWKBD) #define REP_DELAY1 400 @@ -213,7 +191,6 @@ struct ukbd_softc { int sc_polling; int sc_npollchar; u_int16_t sc_pollchars[MAXKEYS]; -#endif u_char sc_dying; }; @@ -254,22 +231,21 @@ Static int ukbd_is_console; Static void ukbd_cngetc(void *, u_int *, int *); Static void ukbd_cnpollc(void *, int); -#if defined(__NetBSD__) || defined(__OpenBSD__) const struct wskbd_consops ukbd_consops = { ukbd_cngetc, ukbd_cnpollc, }; -#endif -Static void ukbd_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); +Static const char *ukbd_parse_desc(struct ukbd_softc *sc); + +Static void ukbd_intr(struct uhidev *addr, void *ibuf, u_int len); Static void ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud); Static void ukbd_delayed_decode(void *addr); Static int ukbd_enable(void *, int); Static void ukbd_set_leds(void *, int); -#if defined(__NetBSD__) || defined(__OpenBSD__) -Static int ukbd_ioctl(void *, u_long, caddr_t, int, struct proc *); +Static int ukbd_ioctl(void *, u_long, caddr_t, int, usb_proc_ptr ); #ifdef WSDISPLAY_COMPAT_RAWKBD Static void ukbd_rawrepeat(void *v); #endif @@ -290,90 +266,53 @@ const struct wskbd_mapdata ukbd_keymapdata = { KB_US, #endif }; -#endif USB_DECLARE_DRIVER(ukbd); USB_MATCH(ukbd) { USB_MATCH_START(ukbd, uaa); - usb_interface_descriptor_t *id; + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; + int size; + void *desc; - /* Check that this is a keyboard that speaks the boot protocol. */ - if (uaa->iface == NULL) - return (UMATCH_NONE); - id = usbd_get_interface_descriptor(uaa->iface); - if (id == NULL || - id->bInterfaceClass != UICLASS_HID || - id->bInterfaceSubClass != UISUBCLASS_BOOT || - id->bInterfaceProtocol != UIPROTO_BOOT_KEYBOARD) + uhidev_get_report_desc(uha->parent, &desc, &size); + if (!hid_is_collection(desc, size, uha->reportid, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD))) return (UMATCH_NONE); - return (UMATCH_IFACECLASS_IFACESUBCLASS_IFACEPROTO); + + return (UMATCH_IFACECLASS); } USB_ATTACH(ukbd) { USB_ATTACH_START(ukbd, sc, uaa); - usbd_interface_handle iface = uaa->iface; - usb_interface_descriptor_t *id; - usb_endpoint_descriptor_t *ed; - usbd_status err; + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; u_int32_t qflags; - char devinfo[1024]; -#if defined(__NetBSD__) || defined(__OpenBSD__) + const char *parseerr; struct wskbddev_attach_args a; -#else - int i; -#endif - sc->sc_udev = uaa->device; - sc->sc_iface = iface; - id = usbd_get_interface_descriptor(iface); - usbd_devinfo(uaa->device, 0, devinfo); - USB_ATTACH_SETUP; - printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), - devinfo, id->bInterfaceClass, id->bInterfaceSubClass); - - ed = usbd_interface2endpoint_descriptor(iface, 0); - if (ed == NULL) { - printf("%s: could not read endpoint descriptor\n", - USBDEVNAME(sc->sc_dev)); + 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); USB_ATTACH_ERROR_RETURN; } + +#ifdef DIAGNOSTIC + printf(": %d modifier keys, %d key codes", sc->sc_nmod, + sc->sc_nkeycode); +#endif + printf("\n"); - DPRINTFN(10,("ukbd_attach: bLength=%d bDescriptorType=%d " - "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" - " bInterval=%d\n", - ed->bLength, ed->bDescriptorType, - ed->bEndpointAddress & UE_ADDR, - UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", - ed->bmAttributes & UE_XFERTYPE, - UGETW(ed->wMaxPacketSize), ed->bInterval)); - - if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || - (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { - printf("%s: unexpected endpoint\n", - USBDEVNAME(sc->sc_dev)); - USB_ATTACH_ERROR_RETURN; - } - qflags = usbd_get_quirks(uaa->device)->uq_flags; - if ((qflags & UQ_NO_SET_PROTO) == 0) { - err = usbd_set_protocol(iface, 0); - DPRINTFN(5, ("ukbd_attach: protocol set\n")); - if (err) { - printf("%s: set protocol failed\n", - USBDEVNAME(sc->sc_dev)); - USB_ATTACH_ERROR_RETURN; - } - } + qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags; sc->sc_debounce = (qflags & UQ_SPUR_BUT_UP) != 0; - /* Ignore if SETIDLE fails since it is not crucial. */ - (void)usbd_set_idle(iface, 0, 0); - - sc->sc_ep_addr = ed->bEndpointAddress; - /* * Remember if we're the console keyboard. * @@ -398,26 +337,14 @@ USB_ATTACH(ukbd) a.accessops = &ukbd_accessops; a.accesscookie = sc; -#if defined(__OpenBSD__) -#ifdef WSDISPLAY_COMPAT_RAWKBD - timeout_set(&sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc); -#endif - timeout_set(&sc->sc_delay, ukbd_delayed_decode, sc); -#endif - -#if defined(__NetBSD__) - callout_init(&sc->sc_rawrepeat_ch); - callout_init(&sc->sc_delay); -#endif + usb_callout_init(sc->sc_rawrepeat_ch); + usb_callout_init(sc->sc_delay); /* 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(uaa->device, 400); + usbd_delay_ms(uha->parent->sc_udev, 400); ukbd_set_leds(sc, 0); - usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, - USBDEV(sc->sc_dev)); - sc->sc_wskbddev = config_found(self, &a, wskbddevprint); USB_ATTACH_SUCCESS_RETURN; @@ -427,38 +354,27 @@ int ukbd_enable(void *v, int on) { struct ukbd_softc *sc = v; - usbd_status err; if (on && sc->sc_dying) return (EIO); /* Should only be called to change state */ if (sc->sc_enabled == on) { -#ifdef UKBD_DEBUG +#ifdef DIAGNOSTIC printf("ukbd_enable: %s: bad call on=%d\n", - USBDEVNAME(sc->sc_dev), on); + USBDEVNAME(sc->sc_hdev.sc_dev), on); #endif return (EBUSY); } DPRINTF(("ukbd_enable: sc=%p on=%d\n", sc, on)); + sc->sc_enabled = on; if (on) { - /* Set up interrupt pipe. */ - err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, - USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, - &sc->sc_ndata, sizeof(sc->sc_ndata), ukbd_intr, - USBD_DEFAULT_INTERVAL); - if (err) - return (EIO); + return (uhidev_open(&sc->sc_hdev)); } else { - /* Disable interrupts. */ - usbd_abort_pipe(sc->sc_intrpipe); - usbd_close_pipe(sc->sc_intrpipe); - sc->sc_intrpipe = NULL; + uhidev_close(&sc->sc_hdev); + return (0); } - sc->sc_enabled = on; - - return (0); } int @@ -507,7 +423,8 @@ USB_DETACH(ukbd) * XXX Should notify some other keyboard that it can be * XXX console, if there are any other keyboards. */ - printf("%s: was console keyboard\n", USBDEVNAME(sc->sc_dev)); + printf("%s: was console keyboard\n", + USBDEVNAME(sc->sc_hdev.sc_dev)); wskbd_cndetach(); ukbd_is_console = 1; #endif @@ -517,37 +434,34 @@ USB_DETACH(ukbd) rv = config_detach(sc->sc_wskbddev, flags); /* The console keyboard does not get a disable call, so check pipe. */ - if (sc->sc_intrpipe != NULL) { - usbd_abort_pipe(sc->sc_intrpipe); - usbd_close_pipe(sc->sc_intrpipe); - sc->sc_intrpipe = NULL; - } - - usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, - USBDEV(sc->sc_dev)); + if (sc->sc_hdev.sc_state & UHIDEV_OPEN) + uhidev_close(&sc->sc_hdev); return (rv); } void -ukbd_intr(xfer, addr, status) - usbd_xfer_handle xfer; - usbd_private_handle addr; - usbd_status status; +ukbd_intr(struct uhidev *addr, void *ibuf, u_int len) { - struct ukbd_softc *sc = addr; + struct ukbd_softc *sc = (struct ukbd_softc *)addr; struct ukbd_data *ud = &sc->sc_ndata; + int i; - DPRINTFN(5, ("ukbd_intr: status=%d\n", status)); - if (status == USBD_CANCELLED) - return; - - if (status) { - DPRINTF(("ukbd_intr: status=%d\n", status)); - if (status == USBD_STALLED) - usbd_clear_endpoint_stall_async(sc->sc_intrpipe); - return; +#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 + + 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) { /* @@ -557,12 +471,8 @@ ukbd_intr(xfer, addr, status) * We avoid this bug by holding off decoding for 20 ms. */ sc->sc_data = *ud; -#if defined(__OpenBSD__) - timeout_add(&sc->sc_delay, hz / 50); -#else - callout_reset(&sc->sc_delay, hz / 50, ukbd_delayed_decode, sc); -#endif -#if DDB + usb_callout(sc->sc_delay, hz / 50, ukbd_delayed_decode, sc); +#ifdef DDB } else if (sc->sc_console_keyboard && !sc->sc_polling) { /* * For the console keyboard we can't deliver CTL-ALT-ESC @@ -571,11 +481,7 @@ ukbd_intr(xfer, addr, status) * loses bigtime. */ sc->sc_data = *ud; -#if defined(__OpenBSD__) - timeout_add(&sc->sc_delay, 1); /* NOT an immediate timeout */ -#else - callout_reset(&sc->sc_delay, 0, ukbd_delayed_decode, sc); -#endif + usb_callout(sc->sc_delay, 1, ukbd_delayed_decode, sc); #endif } else { ukbd_decode(sc, ud); @@ -607,7 +513,7 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) */ if (ukbdtrace) { struct ukbdtraceinfo *p = &ukbdtracedata[ukbdtraceindex]; - p->unit = sc->sc_dev.dv_unit; + p->unit = sc->sc_hdev.sc_dev.dv_unit; microtime(&p->tv); p->ud = *ud; if (++ukbdtraceindex >= UKBDTRACESIZE) @@ -632,19 +538,19 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) mod = ud->modifiers; omod = sc->sc_odata.modifiers; if (mod != omod) - for (i = 0; i < NMOD; i++) - if (( mod & ukbd_mods[i].mask) != - (omod & ukbd_mods[i].mask)) - ADDKEY(ukbd_mods[i].key | - (mod & ukbd_mods[i].mask + 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, NKEYCODE) != 0) { + if (memcmp(ud->keycode, sc->sc_odata.keycode, sc->sc_nkeycode) != 0) { /* Check for released keys. */ - for (i = 0; i < NKEYCODE; i++) { + for (i = 0; i < sc->sc_nkeycode; i++) { key = sc->sc_odata.keycode[i]; if (key == 0) continue; - for (j = 0; j < NKEYCODE; j++) + 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)); @@ -654,11 +560,11 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) } /* Check for pressed keys. */ - for (i = 0; i < NKEYCODE; i++) { + for (i = 0; i < sc->sc_nkeycode; i++) { key = ud->keycode[i]; if (key == 0) continue; - for (j = 0; j < NKEYCODE; j++) + 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)); @@ -680,7 +586,7 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) } #ifdef WSDISPLAY_COMPAT_RAWKBD if (sc->sc_rawkbd) { - char cbuf[MAXKEYS * 2]; + u_char cbuf[MAXKEYS * 2]; int c; int npress; @@ -708,19 +614,11 @@ ukbd_decode(struct ukbd_softc *sc, struct ukbd_data *ud) s = spltty(); wskbd_rawinput(sc->sc_wskbddev, cbuf, j); splx(s); -#if defined(__OpenBSD__) - timeout_del(&sc->sc_rawrepeat_ch); -#else - callout_stop(&sc->sc_rawrepeat_ch); -#endif + usb_uncallout(sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc); if (npress != 0) { sc->sc_nrep = npress; -#if defined(__OpenBSD__) - timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAY1/1000); -#else - callout_reset(&sc->sc_rawrepeat_ch, + usb_callout(sc->sc_rawrepeat_ch, hz * REP_DELAY1 / 1000, ukbd_rawrepeat, sc); -#endif } return; } @@ -742,21 +640,24 @@ ukbd_set_leds(void *v, int leds) struct ukbd_softc *sc = v; u_int8_t res; - DPRINTF(("ukbd_set_leds: sc=%p leds=%d\n", sc, leds)); + 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; - if (leds & WSKBD_LED_SCROLL) - res |= SCROLL_LOCK; - if (leds & WSKBD_LED_NUM) - res |= NUM_LOCK; - if (leds & WSKBD_LED_CAPS) - res |= CAPS_LOCK; - res |= leds & 0xf8; - usbd_set_report_async(sc->sc_iface, UHID_OUTPUT_REPORT, 0, &res, 1); + /* 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); } #ifdef WSDISPLAY_COMPAT_RAWKBD @@ -769,17 +670,13 @@ ukbd_rawrepeat(void *v) s = spltty(); wskbd_rawinput(sc->sc_wskbddev, sc->sc_rep, sc->sc_nrep); splx(s); -#if defined(__OpenBSD__) - timeout_add(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000); -#else - callout_reset(&sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000, + usb_callout(sc->sc_rawrepeat_ch, hz * REP_DELAYN / 1000, ukbd_rawrepeat, sc); -#endif } #endif int -ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) +ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, usb_proc_ptr p) { struct ukbd_softc *sc = v; @@ -797,17 +694,19 @@ ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) case WSKBDIO_SETMODE: DPRINTF(("ukbd_ioctl: set raw = %d\n", *(int *)data)); sc->sc_rawkbd = *(int *)data == WSKBD_RAW; -#if defined(__OpenBSD__) - timeout_del(&sc->sc_rawrepeat_ch); -#else - callout_stop(&sc->sc_rawrepeat_ch); -#endif + usb_uncallout(sc->sc_rawrepeat_ch, ukbd_rawrepeat, sc); return (0); #endif } return (-1); } +/* + * This is a hack to work around some broken ports that don't call + * cnpollc() before cngetc(). + */ +static int pollenter, warned; + /* Console interface. */ void ukbd_cngetc(void *v, u_int *type, int *data) @@ -815,12 +714,25 @@ ukbd_cngetc(void *v, u_int *type, int *data) struct ukbd_softc *sc = v; int s; int c; + int broken; + + if (pollenter == 0) { + if (!warned) { + printf("\n" +"This port is broken, it does not call cnpollc() before calling cngetc().\n" +"This should be fixed, but it will work anyway (for now).\n"); + warned = 1; + } + broken = 1; + ukbd_cnpollc(v, 1); + } else + broken = 0; DPRINTFN(0,("ukbd_cngetc: enter\n")); s = splusb(); sc->sc_polling = 1; while(sc->sc_npollchar <= 0) - usbd_dopoll(sc->sc_iface); + usbd_dopoll(sc->sc_hdev.sc_parent->sc_iface); sc->sc_polling = 0; c = sc->sc_pollchars[0]; sc->sc_npollchar--; @@ -830,6 +742,8 @@ ukbd_cngetc(void *v, u_int *type, int *data) *data = c & CODEMASK; splx(s); DPRINTFN(0,("ukbd_cngetc: return 0x%02x\n", c)); + if (broken) + ukbd_cnpollc(v, 0); } void @@ -840,7 +754,8 @@ ukbd_cnpollc(void *v, int on) DPRINTFN(2,("ukbd_cnpollc: sc=%p on=%d\n", v, on)); - (void)usbd_interface2device_handle(sc->sc_iface,&dev); + usbd_interface2device_handle(sc->sc_hdev.sc_parent->sc_iface, &dev); + if (on) pollenter++; else pollenter--; usbd_set_polling(dev, on); } @@ -856,3 +771,64 @@ ukbd_cnattach(void) ukbd_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/ums.c b/sys/dev/usb/ums.c index 8bd88b43c81..324e5119a2c 100644 --- a/sys/dev/usb/ums.c +++ b/sys/dev/usb/ums.c @@ -1,5 +1,5 @@ -/* $OpenBSD: ums.c,v 1.8 2002/05/07 18:29:18 nate Exp $ */ -/* $NetBSD: ums.c,v 1.49 2001/10/26 17:58:21 augustss Exp $ */ +/* $OpenBSD: ums.c,v 1.9 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: ums.c,v 1.55 2001/12/31 12:15:22 augustss Exp $ */ /* * Copyright (c) 1998 The NetBSD Foundation, Inc. @@ -42,8 +42,6 @@ * HID spec: http://www.usb.org/developers/data/devclass/hid1_1.pdf */ -/* XXX complete SPUR_UP change */ - #include <sys/param.h> #include <sys/systm.h> #include <sys/kernel.h> @@ -64,6 +62,7 @@ #include <dev/usb/usbdi_util.h> #include <dev/usb/usbdevs.h> #include <dev/usb/usb_quirks.h> +#include <dev/usb/uhidev.h> #include <dev/usb/hid.h> #include <dev/wscons/wsconsio.h> @@ -87,18 +86,13 @@ int umsdebug = 0; #define PS2MBUTMASK x04 #define PS2BUTMASK 0x0f +#define MAX_BUTTONS 7 /* must not exceed size of sc_buttons */ + struct ums_softc { - USBBASEDEVICE sc_dev; /* base device */ - usbd_device_handle sc_udev; - usbd_interface_handle sc_iface; /* interface */ - usbd_pipe_handle sc_intrpipe; /* interrupt pipe */ - int sc_ep_addr; - - u_char *sc_ibuf; - u_int8_t sc_iid; - int sc_isize; + struct uhidev sc_hdev; + struct hid_location sc_loc_x, sc_loc_y, sc_loc_z; - struct hid_location *sc_loc_btn; + struct hid_location sc_loc_btn[MAX_BUTTONS]; int sc_enabled; @@ -108,7 +102,6 @@ struct ums_softc { #define UMS_REVZ 0x04 /* Z-axis is reversed */ int nbuttons; -#define MAX_BUTTONS 31 /* chosen because sc_buttons is u_int32_t */ u_int32_t sc_buttons; /* mouse button status */ struct device *sc_wsmousedev; @@ -119,11 +112,11 @@ struct ums_softc { #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE) #define MOUSE_FLAGS (HIO_RELATIVE) -Static void ums_intr(usbd_xfer_handle, usbd_private_handle, usbd_status); +Static void ums_intr(struct uhidev *addr, void *ibuf, u_int len); Static int ums_enable(void *); Static void ums_disable(void *); -Static int ums_ioctl(void *, u_long, caddr_t, int, struct proc *); +Static int ums_ioctl(void *, u_long, caddr_t, int, usb_proc_ptr); const struct wsmouse_accessops ums_accessops = { ums_enable, @@ -136,115 +129,72 @@ USB_DECLARE_DRIVER(ums); USB_MATCH(ums) { USB_MATCH_START(ums, uaa); - usb_interface_descriptor_t *id; - int size, ret; + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; + int size; void *desc; - usbd_status err; - if (uaa->iface == NULL) - return (UMATCH_NONE); - id = usbd_get_interface_descriptor(uaa->iface); - if (id == NULL || id->bInterfaceClass != UICLASS_HID) + uhidev_get_report_desc(uha->parent, &desc, &size); + if (!hid_is_collection(desc, size, uha->reportid, + HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) return (UMATCH_NONE); - err = usbd_read_report_desc(uaa->iface, &desc, &size, M_TEMP); - if (err) - return (UMATCH_NONE); - - if (hid_is_collection(desc, size, - HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) - ret = UMATCH_IFACECLASS; - else - ret = UMATCH_NONE; - - free(desc, M_TEMP); - return (ret); + return (UMATCH_IFACECLASS); } USB_ATTACH(ums) { USB_ATTACH_START(ums, sc, uaa); - usbd_interface_handle iface = uaa->iface; - usb_interface_descriptor_t *id; - usb_endpoint_descriptor_t *ed; + struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa; struct wsmousedev_attach_args a; int size; void *desc; - usbd_status err; - char devinfo[1024]; u_int32_t flags, quirks; int i, wheel; struct hid_location loc_btn; - - sc->sc_udev = uaa->device; - sc->sc_iface = iface; - id = usbd_get_interface_descriptor(iface); - usbd_devinfo(uaa->device, 0, devinfo); - USB_ATTACH_SETUP; - printf("%s: %s, iclass %d/%d\n", USBDEVNAME(sc->sc_dev), - devinfo, id->bInterfaceClass, id->bInterfaceSubClass); - ed = usbd_interface2endpoint_descriptor(iface, 0); - if (ed == NULL) { - printf("%s: could not read endpoint descriptor\n", - USBDEVNAME(sc->sc_dev)); - USB_ATTACH_ERROR_RETURN; - } - DPRINTFN(10,("ums_attach: bLength=%d bDescriptorType=%d " - "bEndpointAddress=%d-%s bmAttributes=%d wMaxPacketSize=%d" - " bInterval=%d\n", - ed->bLength, ed->bDescriptorType, - ed->bEndpointAddress & UE_ADDR, - UE_GET_DIR(ed->bEndpointAddress)==UE_DIR_IN? "in" : "out", - ed->bmAttributes & UE_XFERTYPE, - UGETW(ed->wMaxPacketSize), ed->bInterval)); - - if (UE_GET_DIR(ed->bEndpointAddress) != UE_DIR_IN || - (ed->bmAttributes & UE_XFERTYPE) != UE_INTERRUPT) { - printf("%s: unexpected endpoint\n", - USBDEVNAME(sc->sc_dev)); - USB_ATTACH_ERROR_RETURN; - } + 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(uaa->device)->uq_flags; + 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; - err = usbd_read_report_desc(uaa->iface, &desc, &size, M_TEMP); - if (err) - USB_ATTACH_ERROR_RETURN; + uhidev_get_report_desc(uha->parent, &desc, &size); if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), - hid_input, &sc->sc_loc_x, &flags)) { - printf("%s: mouse has no X report\n", USBDEVNAME(sc->sc_dev)); + uha->reportid, hid_input, &sc->sc_loc_x, &flags)) { + printf("\n%s: mouse has no X report\n", + USBDEVNAME(sc->sc_hdev.sc_dev)); USB_ATTACH_ERROR_RETURN; } if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { - printf("%s: X report 0x%04x not supported\n", - USBDEVNAME(sc->sc_dev), flags); + printf("\n%s: X report 0x%04x not supported\n", + USBDEVNAME(sc->sc_hdev.sc_dev), flags); USB_ATTACH_ERROR_RETURN; } if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), - hid_input, &sc->sc_loc_y, &flags)) { - printf("%s: mouse has no Y report\n", USBDEVNAME(sc->sc_dev)); + uha->reportid, hid_input, &sc->sc_loc_y, &flags)) { + printf("\n%s: mouse has no Y report\n", + USBDEVNAME(sc->sc_hdev.sc_dev)); USB_ATTACH_ERROR_RETURN; } if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { - printf("%s: Y report 0x%04x not supported\n", - USBDEVNAME(sc->sc_dev), flags); + printf("\n%s: Y report 0x%04x not supported\n", + USBDEVNAME(sc->sc_hdev.sc_dev), flags); USB_ATTACH_ERROR_RETURN; } /* Try to guess the Z activator: first check Z, then WHEEL. */ wheel = 0; if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), - hid_input, &sc->sc_loc_z, &flags) || + uha->reportid, hid_input, &sc->sc_loc_z, &flags) || (wheel = hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), - hid_input, &sc->sc_loc_z, &flags))) { + uha->reportid, hid_input, &sc->sc_loc_z, &flags))) { if ((flags & MOUSE_FLAGS_MASK) != MOUSE_FLAGS) { sc->sc_loc_z.size = 0; /* Bad Z coord, ignore it */ } else { @@ -258,34 +208,18 @@ USB_ATTACH(ums) /* figure out the number of buttons */ for (i = 1; i <= MAX_BUTTONS; i++) if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i), - hid_input, &loc_btn, 0)) + uha->reportid, hid_input, &loc_btn, 0)) break; sc->nbuttons = i - 1; - sc->sc_loc_btn = malloc(sizeof(struct hid_location) * sc->nbuttons, - M_USBDEV, M_NOWAIT); - if (!sc->sc_loc_btn) { - printf("%s: no memory\n", USBDEVNAME(sc->sc_dev)); - USB_ATTACH_ERROR_RETURN; - } - printf("%s: %d button%s%s\n", USBDEVNAME(sc->sc_dev), + printf(": %d button%s%s\n", sc->nbuttons, sc->nbuttons == 1 ? "" : "s", sc->flags & UMS_Z ? " and Z dir." : ""); for (i = 1; i <= sc->nbuttons; i++) hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i), - hid_input, &sc->sc_loc_btn[i-1], 0); - - sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid); - sc->sc_ibuf = malloc(sc->sc_isize, M_USBDEV, M_NOWAIT); - if (sc->sc_ibuf == NULL) { - printf("%s: no memory\n", USBDEVNAME(sc->sc_dev)); - free(sc->sc_loc_btn, M_USBDEV); - USB_ATTACH_ERROR_RETURN; - } - - sc->sc_ep_addr = ed->bEndpointAddress; - free(desc, M_TEMP); + uha->reportid, hid_input, + &sc->sc_loc_btn[i-1], 0); #ifdef USB_DEBUG DPRINTF(("ums_attach: sc=%p\n", sc)); @@ -300,15 +234,11 @@ USB_ATTACH(ums) DPRINTF(("ums_attach: B%d\t%d/%d\n", i, sc->sc_loc_btn[i-1].pos,sc->sc_loc_btn[i-1].size)); } - DPRINTF(("ums_attach: size=%d, id=%d\n", sc->sc_isize, sc->sc_iid)); #endif a.accessops = &ums_accessops; a.accesscookie = sc; - usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH, sc->sc_udev, - USBDEV(sc->sc_dev)); - sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint); USB_ATTACH_SUCCESS_RETURN; @@ -344,45 +274,21 @@ USB_DETACH(ums) /* 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); - if (rv == 0) { - free(sc->sc_loc_btn, M_USBDEV); - free(sc->sc_ibuf, M_USBDEV); - } - - usbd_add_drv_event(USB_EVENT_DRIVER_DETACH, sc->sc_udev, - USBDEV(sc->sc_dev)); return (rv); } void -ums_intr(usbd_xfer_handle xfer, usbd_private_handle addr, usbd_status status) +ums_intr(struct uhidev *addr, void *ibuf, u_int len) { - struct ums_softc *sc = addr; - u_char *ibuf; + struct ums_softc *sc = (struct ums_softc *)addr; int dx, dy, dz; u_int32_t buttons = 0; int i; int s; - DPRINTFN(5, ("ums_intr: sc=%p status=%d\n", sc, status)); - DPRINTFN(5, ("ums_intr: data = %02x %02x %02x\n", - sc->sc_ibuf[0], sc->sc_ibuf[1], sc->sc_ibuf[2])); - - if (status == USBD_CANCELLED) - return; - - if (status) { - DPRINTF(("ums_intr: status=%d\n", status)); - usbd_clear_endpoint_stall_async(sc->sc_intrpipe); - return; - } + DPRINTFN(5,("ums_intr: len=%d\n", len)); - ibuf = sc->sc_ibuf; - if (sc->sc_iid != 0) { - if (*ibuf++ != sc->sc_iid) - 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); @@ -410,8 +316,6 @@ ums_enable(void *v) { struct ums_softc *sc = v; - usbd_status err; - DPRINTFN(1,("ums_enable: sc=%p\n", sc)); if (sc->sc_dying) @@ -423,17 +327,7 @@ ums_enable(void *v) sc->sc_enabled = 1; sc->sc_buttons = 0; - /* Set up interrupt pipe. */ - err = usbd_open_pipe_intr(sc->sc_iface, sc->sc_ep_addr, - USBD_SHORT_XFER_OK, &sc->sc_intrpipe, sc, - sc->sc_ibuf, sc->sc_isize, ums_intr, USBD_DEFAULT_INTERVAL); - if (err) { - DPRINTF(("ums_enable: usbd_open_pipe_intr failed, error=%d\n", - err)); - sc->sc_enabled = 0; - return (EIO); - } - return (0); + return (uhidev_open(&sc->sc_hdev)); } Static void @@ -449,15 +343,12 @@ ums_disable(void *v) } #endif - /* Disable interrupts. */ - usbd_abort_pipe(sc->sc_intrpipe); - usbd_close_pipe(sc->sc_intrpipe); - sc->sc_enabled = 0; + return (uhidev_close(&sc->sc_hdev)); } Static int -ums_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) +ums_ioctl(void *v, u_long cmd, caddr_t data, int flag, usb_proc_ptr p) { switch (cmd) { diff --git a/sys/dev/usb/usb.h b/sys/dev/usb/usb.h index 89121f65dec..8defac116a4 100644 --- a/sys/dev/usb/usb.h +++ b/sys/dev/usb/usb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usb.h,v 1.17 2002/05/07 18:29:18 nate Exp $ */ +/* $OpenBSD: usb.h,v 1.18 2002/05/09 15:06:29 nate Exp $ */ /* $NetBSD: usb.h,v 1.52 2001/07/23 15:17:50 nathanw Exp $ */ /* $FreeBSD: src/sys/dev/usb/usb.h,v 1.14 1999/11/17 22:33:46 n_hibma Exp $ */ @@ -588,6 +588,7 @@ struct usb_event { #define USB_SET_IMMED _IOW ('U', 22, int) #define USB_GET_REPORT _IOWR('U', 23, struct usb_ctl_report) #define USB_SET_REPORT _IOW ('U', 24, struct usb_ctl_report) +#define USB_GET_REPORT_ID _IOR ('U', 25, int) /* Generic USB device */ #define USB_GET_CONFIG _IOR ('U', 100, int) diff --git a/sys/dev/usb/usb_port.h b/sys/dev/usb/usb_port.h index bb15013ec29..1031618e4ab 100644 --- a/sys/dev/usb/usb_port.h +++ b/sys/dev/usb/usb_port.h @@ -1,4 +1,4 @@ -/* $OpenBSD: usb_port.h,v 1.37 2002/05/07 18:29:18 nate Exp $ */ +/* $OpenBSD: usb_port.h,v 1.38 2002/05/09 15:06:29 nate Exp $ */ /* $NetBSD: usb_port.h,v 1.44 2001/05/14 20:35:29 bouyer Exp $ */ /* $FreeBSD: src/sys/dev/usb/usb_port.h,v 1.21 1999/11/17 22:33:47 n_hibma Exp $ */ @@ -190,6 +190,7 @@ __CONCAT(dname,_detach)(self, flags) \ */ #ifdef USB_DEBUG #define UKBD_DEBUG 1 +#define UHIDEV_DEBUG 1 #define UHID_DEBUG 1 #define OHCI_DEBUG 1 #define UGEN_DEBUG 1 @@ -235,6 +236,8 @@ __CONCAT(dname,_detach)(self, flags) \ #define show_scsipi_cmd show_scsi_cmd #define xs_control flags #define xs_status status +#define UHIDBUSCF_REPORTID -1 +#define UHIDBUSCF_REPORTID_DEFAULT -1 #define bswap32(x) swap32(x) #define bswap16(x) swap16(x) diff --git a/sys/dev/usb/usbhid.h b/sys/dev/usb/usbhid.h index 695c1cdb925..d88c6d375ee 100644 --- a/sys/dev/usb/usbhid.h +++ b/sys/dev/usb/usbhid.h @@ -1,5 +1,5 @@ -/* $OpenBSD: usbhid.h,v 1.6 2002/05/07 18:29:19 nate Exp $ */ -/* $NetBSD: usbhid.h,v 1.9 2000/09/03 19:09:14 augustss Exp $ */ +/* $OpenBSD: usbhid.h,v 1.7 2002/05/09 15:06:29 nate Exp $ */ +/* $NetBSD: usbhid.h,v 1.11 2001/12/28 00:20:24 augustss Exp $ */ /* $FreeBSD: src/sys/dev/usb/usbhid.h,v 1.7 1999/11/17 22:33:51 n_hibma Exp $ */ /* @@ -165,12 +165,25 @@ typedef struct usb_hid_descriptor { #define HUD_ERASER 0x0045 #define HUD_TABLET_PICK 0x0046 -#define HID_USAGE2(p,u) (((p) << 16) | u) +/* Usages LEDs */ +#define HUD_LED_NUM_LOCK 0x0001 +#define HUD_LED_CAPS_LOCK 0x0002 +#define HUD_LED_SCROLL_LOCK 0x0003 +#define HUD_LED_COMPOSE 0x0004 +#define HUD_LED_KANA 0x0005 + +#define HID_USAGE2(p, u) (((p) << 16) | u) +#define HID_GET_USAGE(u) ((u) & 0xffff) +#define HID_GET_USAGE_PAGE(u) (((u) >> 16) & 0xffff) #define UHID_INPUT_REPORT 0x01 #define UHID_OUTPUT_REPORT 0x02 #define UHID_FEATURE_REPORT 0x03 +#define HCOLL_PHYSICAL 0 +#define HCOLL_APPLICATION 1 +#define HCOLL_LOGICAL 2 + /* Bits in the input/output/feature items */ #define HIO_CONST 0x001 #define HIO_VARIABLE 0x002 |