1194676Sthompsa/* $FreeBSD: stable/11/lib/libusb/libusb10_desc.c 328142 2018-01-18 21:39:03Z kevans $ */ 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) 335301846Shselasky return (strlen((char *)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 413301968Shselaskylibusb_get_ss_endpoint_companion_descriptor(struct libusb_context *ctx, 414301968Shselasky const struct libusb_endpoint_descriptor *endpoint, 415301968Shselasky struct libusb_ss_endpoint_companion_descriptor **ep_comp) 416301968Shselasky{ 417301968Shselasky if (endpoint == NULL) 418301968Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 419301968Shselasky return (libusb_parse_ss_endpoint_comp(endpoint->extra, endpoint->extra_length, ep_comp)); 420301968Shselasky} 421301968Shselasky 422301968Shselaskyvoid 423301968Shselaskylibusb_free_ss_endpoint_companion_descriptor(struct libusb_ss_endpoint_companion_descriptor *ep_comp) 424301968Shselasky{ 425301968Shselasky 426301968Shselasky libusb_free_ss_endpoint_comp(ep_comp); 427301968Shselasky} 428301968Shselasky 429301968Shselaskyint 430227404Shselaskylibusb_parse_bos_descriptor(const void *buf, int len, 431227404Shselasky struct libusb_bos_descriptor **bos) 432227404Shselasky{ 433227404Shselasky struct libusb_bos_descriptor *ptr; 434234491Shselasky struct libusb_usb_2_0_device_capability_descriptor *dcap_20 = NULL; 435234491Shselasky struct libusb_ss_usb_device_capability_descriptor *ss_cap = NULL; 436328142Skevans uint8_t index = 0; 437227404Shselasky 438227404Shselasky if (buf == NULL || bos == NULL || len < 1) 439227404Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 440227404Shselasky 441227404Shselasky if (len > 65535) 442227404Shselasky len = 65535; 443227404Shselasky 444227404Shselasky *bos = ptr = NULL; 445227404Shselasky 446227404Shselasky while (len != 0) { 447227404Shselasky uint8_t dlen; 448227404Shselasky uint8_t dtype; 449227404Shselasky 450227404Shselasky dlen = ((const uint8_t *)buf)[0]; 451227404Shselasky dtype = ((const uint8_t *)buf)[1]; 452227404Shselasky 453227404Shselasky if (dlen < 2 || dlen > len) 454227404Shselasky break; 455227404Shselasky 456227404Shselasky if (dlen >= LIBUSB_DT_BOS_SIZE && 457328142Skevans dtype == LIBUSB_DT_BOS && 458328142Skevans ptr == NULL) { 459227404Shselasky 460227404Shselasky ptr = malloc(sizeof(*ptr) + sizeof(*dcap_20) + 461227404Shselasky sizeof(*ss_cap)); 462227404Shselasky 463227404Shselasky if (ptr == NULL) 464227404Shselasky return (LIBUSB_ERROR_NO_MEM); 465227404Shselasky 466227404Shselasky *bos = ptr; 467227404Shselasky 468227404Shselasky ptr->bLength = LIBUSB_DT_BOS_SIZE; 469227404Shselasky ptr->bDescriptorType = dtype; 470227404Shselasky ptr->wTotalLength = ((const uint8_t *)buf)[2] | 471227404Shselasky (((const uint8_t *)buf)[3] << 8); 472227404Shselasky ptr->bNumDeviceCapabilities = ((const uint8_t *)buf)[4]; 473227404Shselasky ptr->usb_2_0_ext_cap = NULL; 474227404Shselasky ptr->ss_usb_cap = NULL; 475328142Skevans ptr->dev_capability = calloc(ptr->bNumDeviceCapabilities, sizeof(void *)); 476328142Skevans if (ptr->dev_capability == NULL) { 477328142Skevans free(ptr); 478328142Skevans return (LIBUSB_ERROR_NO_MEM); 479328142Skevans } 480227404Shselasky 481227404Shselasky dcap_20 = (void *)(ptr + 1); 482227404Shselasky ss_cap = (void *)(dcap_20 + 1); 483227404Shselasky } 484227404Shselasky if (dlen >= 3 && 485227404Shselasky ptr != NULL && 486227404Shselasky dtype == LIBUSB_DT_DEVICE_CAPABILITY) { 487328142Skevans if (index != ptr->bNumDeviceCapabilities) { 488328142Skevans ptr->dev_capability[index] = malloc(dlen); 489328142Skevans if (ptr->dev_capability[index] == NULL) { 490328142Skevans libusb_free_bos_descriptor(ptr); 491328142Skevans return LIBUSB_ERROR_NO_MEM; 492328142Skevans } 493328142Skevans memcpy(ptr->dev_capability[index], buf, dlen); 494328142Skevans index++; 495328142Skevans } 496227404Shselasky switch (((const uint8_t *)buf)[2]) { 497227404Shselasky case LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY: 498234491Shselasky if (ptr->usb_2_0_ext_cap != NULL || dcap_20 == NULL) 499227404Shselasky break; 500227404Shselasky if (dlen < LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE) 501227404Shselasky break; 502227404Shselasky 503227404Shselasky ptr->usb_2_0_ext_cap = dcap_20; 504227404Shselasky 505227404Shselasky dcap_20->bLength = LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE; 506227404Shselasky dcap_20->bDescriptorType = dtype; 507227404Shselasky dcap_20->bDevCapabilityType = ((const uint8_t *)buf)[2]; 508227404Shselasky dcap_20->bmAttributes = ((const uint8_t *)buf)[3] | 509227404Shselasky (((const uint8_t *)buf)[4] << 8) | 510227404Shselasky (((const uint8_t *)buf)[5] << 16) | 511227404Shselasky (((const uint8_t *)buf)[6] << 24); 512227404Shselasky break; 513227404Shselasky 514227404Shselasky case LIBUSB_SS_USB_DEVICE_CAPABILITY: 515234491Shselasky if (ptr->ss_usb_cap != NULL || ss_cap == NULL) 516227404Shselasky break; 517227404Shselasky if (dlen < LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE) 518227404Shselasky break; 519227404Shselasky 520227404Shselasky ptr->ss_usb_cap = ss_cap; 521227404Shselasky 522227404Shselasky ss_cap->bLength = LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE; 523227404Shselasky ss_cap->bDescriptorType = dtype; 524227404Shselasky ss_cap->bDevCapabilityType = ((const uint8_t *)buf)[2]; 525227404Shselasky ss_cap->bmAttributes = ((const uint8_t *)buf)[3]; 526227404Shselasky ss_cap->wSpeedSupported = ((const uint8_t *)buf)[4] | 527227404Shselasky (((const uint8_t *)buf)[5] << 8); 528227404Shselasky ss_cap->bFunctionalitySupport = ((const uint8_t *)buf)[6]; 529227404Shselasky ss_cap->bU1DevExitLat = ((const uint8_t *)buf)[7]; 530227404Shselasky ss_cap->wU2DevExitLat = ((const uint8_t *)buf)[8] | 531227404Shselasky (((const uint8_t *)buf)[9] << 8); 532227404Shselasky break; 533227404Shselasky 534227404Shselasky default: 535227404Shselasky break; 536227404Shselasky } 537227404Shselasky } 538227404Shselasky 539227404Shselasky buf = ((const uint8_t *)buf) + dlen; 540227404Shselasky len -= dlen; 541227404Shselasky } 542328142Skevans 543328142Skevans if (ptr != NULL) { 544328142Skevans ptr->bNumDeviceCapabilities = index; 545227404Shselasky return (0); /* success */ 546328142Skevans } 547227404Shselasky 548227404Shselasky return (LIBUSB_ERROR_IO); 549227404Shselasky} 550227404Shselasky 551227404Shselaskyvoid 552227404Shselaskylibusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) 553227404Shselasky{ 554328142Skevans uint8_t i; 555328142Skevans 556227404Shselasky if (bos == NULL) 557227404Shselasky return; 558227404Shselasky 559328142Skevans for (i = 0; i != bos->bNumDeviceCapabilities; i++) 560328142Skevans free(bos->dev_capability[i]); 561328142Skevans free(bos->dev_capability); 562227404Shselasky free(bos); 563227404Shselasky} 564301968Shselasky 565301968Shselaskyint 566301968Shselaskylibusb_get_bos_descriptor(libusb_device_handle *handle, 567301968Shselasky struct libusb_bos_descriptor **bos) 568301968Shselasky{ 569301968Shselasky uint8_t bos_header[LIBUSB_DT_BOS_SIZE] = {0}; 570301968Shselasky uint16_t wTotalLength; 571301968Shselasky uint8_t *bos_data; 572301968Shselasky int err; 573301968Shselasky 574301968Shselasky err = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, 575301968Shselasky bos_header, sizeof(bos_header)); 576301968Shselasky if (err < 0) 577301968Shselasky return (err); 578301968Shselasky 579301968Shselasky wTotalLength = bos_header[2] | (bos_header[3] << 8); 580301968Shselasky if (wTotalLength < LIBUSB_DT_BOS_SIZE) 581301968Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 582301968Shselasky 583301968Shselasky bos_data = calloc(wTotalLength, 1); 584301968Shselasky if (bos_data == NULL) 585301968Shselasky return (LIBUSB_ERROR_NO_MEM); 586301968Shselasky 587301968Shselasky err = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, 588301968Shselasky bos_data, wTotalLength); 589301968Shselasky if (err < 0) 590301968Shselasky goto done; 591301968Shselasky 592301968Shselasky /* avoid descriptor length mismatches */ 593301968Shselasky bos_data[2] = (wTotalLength & 0xFF); 594301968Shselasky bos_data[3] = (wTotalLength >> 8); 595301968Shselasky 596301968Shselasky err = libusb_parse_bos_descriptor(bos_data, wTotalLength, bos); 597301968Shselaskydone: 598301968Shselasky free(bos_data); 599301968Shselasky return (err); 600301968Shselasky} 601301968Shselasky 602301968Shselaskyint 603301968Shselaskylibusb_get_usb_2_0_extension_descriptor(struct libusb_context *ctx, 604301968Shselasky struct libusb_bos_dev_capability_descriptor *dev_cap, 605301968Shselasky struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension) 606301968Shselasky{ 607301968Shselasky struct libusb_usb_2_0_extension_descriptor *desc; 608301968Shselasky 609301968Shselasky if (dev_cap == NULL || usb_2_0_extension == NULL || 610301968Shselasky dev_cap->bDevCapabilityType != LIBUSB_BT_USB_2_0_EXTENSION) 611301968Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 612301968Shselasky if (dev_cap->bLength < LIBUSB_BT_USB_2_0_EXTENSION_SIZE) 613301968Shselasky return (LIBUSB_ERROR_IO); 614301968Shselasky 615301968Shselasky desc = malloc(sizeof(*desc)); 616301968Shselasky if (desc == NULL) 617301968Shselasky return (LIBUSB_ERROR_NO_MEM); 618301968Shselasky 619301968Shselasky desc->bLength = LIBUSB_BT_USB_2_0_EXTENSION_SIZE; 620301968Shselasky desc->bDescriptorType = dev_cap->bDescriptorType; 621301968Shselasky desc->bDevCapabilityType = dev_cap->bDevCapabilityType; 622301968Shselasky desc->bmAttributes = 623301968Shselasky (dev_cap->dev_capability_data[0]) | 624301968Shselasky (dev_cap->dev_capability_data[1] << 8) | 625301968Shselasky (dev_cap->dev_capability_data[2] << 16) | 626301968Shselasky (dev_cap->dev_capability_data[3] << 24); 627301968Shselasky 628301968Shselasky *usb_2_0_extension = desc; 629301968Shselasky return (0); 630301968Shselasky} 631301968Shselasky 632301968Shselaskyvoid 633301968Shselaskylibusb_free_usb_2_0_extension_descriptor( 634301968Shselasky struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension) 635301968Shselasky{ 636301968Shselasky 637301968Shselasky free(usb_2_0_extension); 638301968Shselasky} 639301968Shselasky 640301968Shselaskyint 641301968Shselaskylibusb_get_ss_usb_device_capability_descriptor(struct libusb_context *ctx, 642301968Shselasky struct libusb_bos_dev_capability_descriptor *dev_cap, 643301968Shselasky struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_capability) 644301968Shselasky{ 645301968Shselasky struct libusb_ss_usb_device_capability_descriptor *desc; 646301968Shselasky 647301968Shselasky if (dev_cap == NULL || ss_usb_device_capability == NULL || 648301968Shselasky dev_cap->bDevCapabilityType != LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) 649301968Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 650301968Shselasky if (dev_cap->bLength < LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) 651301968Shselasky return (LIBUSB_ERROR_IO); 652301968Shselasky 653301968Shselasky desc = malloc(sizeof(*desc)); 654301968Shselasky if (desc == NULL) 655301968Shselasky return (LIBUSB_ERROR_NO_MEM); 656301968Shselasky 657301968Shselasky desc->bLength = LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE; 658301968Shselasky desc->bDescriptorType = dev_cap->bDescriptorType; 659301968Shselasky desc->bDevCapabilityType = dev_cap->bDevCapabilityType; 660301968Shselasky desc->bmAttributes = dev_cap->dev_capability_data[0]; 661301968Shselasky desc->wSpeedSupported = dev_cap->dev_capability_data[1] | 662301968Shselasky (dev_cap->dev_capability_data[2] << 8); 663301968Shselasky desc->bFunctionalitySupport = dev_cap->dev_capability_data[3]; 664301968Shselasky desc->bU1DevExitLat = dev_cap->dev_capability_data[4]; 665301968Shselasky desc->wU2DevExitLat = dev_cap->dev_capability_data[5] | 666301968Shselasky (dev_cap->dev_capability_data[6] << 8); 667301968Shselasky 668301968Shselasky *ss_usb_device_capability = desc; 669301968Shselasky return (0); 670301968Shselasky} 671301968Shselasky 672301968Shselaskyvoid 673301968Shselaskylibusb_free_ss_usb_device_capability_descriptor( 674301968Shselasky struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_capability) 675301968Shselasky{ 676301968Shselasky 677301968Shselasky free(ss_usb_device_capability); 678301968Shselasky} 679301968Shselasky 680301968Shselaskyint 681301968Shselaskylibusb_get_container_id_descriptor(struct libusb_context *ctx, 682301968Shselasky struct libusb_bos_dev_capability_descriptor *dev_cap, 683301968Shselasky struct libusb_container_id_descriptor **container_id) 684301968Shselasky{ 685301968Shselasky struct libusb_container_id_descriptor *desc; 686301968Shselasky 687301968Shselasky if (dev_cap == NULL || container_id == NULL || 688301968Shselasky dev_cap->bDevCapabilityType != LIBUSB_BT_CONTAINER_ID) 689301968Shselasky return (LIBUSB_ERROR_INVALID_PARAM); 690301968Shselasky if (dev_cap->bLength < LIBUSB_BT_CONTAINER_ID_SIZE) 691301968Shselasky return (LIBUSB_ERROR_IO); 692301968Shselasky 693301968Shselasky desc = malloc(sizeof(*desc)); 694301968Shselasky if (desc == NULL) 695301968Shselasky return (LIBUSB_ERROR_NO_MEM); 696301968Shselasky 697301968Shselasky desc->bLength = LIBUSB_BT_CONTAINER_ID_SIZE; 698301968Shselasky desc->bDescriptorType = dev_cap->bDescriptorType; 699301968Shselasky desc->bDevCapabilityType = dev_cap->bDevCapabilityType; 700301968Shselasky desc->bReserved = dev_cap->dev_capability_data[0]; 701301968Shselasky memcpy(desc->ContainerID, dev_cap->dev_capability_data + 1, 702301968Shselasky sizeof(desc->ContainerID)); 703301968Shselasky 704301968Shselasky *container_id = desc; 705301968Shselasky return (0); 706301968Shselasky} 707301968Shselasky 708301968Shselaskyvoid 709301968Shselaskylibusb_free_container_id_descriptor( 710301968Shselasky struct libusb_container_id_descriptor *container_id) 711301968Shselasky{ 712301968Shselasky 713301968Shselasky free(container_id); 714301968Shselasky} 715