usb_hid.c revision 188942
1184610Salfred/* $NetBSD: hid.c,v 1.17 2001/11/13 06:24:53 lukem Exp $ */ 2184610Salfred 3184610Salfred 4184610Salfred#include <sys/cdefs.h> 5184610Salfred__FBSDID("$FreeBSD: head/sys/dev/usb/usb_hid.c 188942 2009-02-23 18:31:00Z thompsa $"); 6184610Salfred/*- 7184610Salfred * Copyright (c) 1998 The NetBSD Foundation, Inc. 8184610Salfred * All rights reserved. 9184610Salfred * 10184610Salfred * This code is derived from software contributed to The NetBSD Foundation 11184610Salfred * by Lennart Augustsson (lennart@augustsson.net) at 12184610Salfred * Carlstedt Research & Technology. 13184610Salfred * 14184610Salfred * Redistribution and use in source and binary forms, with or without 15184610Salfred * modification, are permitted provided that the following conditions 16184610Salfred * are met: 17184610Salfred * 1. Redistributions of source code must retain the above copyright 18184610Salfred * notice, this list of conditions and the following disclaimer. 19184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 20184610Salfred * notice, this list of conditions and the following disclaimer in the 21184610Salfred * documentation and/or other materials provided with the distribution. 22184610Salfred * 3. All advertising materials mentioning features or use of this software 23184610Salfred * must display the following acknowledgement: 24184610Salfred * This product includes software developed by the NetBSD 25184610Salfred * Foundation, Inc. and its contributors. 26184610Salfred * 4. Neither the name of The NetBSD Foundation nor the names of its 27184610Salfred * contributors may be used to endorse or promote products derived 28184610Salfred * from this software without specific prior written permission. 29184610Salfred * 30184610Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 31184610Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 32184610Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 33184610Salfred * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 34184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 35184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 36184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 37184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 38184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 39184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40184610Salfred * POSSIBILITY OF SUCH DAMAGE. 41184610Salfred */ 42184610Salfred 43188942Sthompsa#include <dev/usb/usb.h> 44188942Sthompsa#include <dev/usb/usb_mfunc.h> 45188942Sthompsa#include <dev/usb/usb_error.h> 46188942Sthompsa#include <dev/usb/usb_defs.h> 47188942Sthompsa#include <dev/usb/usbhid.h> 48184610Salfred 49184610Salfred#define USB_DEBUG_VAR usb2_debug 50184610Salfred 51188942Sthompsa#include <dev/usb/usb_core.h> 52188942Sthompsa#include <dev/usb/usb_debug.h> 53188942Sthompsa#include <dev/usb/usb_parse.h> 54188942Sthompsa#include <dev/usb/usb_process.h> 55188942Sthompsa#include <dev/usb/usb_device.h> 56188942Sthompsa#include <dev/usb/usb_request.h> 57188942Sthompsa#include <dev/usb/usb_hid.h> 58184610Salfred 59184610Salfredstatic void hid_clear_local(struct hid_item *); 60184610Salfred 61184610Salfred#define MAXUSAGE 100 62184610Salfredstruct hid_data { 63184610Salfred const uint8_t *start; 64184610Salfred const uint8_t *end; 65184610Salfred const uint8_t *p; 66184610Salfred struct hid_item cur; 67184610Salfred int32_t usages[MAXUSAGE]; 68184610Salfred int nu; 69184610Salfred int minset; 70184610Salfred int multi; 71184610Salfred int multimax; 72184610Salfred int kindset; 73184610Salfred}; 74184610Salfred 75184610Salfred/*------------------------------------------------------------------------* 76184610Salfred * hid_clear_local 77184610Salfred *------------------------------------------------------------------------*/ 78184610Salfredstatic void 79184610Salfredhid_clear_local(struct hid_item *c) 80184610Salfred{ 81184610Salfred 82184610Salfred c->usage = 0; 83184610Salfred c->usage_minimum = 0; 84184610Salfred c->usage_maximum = 0; 85184610Salfred c->designator_index = 0; 86184610Salfred c->designator_minimum = 0; 87184610Salfred c->designator_maximum = 0; 88184610Salfred c->string_index = 0; 89184610Salfred c->string_minimum = 0; 90184610Salfred c->string_maximum = 0; 91184610Salfred c->set_delimiter = 0; 92184610Salfred} 93184610Salfred 94184610Salfred/*------------------------------------------------------------------------* 95184610Salfred * hid_start_parse 96184610Salfred *------------------------------------------------------------------------*/ 97184610Salfredstruct hid_data * 98184610Salfredhid_start_parse(const void *d, int len, int kindset) 99184610Salfred{ 100184610Salfred struct hid_data *s; 101184610Salfred 102184610Salfred s = malloc(sizeof *s, M_TEMP, M_WAITOK | M_ZERO); 103184610Salfred s->start = s->p = d; 104184610Salfred s->end = ((const uint8_t *)d) + len; 105184610Salfred s->kindset = kindset; 106184610Salfred return (s); 107184610Salfred} 108184610Salfred 109184610Salfred/*------------------------------------------------------------------------* 110184610Salfred * hid_end_parse 111184610Salfred *------------------------------------------------------------------------*/ 112184610Salfredvoid 113184610Salfredhid_end_parse(struct hid_data *s) 114184610Salfred{ 115184610Salfred 116184610Salfred while (s->cur.next != NULL) { 117184610Salfred struct hid_item *hi = s->cur.next->next; 118184610Salfred 119184610Salfred free(s->cur.next, M_TEMP); 120184610Salfred s->cur.next = hi; 121184610Salfred } 122184610Salfred free(s, M_TEMP); 123184610Salfred} 124184610Salfred 125184610Salfred/*------------------------------------------------------------------------* 126184610Salfred * hid_get_item 127184610Salfred *------------------------------------------------------------------------*/ 128184610Salfredint 129184610Salfredhid_get_item(struct hid_data *s, struct hid_item *h) 130184610Salfred{ 131184610Salfred struct hid_item *c = &s->cur; 132184610Salfred unsigned int bTag, bType, bSize; 133184610Salfred uint32_t oldpos; 134184610Salfred const uint8_t *data; 135184610Salfred int32_t dval; 136184610Salfred const uint8_t *p; 137184610Salfred struct hid_item *hi; 138184610Salfred int i; 139184610Salfred 140184610Salfredtop: 141184610Salfred if (s->multimax != 0) { 142184610Salfred if (s->multi < s->multimax) { 143184610Salfred c->usage = s->usages[MIN(s->multi, s->nu - 1)]; 144184610Salfred s->multi++; 145184610Salfred *h = *c; 146184610Salfred c->loc.pos += c->loc.size; 147184610Salfred h->next = 0; 148184610Salfred return (1); 149184610Salfred } else { 150184610Salfred c->loc.count = s->multimax; 151184610Salfred s->multimax = 0; 152184610Salfred s->nu = 0; 153184610Salfred hid_clear_local(c); 154184610Salfred } 155184610Salfred } 156184610Salfred for (;;) { 157184610Salfred p = s->p; 158184610Salfred if (p >= s->end) 159184610Salfred return (0); 160184610Salfred 161184610Salfred bSize = *p++; 162184610Salfred if (bSize == 0xfe) { 163184610Salfred /* long item */ 164184610Salfred bSize = *p++; 165184610Salfred bSize |= *p++ << 8; 166184610Salfred bTag = *p++; 167184610Salfred data = p; 168184610Salfred p += bSize; 169184610Salfred bType = 0xff; /* XXX what should it be */ 170184610Salfred } else { 171184610Salfred /* short item */ 172184610Salfred bTag = bSize >> 4; 173184610Salfred bType = (bSize >> 2) & 3; 174184610Salfred bSize &= 3; 175184610Salfred if (bSize == 3) 176184610Salfred bSize = 4; 177184610Salfred data = p; 178184610Salfred p += bSize; 179184610Salfred } 180184610Salfred s->p = p; 181184610Salfred switch (bSize) { 182184610Salfred case 0: 183184610Salfred dval = 0; 184184610Salfred break; 185184610Salfred case 1: 186184610Salfred dval = (int8_t)*data++; 187184610Salfred break; 188184610Salfred case 2: 189184610Salfred dval = *data++; 190184610Salfred dval |= *data++ << 8; 191184610Salfred dval = (int16_t)dval; 192184610Salfred break; 193184610Salfred case 4: 194184610Salfred dval = *data++; 195184610Salfred dval |= *data++ << 8; 196184610Salfred dval |= *data++ << 16; 197184610Salfred dval |= *data++ << 24; 198184610Salfred break; 199184610Salfred default: 200184610Salfred printf("BAD LENGTH %d\n", bSize); 201184610Salfred continue; 202184610Salfred } 203184610Salfred 204184610Salfred switch (bType) { 205184610Salfred case 0: /* Main */ 206184610Salfred switch (bTag) { 207184610Salfred case 8: /* Input */ 208184610Salfred if (!(s->kindset & (1 << hid_input))) { 209184610Salfred if (s->nu > 0) 210184610Salfred s->nu--; 211184610Salfred continue; 212184610Salfred } 213184610Salfred c->kind = hid_input; 214184610Salfred c->flags = dval; 215184610Salfred ret: 216184610Salfred if (c->flags & HIO_VARIABLE) { 217184610Salfred s->multimax = c->loc.count; 218184610Salfred s->multi = 0; 219184610Salfred c->loc.count = 1; 220184610Salfred if (s->minset) { 221184610Salfred for (i = c->usage_minimum; 222184610Salfred i <= c->usage_maximum; 223184610Salfred i++) { 224184610Salfred s->usages[s->nu] = i; 225184610Salfred if (s->nu < MAXUSAGE - 1) 226184610Salfred s->nu++; 227184610Salfred } 228184610Salfred s->minset = 0; 229184610Salfred } 230184610Salfred goto top; 231184610Salfred } else { 232184610Salfred *h = *c; 233184610Salfred h->next = 0; 234184610Salfred c->loc.pos += 235184610Salfred c->loc.size * c->loc.count; 236184610Salfred hid_clear_local(c); 237184610Salfred s->minset = 0; 238184610Salfred return (1); 239184610Salfred } 240184610Salfred case 9: /* Output */ 241184610Salfred if (!(s->kindset & (1 << hid_output))) { 242184610Salfred if (s->nu > 0) 243184610Salfred s->nu--; 244184610Salfred continue; 245184610Salfred } 246184610Salfred c->kind = hid_output; 247184610Salfred c->flags = dval; 248184610Salfred goto ret; 249184610Salfred case 10: /* Collection */ 250184610Salfred c->kind = hid_collection; 251184610Salfred c->collection = dval; 252184610Salfred c->collevel++; 253184610Salfred *h = *c; 254184610Salfred hid_clear_local(c); 255184610Salfred s->nu = 0; 256184610Salfred return (1); 257184610Salfred case 11: /* Feature */ 258184610Salfred if (!(s->kindset & (1 << hid_feature))) { 259184610Salfred if (s->nu > 0) 260184610Salfred s->nu--; 261184610Salfred continue; 262184610Salfred } 263184610Salfred c->kind = hid_feature; 264184610Salfred c->flags = dval; 265184610Salfred goto ret; 266184610Salfred case 12: /* End collection */ 267184610Salfred c->kind = hid_endcollection; 268184610Salfred c->collevel--; 269184610Salfred *h = *c; 270184610Salfred hid_clear_local(c); 271184610Salfred s->nu = 0; 272184610Salfred return (1); 273184610Salfred default: 274184610Salfred printf("Main bTag=%d\n", bTag); 275184610Salfred break; 276184610Salfred } 277184610Salfred break; 278184610Salfred case 1: /* Global */ 279184610Salfred switch (bTag) { 280184610Salfred case 0: 281184610Salfred c->_usage_page = dval << 16; 282184610Salfred break; 283184610Salfred case 1: 284184610Salfred c->logical_minimum = dval; 285184610Salfred break; 286184610Salfred case 2: 287184610Salfred c->logical_maximum = dval; 288184610Salfred break; 289184610Salfred case 3: 290184610Salfred c->physical_minimum = dval; 291184610Salfred break; 292184610Salfred case 4: 293184610Salfred c->physical_maximum = dval; 294184610Salfred break; 295184610Salfred case 5: 296184610Salfred c->unit_exponent = dval; 297184610Salfred break; 298184610Salfred case 6: 299184610Salfred c->unit = dval; 300184610Salfred break; 301184610Salfred case 7: 302184610Salfred c->loc.size = dval; 303184610Salfred break; 304184610Salfred case 8: 305184610Salfred c->report_ID = dval; 306184610Salfred break; 307184610Salfred case 9: 308184610Salfred c->loc.count = dval; 309184610Salfred break; 310184610Salfred case 10: /* Push */ 311184610Salfred hi = malloc(sizeof *hi, M_TEMP, M_WAITOK); 312184610Salfred *hi = s->cur; 313184610Salfred c->next = hi; 314184610Salfred break; 315184610Salfred case 11: /* Pop */ 316184610Salfred hi = c->next; 317184610Salfred oldpos = c->loc.pos; 318184610Salfred s->cur = *hi; 319184610Salfred c->loc.pos = oldpos; 320184610Salfred free(hi, M_TEMP); 321184610Salfred break; 322184610Salfred default: 323184610Salfred printf("Global bTag=%d\n", bTag); 324184610Salfred break; 325184610Salfred } 326184610Salfred break; 327184610Salfred case 2: /* Local */ 328184610Salfred switch (bTag) { 329184610Salfred case 0: 330184610Salfred if (bSize == 1) 331184610Salfred dval = c->_usage_page | (dval & 0xff); 332184610Salfred else if (bSize == 2) 333184610Salfred dval = c->_usage_page | (dval & 0xffff); 334184610Salfred c->usage = dval; 335184610Salfred if (s->nu < MAXUSAGE) 336184610Salfred s->usages[s->nu++] = dval; 337184610Salfred /* else XXX */ 338184610Salfred break; 339184610Salfred case 1: 340184610Salfred s->minset = 1; 341184610Salfred if (bSize == 1) 342184610Salfred dval = c->_usage_page | (dval & 0xff); 343184610Salfred else if (bSize == 2) 344184610Salfred dval = c->_usage_page | (dval & 0xffff); 345184610Salfred c->usage_minimum = dval; 346184610Salfred break; 347184610Salfred case 2: 348184610Salfred if (bSize == 1) 349184610Salfred dval = c->_usage_page | (dval & 0xff); 350184610Salfred else if (bSize == 2) 351184610Salfred dval = c->_usage_page | (dval & 0xffff); 352184610Salfred c->usage_maximum = dval; 353184610Salfred break; 354184610Salfred case 3: 355184610Salfred c->designator_index = dval; 356184610Salfred break; 357184610Salfred case 4: 358184610Salfred c->designator_minimum = dval; 359184610Salfred break; 360184610Salfred case 5: 361184610Salfred c->designator_maximum = dval; 362184610Salfred break; 363184610Salfred case 7: 364184610Salfred c->string_index = dval; 365184610Salfred break; 366184610Salfred case 8: 367184610Salfred c->string_minimum = dval; 368184610Salfred break; 369184610Salfred case 9: 370184610Salfred c->string_maximum = dval; 371184610Salfred break; 372184610Salfred case 10: 373184610Salfred c->set_delimiter = dval; 374184610Salfred break; 375184610Salfred default: 376184610Salfred printf("Local bTag=%d\n", bTag); 377184610Salfred break; 378184610Salfred } 379184610Salfred break; 380184610Salfred default: 381184610Salfred printf("default bType=%d\n", bType); 382184610Salfred break; 383184610Salfred } 384184610Salfred } 385184610Salfred} 386184610Salfred 387184610Salfred/*------------------------------------------------------------------------* 388184610Salfred * hid_report_size 389184610Salfred *------------------------------------------------------------------------*/ 390184610Salfredint 391184610Salfredhid_report_size(const void *buf, int len, enum hid_kind k, uint8_t *idp) 392184610Salfred{ 393184610Salfred struct hid_data *d; 394184610Salfred struct hid_item h; 395184610Salfred int hi, lo, size, id; 396184610Salfred 397184610Salfred id = 0; 398184610Salfred hi = lo = -1; 399184610Salfred for (d = hid_start_parse(buf, len, 1 << k); hid_get_item(d, &h);) 400184610Salfred if (h.kind == k) { 401184610Salfred if (h.report_ID != 0 && !id) 402184610Salfred id = h.report_ID; 403184610Salfred if (h.report_ID == id) { 404184610Salfred if (lo < 0) 405184610Salfred lo = h.loc.pos; 406184610Salfred hi = h.loc.pos + h.loc.size * h.loc.count; 407184610Salfred } 408184610Salfred } 409184610Salfred hid_end_parse(d); 410184610Salfred size = hi - lo; 411184610Salfred if (id != 0) { 412184610Salfred size += 8; 413184610Salfred *idp = id; /* XXX wrong */ 414184610Salfred } else 415184610Salfred *idp = 0; 416184610Salfred return ((size + 7) / 8); 417184610Salfred} 418184610Salfred 419184610Salfred/*------------------------------------------------------------------------* 420184610Salfred * hid_locate 421184610Salfred *------------------------------------------------------------------------*/ 422184610Salfredint 423184610Salfredhid_locate(const void *desc, int size, uint32_t u, enum hid_kind k, 424184610Salfred struct hid_location *loc, uint32_t *flags) 425184610Salfred{ 426184610Salfred struct hid_data *d; 427184610Salfred struct hid_item h; 428184610Salfred 429184610Salfred for (d = hid_start_parse(desc, size, 1 << k); hid_get_item(d, &h);) { 430184610Salfred if (h.kind == k && !(h.flags & HIO_CONST) && h.usage == u) { 431184610Salfred if (loc != NULL) 432184610Salfred *loc = h.loc; 433184610Salfred if (flags != NULL) 434184610Salfred *flags = h.flags; 435184610Salfred hid_end_parse(d); 436184610Salfred return (1); 437184610Salfred } 438184610Salfred } 439184610Salfred hid_end_parse(d); 440184610Salfred loc->size = 0; 441184610Salfred return (0); 442184610Salfred} 443184610Salfred 444184610Salfred/*------------------------------------------------------------------------* 445184610Salfred * hid_get_data 446184610Salfred *------------------------------------------------------------------------*/ 447184610Salfreduint32_t 448184610Salfredhid_get_data(const uint8_t *buf, uint32_t len, struct hid_location *loc) 449184610Salfred{ 450184610Salfred uint32_t hpos = loc->pos; 451184610Salfred uint32_t hsize = loc->size; 452184610Salfred uint32_t data; 453184610Salfred int i, s, t; 454184610Salfred 455184610Salfred DPRINTFN(11, "hid_get_data: loc %d/%d\n", hpos, hsize); 456184610Salfred 457184610Salfred if (hsize == 0) 458184610Salfred return (0); 459184610Salfred 460184610Salfred data = 0; 461184610Salfred s = hpos / 8; 462184610Salfred for (i = hpos; i < (hpos + hsize); i += 8) { 463184610Salfred t = (i / 8); 464184610Salfred if (t < len) { 465184610Salfred data |= buf[t] << ((t - s) * 8); 466184610Salfred } 467184610Salfred } 468184610Salfred data >>= hpos % 8; 469184610Salfred data &= (1 << hsize) - 1; 470184610Salfred hsize = 32 - hsize; 471184610Salfred /* Sign extend */ 472184610Salfred data = ((int32_t)data << hsize) >> hsize; 473184610Salfred DPRINTFN(11, "hid_get_data: loc %d/%d = %lu\n", 474184610Salfred loc->pos, loc->size, (long)data); 475184610Salfred return (data); 476184610Salfred} 477184610Salfred 478184610Salfred/*------------------------------------------------------------------------* 479184610Salfred * hid_is_collection 480184610Salfred *------------------------------------------------------------------------*/ 481184610Salfredint 482184610Salfredhid_is_collection(const void *desc, int size, uint32_t usage) 483184610Salfred{ 484184610Salfred struct hid_data *hd; 485184610Salfred struct hid_item hi; 486184610Salfred int err; 487184610Salfred 488184610Salfred hd = hid_start_parse(desc, size, hid_input); 489184610Salfred if (hd == NULL) 490184610Salfred return (0); 491184610Salfred 492184610Salfred err = hid_get_item(hd, &hi) && 493184610Salfred hi.kind == hid_collection && 494184610Salfred hi.usage == usage; 495184610Salfred hid_end_parse(hd); 496184610Salfred return (err); 497184610Salfred} 498184610Salfred 499184610Salfred/*------------------------------------------------------------------------* 500184610Salfred * hid_get_descriptor_from_usb 501184610Salfred * 502184610Salfred * This function will search for a HID descriptor between two USB 503184610Salfred * interface descriptors. 504184610Salfred * 505184610Salfred * Return values: 506184610Salfred * NULL: No more HID descriptors. 507184610Salfred * Else: Pointer to HID descriptor. 508184610Salfred *------------------------------------------------------------------------*/ 509184610Salfredstruct usb2_hid_descriptor * 510184610Salfredhid_get_descriptor_from_usb(struct usb2_config_descriptor *cd, 511184610Salfred struct usb2_interface_descriptor *id) 512184610Salfred{ 513184610Salfred struct usb2_descriptor *desc = (void *)id; 514184610Salfred 515184610Salfred if (desc == NULL) { 516184610Salfred return (NULL); 517184610Salfred } 518184610Salfred while ((desc = usb2_desc_foreach(cd, desc))) { 519184610Salfred if ((desc->bDescriptorType == UDESC_HID) && 520184610Salfred (desc->bLength >= USB_HID_DESCRIPTOR_SIZE(0))) { 521184610Salfred return (void *)desc; 522184610Salfred } 523184610Salfred if (desc->bDescriptorType == UDESC_INTERFACE) { 524184610Salfred break; 525184610Salfred } 526184610Salfred } 527184610Salfred return (NULL); 528184610Salfred} 529184610Salfred 530184610Salfred/*------------------------------------------------------------------------* 531184610Salfred * usb2_req_get_hid_desc 532184610Salfred * 533184610Salfred * This function will read out an USB report descriptor from the USB 534184610Salfred * device. 535184610Salfred * 536184610Salfred * Return values: 537184610Salfred * NULL: Failure. 538184610Salfred * Else: Success. The pointer should eventually be passed to free(). 539184610Salfred *------------------------------------------------------------------------*/ 540184610Salfredusb2_error_t 541184610Salfredusb2_req_get_hid_desc(struct usb2_device *udev, struct mtx *mtx, 542184610Salfred void **descp, uint16_t *sizep, 543184610Salfred usb2_malloc_type mem, uint8_t iface_index) 544184610Salfred{ 545184610Salfred struct usb2_interface *iface = usb2_get_iface(udev, iface_index); 546184610Salfred struct usb2_hid_descriptor *hid; 547184610Salfred usb2_error_t err; 548184610Salfred 549184610Salfred if ((iface == NULL) || (iface->idesc == NULL)) { 550184610Salfred return (USB_ERR_INVAL); 551184610Salfred } 552184610Salfred hid = hid_get_descriptor_from_usb 553184610Salfred (usb2_get_config_descriptor(udev), iface->idesc); 554184610Salfred 555184610Salfred if (hid == NULL) { 556184610Salfred return (USB_ERR_IOERROR); 557184610Salfred } 558184610Salfred *sizep = UGETW(hid->descrs[0].wDescriptorLength); 559184610Salfred if (*sizep == 0) { 560184610Salfred return (USB_ERR_IOERROR); 561184610Salfred } 562184610Salfred if (mtx) 563184610Salfred mtx_unlock(mtx); 564184610Salfred 565184610Salfred *descp = malloc(*sizep, mem, M_ZERO | M_WAITOK); 566184610Salfred 567184610Salfred if (mtx) 568184610Salfred mtx_lock(mtx); 569184610Salfred 570184610Salfred if (*descp == NULL) { 571184610Salfred return (USB_ERR_NOMEM); 572184610Salfred } 573184610Salfred err = usb2_req_get_report_descriptor 574184610Salfred (udev, mtx, *descp, *sizep, iface_index); 575184610Salfred 576184610Salfred if (err) { 577184610Salfred free(*descp, mem); 578184610Salfred *descp = NULL; 579184610Salfred return (err); 580184610Salfred } 581184610Salfred return (USB_ERR_NORMAL_COMPLETION); 582184610Salfred} 583