diff -ruN usb.orig/hid.c usb/hid.c --- usb.orig/hid.c Wed Nov 17 16:15:25 2004 +++ usb/hid.c Wed Nov 17 17:08:23 2004 @@ -63,7 +63,7 @@ Static void hid_clear_local(struct hid_item *); -#define MAXUSAGE 100 +#define MAXUSAGE 256 struct hid_data { u_char *start; u_char *end; @@ -74,13 +74,14 @@ 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; @@ -94,14 +95,14 @@ } 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|M_ZERO); s->start = s->p = d; s->end = (char *)d + len; - s->kindset = kindset; + s->kind = kind; return (s); } @@ -128,15 +129,19 @@ 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 +179,12 @@ 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 +197,22 @@ 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 +229,18 @@ } 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 +251,12 @@ 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 +292,7 @@ break; case 8: c->report_ID = dval; + c->loc.pos = 0; break; case 9: c->loc.count = dval; @@ -367,35 +375,51 @@ } 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<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_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_repdesc = desc; sc->sc_repdesc_size = size; diff -ruN usb.orig/ums.c usb/ums.c --- usb.orig/ums.c Wed Nov 17 16:15:25 2004 +++ usb/ums.c Wed Nov 17 17:21:34 2004 @@ -136,6 +136,7 @@ #define MOUSE_FLAGS_MASK (HIO_CONST|HIO_RELATIVE) #define MOUSE_FLAGS (HIO_RELATIVE) +Static int uhidev_maxrepid(void *buf, int len); Static void ums_intr(usbd_xfer_handle xfer, usbd_private_handle priv, usbd_status status); @@ -187,7 +188,7 @@ if (err) return (UMATCH_NONE); - if (hid_is_collection(desc, size, + if (hid_is_collection(desc, size, uaa->reportid, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))) ret = UMATCH_IFACECLASS; else @@ -203,7 +204,8 @@ usbd_interface_handle iface = uaa->iface; usb_interface_descriptor_t *id; usb_endpoint_descriptor_t *ed; - int size; + int size, nrepid, repid, repsz; + int repsizes[256]; void *desc; usbd_status err; char devinfo[1024]; @@ -243,7 +245,42 @@ if (err) USB_ATTACH_ERROR_RETURN; - if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), + 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_isize = 0; + + 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(("ums_attach: isize=%d\n", sc->sc_isize)); + + /* find the report descriptor id to use in MATCH */ + 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 { + uaa->reportid = repid; + DPRINTF(("uhidev_match: repid=%d\n", + repid)); + } + } + + if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), uaa->reportid, hid_input, &sc->sc_loc_x, &flags)) { printf("%s: mouse has no X report\n", USBDEVNAME(sc->sc_dev)); USB_ATTACH_ERROR_RETURN; @@ -254,7 +291,7 @@ USB_ATTACH_ERROR_RETURN; } - if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), + if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), uaa->reportid, hid_input, &sc->sc_loc_y, &flags)) { printf("%s: mouse has no Y report\n", USBDEVNAME(sc->sc_dev)); USB_ATTACH_ERROR_RETURN; @@ -266,9 +303,9 @@ } /* try to guess the Z activator: first check Z, then WHEEL */ - if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), + if (hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), uaa->reportid, hid_input, &sc->sc_loc_z, &flags) || - hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), + hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), uaa->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 */ @@ -279,7 +316,7 @@ /* figure out the number of buttons */ for (i = 1; i <= MAX_BUTTONS; i++) - if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i), + if (!hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i), uaa->reportid, hid_input, &loc_btn, 0)) break; sc->nbuttons = i - 1; @@ -294,10 +331,10 @@ sc->nbuttons, sc->flags & UMS_Z? " and Z dir." : ""); for (i = 1; i <= sc->nbuttons; i++) - hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i), + hid_locate(desc, size, HID_USAGE2(HUP_BUTTON, i), uaa->reportid, hid_input, &sc->sc_loc_btn[i-1], 0); - sc->sc_isize = hid_report_size(desc, size, hid_input, &sc->sc_iid); + sc->sc_isize = hid_report_size(desc, size, hid_input, uaa->reportid); sc->sc_ibuf = malloc(sc->sc_isize, M_USB, M_NOWAIT); if (!sc->sc_ibuf) { printf("%s: no memory\n", USBDEVNAME(sc->sc_dev)); @@ -322,7 +359,7 @@ 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)); + DPRINTF(("ums_attach: size=%d, id=%d\n", sc->sc_isize, uaa->reportid)); #endif if (sc->nbuttons > MOUSE_MSC_MAXBUTTON) @@ -821,6 +858,22 @@ } return error; +} + +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); } DRIVER_MODULE(ums, uhub, ums_driver, ums_devclass, usbd_driver_load, 0); diff -ruN usb.orig/usbdi.h usb/usbdi.h --- usb.orig/usbdi.h Wed Nov 17 16:15:25 2004 +++ usb/usbdi.h Wed Nov 17 16:10:41 2004 @@ -219,6 +219,7 @@ int usegeneric; usbd_interface_handle *ifaces; /* all interfaces */ int nifaces; /* number of interfaces */ + u_int8_t reportid; }; #if defined(__NetBSD__) || defined(__OpenBSD__) diff -ruN usb.orig/usbhid.h usb/usbhid.h --- usb.orig/usbhid.h Wed Nov 17 16:15:25 2004 +++ usb/usbhid.h Wed Nov 17 16:17:20 2004 @@ -170,6 +170,10 @@ #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