1194676Sthompsa/* $FreeBSD$ */ 2194676Sthompsa/*- 3194676Sthompsa * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 4194676Sthompsa * 5194676Sthompsa * Redistribution and use in source and binary forms, with or without 6194676Sthompsa * modification, are permitted provided that the following conditions 7194676Sthompsa * are met: 8194676Sthompsa * 1. Redistributions of source code must retain the above copyright 9194676Sthompsa * notice, this list of conditions and the following disclaimer. 10194676Sthompsa * 2. Redistributions in binary form must reproduce the above copyright 11194676Sthompsa * notice, this list of conditions and the following disclaimer in the 12194676Sthompsa * documentation and/or other materials provided with the distribution. 13194676Sthompsa * 14194676Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15194676Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16194676Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17194676Sthompsa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18194676Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19194676Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20194676Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21194676Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22194676Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23194676Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24194676Sthompsa * SUCH DAMAGE. 25194676Sthompsa */ 26194676Sthompsa 27248236Shselasky#ifdef LIBUSB_GLOBAL_INCLUDE_FILE 28248236Shselasky#include LIBUSB_GLOBAL_INCLUDE_FILE 29248236Shselasky#else 30203815Swkoszek#include <stdio.h> 31203815Swkoszek#include <stdlib.h> 32248236Shselasky#include <string.h> 33248236Shselasky#include <time.h> 34248236Shselasky#include <sys/queue.h> 35248236Shselasky#endif 36203815Swkoszek 37208020Sthompsa#define libusb_device_handle libusb20_device 38208020Sthompsa 39194676Sthompsa#include "libusb20.h" 40194676Sthompsa#include "libusb20_desc.h" 41194676Sthompsa#include "libusb20_int.h" 42194676Sthompsa#include "libusb.h" 43194676Sthompsa#include "libusb10.h" 44194676Sthompsa 45199055Sthompsa#define N_ALIGN(n) (-((-(n)) & (-8UL))) 46199055Sthompsa 47194676Sthompsa/* USB descriptors */ 48194676Sthompsa 49194676Sthompsaint 50195957Salfredlibusb_get_device_descriptor(libusb_device *dev, 51194676Sthompsa struct libusb_device_descriptor *desc) 52194676Sthompsa{ 53194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 54194676Sthompsa struct libusb20_device *pdev; 55194676Sthompsa 56194676Sthompsa if ((dev == NULL) || (desc == NULL)) 57194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 58194676Sthompsa 59194676Sthompsa pdev = dev->os_priv; 60194676Sthompsa pdesc = libusb20_dev_get_device_desc(pdev); 61194676Sthompsa 62194676Sthompsa desc->bLength = pdesc->bLength; 63194676Sthompsa desc->bDescriptorType = pdesc->bDescriptorType; 64194676Sthompsa desc->bcdUSB = pdesc->bcdUSB; 65194676Sthompsa desc->bDeviceClass = pdesc->bDeviceClass; 66194676Sthompsa desc->bDeviceSubClass = pdesc->bDeviceSubClass; 67194676Sthompsa desc->bDeviceProtocol = pdesc->bDeviceProtocol; 68194676Sthompsa desc->bMaxPacketSize0 = pdesc->bMaxPacketSize0; 69194676Sthompsa desc->idVendor = pdesc->idVendor; 70194676Sthompsa desc->idProduct = pdesc->idProduct; 71194676Sthompsa desc->bcdDevice = pdesc->bcdDevice; 72194676Sthompsa desc->iManufacturer = pdesc->iManufacturer; 73194676Sthompsa desc->iProduct = pdesc->iProduct; 74194676Sthompsa desc->iSerialNumber = pdesc->iSerialNumber; 75194676Sthompsa desc->bNumConfigurations = pdesc->bNumConfigurations; 76194676Sthompsa 77194676Sthompsa return (0); 78194676Sthompsa} 79194676Sthompsa 80194676Sthompsaint 81195957Salfredlibusb_get_active_config_descriptor(libusb_device *dev, 82194676Sthompsa struct libusb_config_descriptor **config) 83194676Sthompsa{ 84194676Sthompsa struct libusb20_device *pdev; 85195957Salfred uint8_t config_index; 86194676Sthompsa 87194676Sthompsa pdev = dev->os_priv; 88195957Salfred config_index = libusb20_dev_get_config_index(pdev); 89194676Sthompsa 90195957Salfred return (libusb_get_config_descriptor(dev, config_index, config)); 91194676Sthompsa} 92194676Sthompsa 93194676Sthompsaint 94195957Salfredlibusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, 95194676Sthompsa struct libusb_config_descriptor **config) 96194676Sthompsa{ 97194676Sthompsa struct libusb20_device *pdev; 98194676Sthompsa struct libusb20_config *pconf; 99194676Sthompsa struct libusb20_interface *pinf; 100194676Sthompsa struct libusb20_endpoint *pend; 101195957Salfred struct libusb_config_descriptor *pconfd; 102195957Salfred struct libusb_interface_descriptor *ifd; 103195957Salfred struct libusb_endpoint_descriptor *endd; 104195957Salfred uint8_t *pextra; 105195957Salfred uint16_t nextra; 106195957Salfred uint8_t nif; 107195957Salfred uint8_t nep; 108195957Salfred uint8_t nalt; 109195957Salfred uint8_t i; 110195957Salfred uint8_t j; 111195957Salfred uint8_t k; 112194676Sthompsa 113194676Sthompsa if (dev == NULL || config == NULL) 114194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 115194676Sthompsa 116195957Salfred *config = NULL; 117195957Salfred 118194676Sthompsa pdev = dev->os_priv; 119194676Sthompsa pconf = libusb20_dev_alloc_config(pdev, config_index); 120194676Sthompsa 121194676Sthompsa if (pconf == NULL) 122194676Sthompsa return (LIBUSB_ERROR_NOT_FOUND); 123194676Sthompsa 124194676Sthompsa nalt = nif = pconf->num_interface; 125195957Salfred nep = 0; 126199055Sthompsa nextra = N_ALIGN(pconf->extra.len); 127195957Salfred 128195957Salfred for (i = 0; i < nif; i++) { 129195957Salfred 130195957Salfred pinf = pconf->interface + i; 131199055Sthompsa nextra += N_ALIGN(pinf->extra.len); 132195957Salfred nep += pinf->num_endpoints; 133195957Salfred k = pinf->num_endpoints; 134195957Salfred pend = pinf->endpoints; 135195957Salfred while (k--) { 136199055Sthompsa nextra += N_ALIGN(pend->extra.len); 137195957Salfred pend++; 138195957Salfred } 139195957Salfred 140195957Salfred j = pinf->num_altsetting; 141195957Salfred nalt += pinf->num_altsetting; 142195957Salfred pinf = pinf->altsetting; 143195957Salfred while (j--) { 144199055Sthompsa nextra += N_ALIGN(pinf->extra.len); 145195957Salfred nep += pinf->num_endpoints; 146195957Salfred k = pinf->num_endpoints; 147195957Salfred pend = pinf->endpoints; 148195957Salfred while (k--) { 149199055Sthompsa nextra += N_ALIGN(pend->extra.len); 150195957Salfred pend++; 151194676Sthompsa } 152195957Salfred pinf++; 153194676Sthompsa } 154194676Sthompsa } 155194676Sthompsa 156195957Salfred nextra = nextra + 157195957Salfred (1 * sizeof(libusb_config_descriptor)) + 158194676Sthompsa (nif * sizeof(libusb_interface)) + 159194676Sthompsa (nalt * sizeof(libusb_interface_descriptor)) + 160195957Salfred (nep * sizeof(libusb_endpoint_descriptor)); 161195957Salfred 162199055Sthompsa nextra = N_ALIGN(nextra); 163199055Sthompsa 164195957Salfred pconfd = malloc(nextra); 165195957Salfred 166195957Salfred if (pconfd == NULL) { 167194676Sthompsa free(pconf); 168194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 169194676Sthompsa } 170199055Sthompsa /* make sure memory is initialised */ 171195957Salfred memset(pconfd, 0, nextra); 172194676Sthompsa 173199055Sthompsa pconfd->interface = (libusb_interface *) (pconfd + 1); 174194676Sthompsa 175195957Salfred ifd = (libusb_interface_descriptor *) (pconfd->interface + nif); 176195957Salfred endd = (libusb_endpoint_descriptor *) (ifd + nalt); 177195957Salfred pextra = (uint8_t *)(endd + nep); 178195957Salfred 179195957Salfred /* fill in config descriptor */ 180195957Salfred 181195957Salfred pconfd->bLength = pconf->desc.bLength; 182195957Salfred pconfd->bDescriptorType = pconf->desc.bDescriptorType; 183195957Salfred pconfd->wTotalLength = pconf->desc.wTotalLength; 184195957Salfred pconfd->bNumInterfaces = pconf->desc.bNumInterfaces; 185195957Salfred pconfd->bConfigurationValue = pconf->desc.bConfigurationValue; 186195957Salfred pconfd->iConfiguration = pconf->desc.iConfiguration; 187195957Salfred pconfd->bmAttributes = pconf->desc.bmAttributes; 188195957Salfred pconfd->MaxPower = pconf->desc.bMaxPower; 189195957Salfred 190195957Salfred if (pconf->extra.len != 0) { 191195957Salfred pconfd->extra_length = pconf->extra.len; 192195957Salfred pconfd->extra = pextra; 193195957Salfred memcpy(pextra, pconf->extra.ptr, pconfd->extra_length); 194199055Sthompsa pextra += N_ALIGN(pconfd->extra_length); 195195957Salfred } 196195957Salfred /* setup all interface and endpoint pointers */ 197195957Salfred 198195957Salfred for (i = 0; i < nif; i++) { 199195957Salfred 200195957Salfred pconfd->interface[i].altsetting = ifd; 201195957Salfred ifd->endpoint = endd; 202195957Salfred endd += pconf->interface[i].num_endpoints; 203195957Salfred ifd++; 204195957Salfred 205195957Salfred for (j = 0; j < pconf->interface[i].num_altsetting; j++) { 206195957Salfred ifd->endpoint = endd; 207195957Salfred endd += pconf->interface[i].altsetting[j].num_endpoints; 208195957Salfred ifd++; 209194676Sthompsa } 210194676Sthompsa } 211194676Sthompsa 212195957Salfred /* fill in all interface and endpoint data */ 213194676Sthompsa 214195957Salfred for (i = 0; i < nif; i++) { 215194676Sthompsa pinf = &pconf->interface[i]; 216195957Salfred pconfd->interface[i].num_altsetting = pinf->num_altsetting + 1; 217195957Salfred for (j = 0; j < pconfd->interface[i].num_altsetting; j++) { 218194676Sthompsa if (j != 0) 219194676Sthompsa pinf = &pconf->interface[i].altsetting[j - 1]; 220195957Salfred ifd = &pconfd->interface[i].altsetting[j]; 221194676Sthompsa ifd->bLength = pinf->desc.bLength; 222194676Sthompsa ifd->bDescriptorType = pinf->desc.bDescriptorType; 223194676Sthompsa ifd->bInterfaceNumber = pinf->desc.bInterfaceNumber; 224194676Sthompsa ifd->bAlternateSetting = pinf->desc.bAlternateSetting; 225194676Sthompsa ifd->bNumEndpoints = pinf->desc.bNumEndpoints; 226194676Sthompsa ifd->bInterfaceClass = pinf->desc.bInterfaceClass; 227194676Sthompsa ifd->bInterfaceSubClass = pinf->desc.bInterfaceSubClass; 228194676Sthompsa ifd->bInterfaceProtocol = pinf->desc.bInterfaceProtocol; 229194676Sthompsa ifd->iInterface = pinf->desc.iInterface; 230195957Salfred if (pinf->extra.len != 0) { 231195957Salfred ifd->extra_length = pinf->extra.len; 232195957Salfred ifd->extra = pextra; 233195957Salfred memcpy(pextra, pinf->extra.ptr, pinf->extra.len); 234199055Sthompsa pextra += N_ALIGN(pinf->extra.len); 235195957Salfred } 236195957Salfred for (k = 0; k < pinf->num_endpoints; k++) { 237194676Sthompsa pend = &pinf->endpoints[k]; 238194676Sthompsa endd = &ifd->endpoint[k]; 239194676Sthompsa endd->bLength = pend->desc.bLength; 240194676Sthompsa endd->bDescriptorType = pend->desc.bDescriptorType; 241194676Sthompsa endd->bEndpointAddress = pend->desc.bEndpointAddress; 242194676Sthompsa endd->bmAttributes = pend->desc.bmAttributes; 243194676Sthompsa endd->wMaxPacketSize = pend->desc.wMaxPacketSize; 244194676Sthompsa endd->bInterval = pend->desc.bInterval; 245194676Sthompsa endd->bRefresh = pend->desc.bRefresh; 246194676Sthompsa endd->bSynchAddress = pend->desc.bSynchAddress; 247195957Salfred if (pend->extra.len != 0) { 248195957Salfred endd->extra_length = pend->extra.len; 249195957Salfred endd->extra = pextra; 250195957Salfred memcpy(pextra, pend->extra.ptr, pend->extra.len); 251199055Sthompsa pextra += N_ALIGN(pend->extra.len); 252195957Salfred } 253194676Sthompsa } 254195957Salfred } 255194676Sthompsa } 256194676Sthompsa 257194676Sthompsa free(pconf); 258195957Salfred 259195957Salfred *config = pconfd; 260195957Salfred 261195957Salfred return (0); /* success */ 262194676Sthompsa} 263194676Sthompsa 264194676Sthompsaint 265195957Salfredlibusb_get_config_descriptor_by_value(libusb_device *dev, 266194676Sthompsa uint8_t bConfigurationValue, struct libusb_config_descriptor **config) 267194676Sthompsa{ 268194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 269194676Sthompsa struct libusb20_device *pdev; 270194676Sthompsa int i; 271195957Salfred int err; 272194676Sthompsa 273194676Sthompsa if (dev == NULL || config == NULL) 274194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 275195957Salfred 276194676Sthompsa pdev = dev->os_priv; 277194676Sthompsa pdesc = libusb20_dev_get_device_desc(pdev); 278194676Sthompsa 279195957Salfred for (i = 0; i < pdesc->bNumConfigurations; i++) { 280195957Salfred err = libusb_get_config_descriptor(dev, i, config); 281195957Salfred if (err) 282195957Salfred return (err); 283194676Sthompsa 284195957Salfred if ((*config)->bConfigurationValue == bConfigurationValue) 285195957Salfred return (0); /* success */ 286195957Salfred 287195957Salfred libusb_free_config_descriptor(*config); 288194676Sthompsa } 289194676Sthompsa 290195957Salfred *config = NULL; 291195957Salfred 292194676Sthompsa return (LIBUSB_ERROR_NOT_FOUND); 293194676Sthompsa} 294194676Sthompsa 295194676Sthompsavoid 296194676Sthompsalibusb_free_config_descriptor(struct libusb_config_descriptor *config) 297194676Sthompsa{ 298194676Sthompsa free(config); 299194676Sthompsa} 300194676Sthompsa 301194676Sthompsaint 302235128Shselaskylibusb_get_string_descriptor(libusb_device_handle *pdev, 303235128Shselasky uint8_t desc_index, uint16_t langid, unsigned char *data, 304235128Shselasky int length) 305235128Shselasky{ 306235128Shselasky if (pdev == NULL || data == NULL || length < 1) 307235128Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 308235128Shselasky 309235128Shselasky if (length > 65535) 310235128Shselasky length = 65535; 311235128Shselasky 312235128Shselasky /* put some default data into the destination buffer */ 313235128Shselasky data[0] = 0; 314235128Shselasky 315235128Shselasky return (libusb_control_transfer(pdev, LIBUSB_ENDPOINT_IN, 316235128Shselasky LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc_index, 317235128Shselasky langid, data, length, 1000)); 318235128Shselasky} 319235128Shselasky 320235128Shselaskyint 321195957Salfredlibusb_get_string_descriptor_ascii(libusb_device_handle *pdev, 322194676Sthompsa uint8_t desc_index, unsigned char *data, int length) 323194676Sthompsa{ 324195957Salfred if (pdev == NULL || data == NULL || length < 1) 325227404Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 326194676Sthompsa 327224085Shselasky if (length > 65535) 328224085Shselasky length = 65535; 329224085Shselasky 330195957Salfred /* put some default data into the destination buffer */ 331195957Salfred data[0] = 0; 332194676Sthompsa 333195957Salfred if (libusb20_dev_req_string_simple_sync(pdev, desc_index, 334194676Sthompsa data, length) == 0) 335194676Sthompsa return (strlen(data)); 336194676Sthompsa 337194676Sthompsa return (LIBUSB_ERROR_OTHER); 338194676Sthompsa} 339199055Sthompsa 340199055Sthompsaint 341199055Sthompsalibusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, 342199055Sthompsa uint8_t desc_index, uint8_t *data, int length) 343199055Sthompsa{ 344224085Shselasky if (devh == NULL || data == NULL || length < 1) 345227404Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 346224085Shselasky 347224085Shselasky if (length > 65535) 348224085Shselasky length = 65535; 349224085Shselasky 350199055Sthompsa return (libusb_control_transfer(devh, LIBUSB_ENDPOINT_IN, 351199055Sthompsa LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, 352199055Sthompsa length, 1000)); 353199055Sthompsa} 354227404Shselasky 355227404Shselaskyint 356227404Shselaskylibusb_parse_ss_endpoint_comp(const void *buf, int len, 357227404Shselasky struct libusb_ss_endpoint_companion_descriptor **ep_comp) 358227404Shselasky{ 359227404Shselasky if (buf == NULL || ep_comp == NULL || len < 1) 360227404Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 361227404Shselasky 362227404Shselasky if (len > 65535) 363227404Shselasky len = 65535; 364227404Shselasky 365227404Shselasky *ep_comp = NULL; 366227404Shselasky 367227404Shselasky while (len != 0) { 368227404Shselasky uint8_t dlen; 369227404Shselasky uint8_t dtype; 370227404Shselasky 371227404Shselasky dlen = ((const uint8_t *)buf)[0]; 372227404Shselasky dtype = ((const uint8_t *)buf)[1]; 373227404Shselasky 374227404Shselasky if (dlen < 2 || dlen > len) 375227404Shselasky break; 376227404Shselasky 377227404Shselasky if (dlen >= LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE && 378227404Shselasky dtype == LIBUSB_DT_SS_ENDPOINT_COMPANION) { 379227404Shselasky struct libusb_ss_endpoint_companion_descriptor *ptr; 380227404Shselasky 381227404Shselasky ptr = malloc(sizeof(*ptr)); 382227404Shselasky if (ptr == NULL) 383227404Shselasky return (LIBUSB_ERROR_NO_MEM); 384227404Shselasky 385227404Shselasky ptr->bLength = LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE; 386227404Shselasky ptr->bDescriptorType = dtype; 387227404Shselasky ptr->bMaxBurst = ((const uint8_t *)buf)[2]; 388227404Shselasky ptr->bmAttributes = ((const uint8_t *)buf)[3]; 389227404Shselasky ptr->wBytesPerInterval = ((const uint8_t *)buf)[4] | 390227404Shselasky (((const uint8_t *)buf)[5] << 8); 391227404Shselasky 392227404Shselasky *ep_comp = ptr; 393227404Shselasky 394227404Shselasky return (0); /* success */ 395227404Shselasky } 396227404Shselasky 397227404Shselasky buf = ((const uint8_t *)buf) + dlen; 398227404Shselasky len -= dlen; 399227404Shselasky } 400227404Shselasky return (LIBUSB_ERROR_IO); 401227404Shselasky} 402227404Shselasky 403227404Shselaskyvoid 404227404Shselaskylibusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp) 405227404Shselasky{ 406227404Shselasky if (ep_comp == NULL) 407227404Shselasky return; 408227404Shselasky 409227404Shselasky free(ep_comp); 410227404Shselasky} 411227404Shselasky 412227404Shselaskyint 413227404Shselaskylibusb_parse_bos_descriptor(const void *buf, int len, 414227404Shselasky struct libusb_bos_descriptor **bos) 415227404Shselasky{ 416227404Shselasky struct libusb_bos_descriptor *ptr; 417234491Shselasky struct libusb_usb_2_0_device_capability_descriptor *dcap_20 = NULL; 418234491Shselasky struct libusb_ss_usb_device_capability_descriptor *ss_cap = NULL; 419227404Shselasky 420227404Shselasky if (buf == NULL || bos == NULL || len < 1) 421227404Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 422227404Shselasky 423227404Shselasky if (len > 65535) 424227404Shselasky len = 65535; 425227404Shselasky 426227404Shselasky *bos = ptr = NULL; 427227404Shselasky 428227404Shselasky while (len != 0) { 429227404Shselasky uint8_t dlen; 430227404Shselasky uint8_t dtype; 431227404Shselasky 432227404Shselasky dlen = ((const uint8_t *)buf)[0]; 433227404Shselasky dtype = ((const uint8_t *)buf)[1]; 434227404Shselasky 435227404Shselasky if (dlen < 2 || dlen > len) 436227404Shselasky break; 437227404Shselasky 438227404Shselasky if (dlen >= LIBUSB_DT_BOS_SIZE && 439227404Shselasky dtype == LIBUSB_DT_BOS) { 440227404Shselasky 441227404Shselasky ptr = malloc(sizeof(*ptr) + sizeof(*dcap_20) + 442227404Shselasky sizeof(*ss_cap)); 443227404Shselasky 444227404Shselasky if (ptr == NULL) 445227404Shselasky return (LIBUSB_ERROR_NO_MEM); 446227404Shselasky 447227404Shselasky *bos = ptr; 448227404Shselasky 449227404Shselasky ptr->bLength = LIBUSB_DT_BOS_SIZE; 450227404Shselasky ptr->bDescriptorType = dtype; 451227404Shselasky ptr->wTotalLength = ((const uint8_t *)buf)[2] | 452227404Shselasky (((const uint8_t *)buf)[3] << 8); 453227404Shselasky ptr->bNumDeviceCapabilities = ((const uint8_t *)buf)[4]; 454227404Shselasky ptr->usb_2_0_ext_cap = NULL; 455227404Shselasky ptr->ss_usb_cap = NULL; 456227404Shselasky 457227404Shselasky dcap_20 = (void *)(ptr + 1); 458227404Shselasky ss_cap = (void *)(dcap_20 + 1); 459227404Shselasky } 460227404Shselasky if (dlen >= 3 && 461227404Shselasky ptr != NULL && 462227404Shselasky dtype == LIBUSB_DT_DEVICE_CAPABILITY) { 463227404Shselasky switch (((const uint8_t *)buf)[2]) { 464227404Shselasky case LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY: 465234491Shselasky if (ptr->usb_2_0_ext_cap != NULL || dcap_20 == NULL) 466227404Shselasky break; 467227404Shselasky if (dlen < LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE) 468227404Shselasky break; 469227404Shselasky 470227404Shselasky ptr->usb_2_0_ext_cap = dcap_20; 471227404Shselasky 472227404Shselasky dcap_20->bLength = LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE; 473227404Shselasky dcap_20->bDescriptorType = dtype; 474227404Shselasky dcap_20->bDevCapabilityType = ((const uint8_t *)buf)[2]; 475227404Shselasky dcap_20->bmAttributes = ((const uint8_t *)buf)[3] | 476227404Shselasky (((const uint8_t *)buf)[4] << 8) | 477227404Shselasky (((const uint8_t *)buf)[5] << 16) | 478227404Shselasky (((const uint8_t *)buf)[6] << 24); 479227404Shselasky break; 480227404Shselasky 481227404Shselasky case LIBUSB_SS_USB_DEVICE_CAPABILITY: 482234491Shselasky if (ptr->ss_usb_cap != NULL || ss_cap == NULL) 483227404Shselasky break; 484227404Shselasky if (dlen < LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE) 485227404Shselasky break; 486227404Shselasky 487227404Shselasky ptr->ss_usb_cap = ss_cap; 488227404Shselasky 489227404Shselasky ss_cap->bLength = LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE; 490227404Shselasky ss_cap->bDescriptorType = dtype; 491227404Shselasky ss_cap->bDevCapabilityType = ((const uint8_t *)buf)[2]; 492227404Shselasky ss_cap->bmAttributes = ((const uint8_t *)buf)[3]; 493227404Shselasky ss_cap->wSpeedSupported = ((const uint8_t *)buf)[4] | 494227404Shselasky (((const uint8_t *)buf)[5] << 8); 495227404Shselasky ss_cap->bFunctionalitySupport = ((const uint8_t *)buf)[6]; 496227404Shselasky ss_cap->bU1DevExitLat = ((const uint8_t *)buf)[7]; 497227404Shselasky ss_cap->wU2DevExitLat = ((const uint8_t *)buf)[8] | 498227404Shselasky (((const uint8_t *)buf)[9] << 8); 499227404Shselasky break; 500227404Shselasky 501227404Shselasky default: 502227404Shselasky break; 503227404Shselasky } 504227404Shselasky } 505227404Shselasky 506227404Shselasky buf = ((const uint8_t *)buf) + dlen; 507227404Shselasky len -= dlen; 508227404Shselasky } 509227404Shselasky if (ptr != NULL) 510227404Shselasky return (0); /* success */ 511227404Shselasky 512227404Shselasky return (LIBUSB_ERROR_IO); 513227404Shselasky} 514227404Shselasky 515227404Shselaskyvoid 516227404Shselaskylibusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) 517227404Shselasky{ 518227404Shselasky if (bos == NULL) 519227404Shselasky return; 520227404Shselasky 521227404Shselasky free(bos); 522227404Shselasky} 523