18c8fff31SAndrew Thompson /* $FreeBSD$ */ 28c8fff31SAndrew Thompson /*- 38c8fff31SAndrew Thompson * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 48c8fff31SAndrew Thompson * 58c8fff31SAndrew Thompson * Redistribution and use in source and binary forms, with or without 68c8fff31SAndrew Thompson * modification, are permitted provided that the following conditions 78c8fff31SAndrew Thompson * are met: 88c8fff31SAndrew Thompson * 1. Redistributions of source code must retain the above copyright 98c8fff31SAndrew Thompson * notice, this list of conditions and the following disclaimer. 108c8fff31SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 118c8fff31SAndrew Thompson * notice, this list of conditions and the following disclaimer in the 128c8fff31SAndrew Thompson * documentation and/or other materials provided with the distribution. 138c8fff31SAndrew Thompson * 148c8fff31SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 158c8fff31SAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 168c8fff31SAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 178c8fff31SAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 188c8fff31SAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 198c8fff31SAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 208c8fff31SAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 218c8fff31SAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 228c8fff31SAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 238c8fff31SAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 248c8fff31SAndrew Thompson * SUCH DAMAGE. 258c8fff31SAndrew Thompson */ 268c8fff31SAndrew Thompson 27390065b1SAlfred Perlstein #include <sys/queue.h> 288c8fff31SAndrew Thompson 29f3cba95cSWojciech A. Koszek #include <stdio.h> 30f3cba95cSWojciech A. Koszek #include <stdlib.h> 31f3cba95cSWojciech A. Koszek 329c087c5aSAndrew Thompson #define libusb_device_handle libusb20_device 339c087c5aSAndrew Thompson 348c8fff31SAndrew Thompson #include "libusb20.h" 358c8fff31SAndrew Thompson #include "libusb20_desc.h" 368c8fff31SAndrew Thompson #include "libusb20_int.h" 378c8fff31SAndrew Thompson #include "libusb.h" 388c8fff31SAndrew Thompson #include "libusb10.h" 398c8fff31SAndrew Thompson 40ccef4ddfSAndrew Thompson #define N_ALIGN(n) (-((-(n)) & (-8UL))) 41ccef4ddfSAndrew Thompson 428c8fff31SAndrew Thompson /* USB descriptors */ 438c8fff31SAndrew Thompson 448c8fff31SAndrew Thompson int 458c8fff31SAndrew Thompson libusb_get_device_descriptor(libusb_device *dev, 468c8fff31SAndrew Thompson struct libusb_device_descriptor *desc) 478c8fff31SAndrew Thompson { 488c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 498c8fff31SAndrew Thompson struct libusb20_device *pdev; 508c8fff31SAndrew Thompson 518c8fff31SAndrew Thompson if ((dev == NULL) || (desc == NULL)) 528c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 538c8fff31SAndrew Thompson 548c8fff31SAndrew Thompson pdev = dev->os_priv; 558c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 568c8fff31SAndrew Thompson 578c8fff31SAndrew Thompson desc->bLength = pdesc->bLength; 588c8fff31SAndrew Thompson desc->bDescriptorType = pdesc->bDescriptorType; 598c8fff31SAndrew Thompson desc->bcdUSB = pdesc->bcdUSB; 608c8fff31SAndrew Thompson desc->bDeviceClass = pdesc->bDeviceClass; 618c8fff31SAndrew Thompson desc->bDeviceSubClass = pdesc->bDeviceSubClass; 628c8fff31SAndrew Thompson desc->bDeviceProtocol = pdesc->bDeviceProtocol; 638c8fff31SAndrew Thompson desc->bMaxPacketSize0 = pdesc->bMaxPacketSize0; 648c8fff31SAndrew Thompson desc->idVendor = pdesc->idVendor; 658c8fff31SAndrew Thompson desc->idProduct = pdesc->idProduct; 668c8fff31SAndrew Thompson desc->bcdDevice = pdesc->bcdDevice; 678c8fff31SAndrew Thompson desc->iManufacturer = pdesc->iManufacturer; 688c8fff31SAndrew Thompson desc->iProduct = pdesc->iProduct; 698c8fff31SAndrew Thompson desc->iSerialNumber = pdesc->iSerialNumber; 708c8fff31SAndrew Thompson desc->bNumConfigurations = pdesc->bNumConfigurations; 718c8fff31SAndrew Thompson 728c8fff31SAndrew Thompson return (0); 738c8fff31SAndrew Thompson } 748c8fff31SAndrew Thompson 758c8fff31SAndrew Thompson int 768c8fff31SAndrew Thompson libusb_get_active_config_descriptor(libusb_device *dev, 778c8fff31SAndrew Thompson struct libusb_config_descriptor **config) 788c8fff31SAndrew Thompson { 798c8fff31SAndrew Thompson struct libusb20_device *pdev; 80390065b1SAlfred Perlstein uint8_t config_index; 818c8fff31SAndrew Thompson 828c8fff31SAndrew Thompson pdev = dev->os_priv; 83390065b1SAlfred Perlstein config_index = libusb20_dev_get_config_index(pdev); 848c8fff31SAndrew Thompson 85390065b1SAlfred Perlstein return (libusb_get_config_descriptor(dev, config_index, config)); 868c8fff31SAndrew Thompson } 878c8fff31SAndrew Thompson 888c8fff31SAndrew Thompson int 898c8fff31SAndrew Thompson libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, 908c8fff31SAndrew Thompson struct libusb_config_descriptor **config) 918c8fff31SAndrew Thompson { 928c8fff31SAndrew Thompson struct libusb20_device *pdev; 938c8fff31SAndrew Thompson struct libusb20_config *pconf; 948c8fff31SAndrew Thompson struct libusb20_interface *pinf; 958c8fff31SAndrew Thompson struct libusb20_endpoint *pend; 96390065b1SAlfred Perlstein struct libusb_config_descriptor *pconfd; 97390065b1SAlfred Perlstein struct libusb_interface_descriptor *ifd; 98390065b1SAlfred Perlstein struct libusb_endpoint_descriptor *endd; 99390065b1SAlfred Perlstein uint8_t *pextra; 100390065b1SAlfred Perlstein uint16_t nextra; 101390065b1SAlfred Perlstein uint8_t nif; 102390065b1SAlfred Perlstein uint8_t nep; 103390065b1SAlfred Perlstein uint8_t nalt; 104390065b1SAlfred Perlstein uint8_t i; 105390065b1SAlfred Perlstein uint8_t j; 106390065b1SAlfred Perlstein uint8_t k; 1078c8fff31SAndrew Thompson 1088c8fff31SAndrew Thompson if (dev == NULL || config == NULL) 1098c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 1108c8fff31SAndrew Thompson 111390065b1SAlfred Perlstein *config = NULL; 112390065b1SAlfred Perlstein 1138c8fff31SAndrew Thompson pdev = dev->os_priv; 1148c8fff31SAndrew Thompson pconf = libusb20_dev_alloc_config(pdev, config_index); 1158c8fff31SAndrew Thompson 1168c8fff31SAndrew Thompson if (pconf == NULL) 1178c8fff31SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 1188c8fff31SAndrew Thompson 1198c8fff31SAndrew Thompson nalt = nif = pconf->num_interface; 120390065b1SAlfred Perlstein nep = 0; 121ccef4ddfSAndrew Thompson nextra = N_ALIGN(pconf->extra.len); 122390065b1SAlfred Perlstein 1238c8fff31SAndrew Thompson for (i = 0; i < nif; i++) { 124390065b1SAlfred Perlstein 125390065b1SAlfred Perlstein pinf = pconf->interface + i; 126ccef4ddfSAndrew Thompson nextra += N_ALIGN(pinf->extra.len); 127390065b1SAlfred Perlstein nep += pinf->num_endpoints; 128390065b1SAlfred Perlstein k = pinf->num_endpoints; 129390065b1SAlfred Perlstein pend = pinf->endpoints; 130390065b1SAlfred Perlstein while (k--) { 131ccef4ddfSAndrew Thompson nextra += N_ALIGN(pend->extra.len); 132390065b1SAlfred Perlstein pend++; 1338c8fff31SAndrew Thompson } 1348c8fff31SAndrew Thompson 135390065b1SAlfred Perlstein j = pinf->num_altsetting; 136390065b1SAlfred Perlstein nalt += pinf->num_altsetting; 137390065b1SAlfred Perlstein pinf = pinf->altsetting; 138390065b1SAlfred Perlstein while (j--) { 139ccef4ddfSAndrew Thompson nextra += N_ALIGN(pinf->extra.len); 140390065b1SAlfred Perlstein nep += pinf->num_endpoints; 141390065b1SAlfred Perlstein k = pinf->num_endpoints; 142390065b1SAlfred Perlstein pend = pinf->endpoints; 143390065b1SAlfred Perlstein while (k--) { 144ccef4ddfSAndrew Thompson nextra += N_ALIGN(pend->extra.len); 145390065b1SAlfred Perlstein pend++; 146390065b1SAlfred Perlstein } 147390065b1SAlfred Perlstein pinf++; 148390065b1SAlfred Perlstein } 149390065b1SAlfred Perlstein } 150390065b1SAlfred Perlstein 151390065b1SAlfred Perlstein nextra = nextra + 152390065b1SAlfred Perlstein (1 * sizeof(libusb_config_descriptor)) + 1538c8fff31SAndrew Thompson (nif * sizeof(libusb_interface)) + 1548c8fff31SAndrew Thompson (nalt * sizeof(libusb_interface_descriptor)) + 155390065b1SAlfred Perlstein (nep * sizeof(libusb_endpoint_descriptor)); 156390065b1SAlfred Perlstein 157ccef4ddfSAndrew Thompson nextra = N_ALIGN(nextra); 158ccef4ddfSAndrew Thompson 159390065b1SAlfred Perlstein pconfd = malloc(nextra); 160390065b1SAlfred Perlstein 161390065b1SAlfred Perlstein if (pconfd == NULL) { 1628c8fff31SAndrew Thompson free(pconf); 1638c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 1648c8fff31SAndrew Thompson } 165ccef4ddfSAndrew Thompson /* make sure memory is initialised */ 166390065b1SAlfred Perlstein memset(pconfd, 0, nextra); 1678c8fff31SAndrew Thompson 168ccef4ddfSAndrew Thompson pconfd->interface = (libusb_interface *) (pconfd + 1); 1698c8fff31SAndrew Thompson 170390065b1SAlfred Perlstein ifd = (libusb_interface_descriptor *) (pconfd->interface + nif); 171390065b1SAlfred Perlstein endd = (libusb_endpoint_descriptor *) (ifd + nalt); 172390065b1SAlfred Perlstein pextra = (uint8_t *)(endd + nep); 173390065b1SAlfred Perlstein 174390065b1SAlfred Perlstein /* fill in config descriptor */ 175390065b1SAlfred Perlstein 176390065b1SAlfred Perlstein pconfd->bLength = pconf->desc.bLength; 177390065b1SAlfred Perlstein pconfd->bDescriptorType = pconf->desc.bDescriptorType; 178390065b1SAlfred Perlstein pconfd->wTotalLength = pconf->desc.wTotalLength; 179390065b1SAlfred Perlstein pconfd->bNumInterfaces = pconf->desc.bNumInterfaces; 180390065b1SAlfred Perlstein pconfd->bConfigurationValue = pconf->desc.bConfigurationValue; 181390065b1SAlfred Perlstein pconfd->iConfiguration = pconf->desc.iConfiguration; 182390065b1SAlfred Perlstein pconfd->bmAttributes = pconf->desc.bmAttributes; 183390065b1SAlfred Perlstein pconfd->MaxPower = pconf->desc.bMaxPower; 184390065b1SAlfred Perlstein 185390065b1SAlfred Perlstein if (pconf->extra.len != 0) { 186390065b1SAlfred Perlstein pconfd->extra_length = pconf->extra.len; 187390065b1SAlfred Perlstein pconfd->extra = pextra; 188390065b1SAlfred Perlstein memcpy(pextra, pconf->extra.ptr, pconfd->extra_length); 189ccef4ddfSAndrew Thompson pextra += N_ALIGN(pconfd->extra_length); 1908c8fff31SAndrew Thompson } 191390065b1SAlfred Perlstein /* setup all interface and endpoint pointers */ 192390065b1SAlfred Perlstein 193390065b1SAlfred Perlstein for (i = 0; i < nif; i++) { 194390065b1SAlfred Perlstein 195390065b1SAlfred Perlstein pconfd->interface[i].altsetting = ifd; 196390065b1SAlfred Perlstein ifd->endpoint = endd; 197390065b1SAlfred Perlstein endd += pconf->interface[i].num_endpoints; 198390065b1SAlfred Perlstein ifd++; 199390065b1SAlfred Perlstein 200390065b1SAlfred Perlstein for (j = 0; j < pconf->interface[i].num_altsetting; j++) { 201390065b1SAlfred Perlstein ifd->endpoint = endd; 202390065b1SAlfred Perlstein endd += pconf->interface[i].altsetting[j].num_endpoints; 203390065b1SAlfred Perlstein ifd++; 2048c8fff31SAndrew Thompson } 2058c8fff31SAndrew Thompson } 2068c8fff31SAndrew Thompson 207390065b1SAlfred Perlstein /* fill in all interface and endpoint data */ 2088c8fff31SAndrew Thompson 2098c8fff31SAndrew Thompson for (i = 0; i < nif; i++) { 2108c8fff31SAndrew Thompson pinf = &pconf->interface[i]; 211390065b1SAlfred Perlstein pconfd->interface[i].num_altsetting = pinf->num_altsetting + 1; 212390065b1SAlfred Perlstein for (j = 0; j < pconfd->interface[i].num_altsetting; j++) { 2138c8fff31SAndrew Thompson if (j != 0) 2148c8fff31SAndrew Thompson pinf = &pconf->interface[i].altsetting[j - 1]; 215390065b1SAlfred Perlstein ifd = &pconfd->interface[i].altsetting[j]; 2168c8fff31SAndrew Thompson ifd->bLength = pinf->desc.bLength; 2178c8fff31SAndrew Thompson ifd->bDescriptorType = pinf->desc.bDescriptorType; 2188c8fff31SAndrew Thompson ifd->bInterfaceNumber = pinf->desc.bInterfaceNumber; 2198c8fff31SAndrew Thompson ifd->bAlternateSetting = pinf->desc.bAlternateSetting; 2208c8fff31SAndrew Thompson ifd->bNumEndpoints = pinf->desc.bNumEndpoints; 2218c8fff31SAndrew Thompson ifd->bInterfaceClass = pinf->desc.bInterfaceClass; 2228c8fff31SAndrew Thompson ifd->bInterfaceSubClass = pinf->desc.bInterfaceSubClass; 2238c8fff31SAndrew Thompson ifd->bInterfaceProtocol = pinf->desc.bInterfaceProtocol; 2248c8fff31SAndrew Thompson ifd->iInterface = pinf->desc.iInterface; 225390065b1SAlfred Perlstein if (pinf->extra.len != 0) { 2268c8fff31SAndrew Thompson ifd->extra_length = pinf->extra.len; 227390065b1SAlfred Perlstein ifd->extra = pextra; 228390065b1SAlfred Perlstein memcpy(pextra, pinf->extra.ptr, pinf->extra.len); 229ccef4ddfSAndrew Thompson pextra += N_ALIGN(pinf->extra.len); 230390065b1SAlfred Perlstein } 2318c8fff31SAndrew Thompson for (k = 0; k < pinf->num_endpoints; k++) { 2328c8fff31SAndrew Thompson pend = &pinf->endpoints[k]; 2338c8fff31SAndrew Thompson endd = &ifd->endpoint[k]; 2348c8fff31SAndrew Thompson endd->bLength = pend->desc.bLength; 2358c8fff31SAndrew Thompson endd->bDescriptorType = pend->desc.bDescriptorType; 2368c8fff31SAndrew Thompson endd->bEndpointAddress = pend->desc.bEndpointAddress; 2378c8fff31SAndrew Thompson endd->bmAttributes = pend->desc.bmAttributes; 2388c8fff31SAndrew Thompson endd->wMaxPacketSize = pend->desc.wMaxPacketSize; 2398c8fff31SAndrew Thompson endd->bInterval = pend->desc.bInterval; 2408c8fff31SAndrew Thompson endd->bRefresh = pend->desc.bRefresh; 2418c8fff31SAndrew Thompson endd->bSynchAddress = pend->desc.bSynchAddress; 242390065b1SAlfred Perlstein if (pend->extra.len != 0) { 2438c8fff31SAndrew Thompson endd->extra_length = pend->extra.len; 244390065b1SAlfred Perlstein endd->extra = pextra; 245390065b1SAlfred Perlstein memcpy(pextra, pend->extra.ptr, pend->extra.len); 246ccef4ddfSAndrew Thompson pextra += N_ALIGN(pend->extra.len); 247390065b1SAlfred Perlstein } 2488c8fff31SAndrew Thompson } 2498c8fff31SAndrew Thompson } 2508c8fff31SAndrew Thompson } 2518c8fff31SAndrew Thompson 2528c8fff31SAndrew Thompson free(pconf); 253390065b1SAlfred Perlstein 254390065b1SAlfred Perlstein *config = pconfd; 255390065b1SAlfred Perlstein 256390065b1SAlfred Perlstein return (0); /* success */ 2578c8fff31SAndrew Thompson } 2588c8fff31SAndrew Thompson 2598c8fff31SAndrew Thompson int 2608c8fff31SAndrew Thompson libusb_get_config_descriptor_by_value(libusb_device *dev, 2618c8fff31SAndrew Thompson uint8_t bConfigurationValue, struct libusb_config_descriptor **config) 2628c8fff31SAndrew Thompson { 2638c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 2648c8fff31SAndrew Thompson struct libusb20_device *pdev; 2658c8fff31SAndrew Thompson int i; 266390065b1SAlfred Perlstein int err; 2678c8fff31SAndrew Thompson 2688c8fff31SAndrew Thompson if (dev == NULL || config == NULL) 2698c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 2708c8fff31SAndrew Thompson 2718c8fff31SAndrew Thompson pdev = dev->os_priv; 2728c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 2738c8fff31SAndrew Thompson 2748c8fff31SAndrew Thompson for (i = 0; i < pdesc->bNumConfigurations; i++) { 275390065b1SAlfred Perlstein err = libusb_get_config_descriptor(dev, i, config); 276390065b1SAlfred Perlstein if (err) 277390065b1SAlfred Perlstein return (err); 2788c8fff31SAndrew Thompson 279390065b1SAlfred Perlstein if ((*config)->bConfigurationValue == bConfigurationValue) 280390065b1SAlfred Perlstein return (0); /* success */ 281390065b1SAlfred Perlstein 282390065b1SAlfred Perlstein libusb_free_config_descriptor(*config); 2838c8fff31SAndrew Thompson } 2848c8fff31SAndrew Thompson 285390065b1SAlfred Perlstein *config = NULL; 286390065b1SAlfred Perlstein 2878c8fff31SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 2888c8fff31SAndrew Thompson } 2898c8fff31SAndrew Thompson 2908c8fff31SAndrew Thompson void 2918c8fff31SAndrew Thompson libusb_free_config_descriptor(struct libusb_config_descriptor *config) 2928c8fff31SAndrew Thompson { 2938c8fff31SAndrew Thompson free(config); 2948c8fff31SAndrew Thompson } 2958c8fff31SAndrew Thompson 2968c8fff31SAndrew Thompson int 297390065b1SAlfred Perlstein libusb_get_string_descriptor_ascii(libusb_device_handle *pdev, 2988c8fff31SAndrew Thompson uint8_t desc_index, unsigned char *data, int length) 2998c8fff31SAndrew Thompson { 300390065b1SAlfred Perlstein if (pdev == NULL || data == NULL || length < 1) 301*4c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 3028c8fff31SAndrew Thompson 3034eb5923dSHans Petter Selasky if (length > 65535) 3044eb5923dSHans Petter Selasky length = 65535; 3054eb5923dSHans Petter Selasky 306390065b1SAlfred Perlstein /* put some default data into the destination buffer */ 307390065b1SAlfred Perlstein data[0] = 0; 308390065b1SAlfred Perlstein 3098c8fff31SAndrew Thompson if (libusb20_dev_req_string_simple_sync(pdev, desc_index, 3108c8fff31SAndrew Thompson data, length) == 0) 3118c8fff31SAndrew Thompson return (strlen(data)); 3128c8fff31SAndrew Thompson 3138c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 3148c8fff31SAndrew Thompson } 315ccef4ddfSAndrew Thompson 316ccef4ddfSAndrew Thompson int 317ccef4ddfSAndrew Thompson libusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, 318ccef4ddfSAndrew Thompson uint8_t desc_index, uint8_t *data, int length) 319ccef4ddfSAndrew Thompson { 3204eb5923dSHans Petter Selasky if (devh == NULL || data == NULL || length < 1) 321*4c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 3224eb5923dSHans Petter Selasky 3234eb5923dSHans Petter Selasky if (length > 65535) 3244eb5923dSHans Petter Selasky length = 65535; 3254eb5923dSHans Petter Selasky 326ccef4ddfSAndrew Thompson return (libusb_control_transfer(devh, LIBUSB_ENDPOINT_IN, 327ccef4ddfSAndrew Thompson LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, 328ccef4ddfSAndrew Thompson length, 1000)); 329ccef4ddfSAndrew Thompson } 330*4c0392e6SHans Petter Selasky 331*4c0392e6SHans Petter Selasky int 332*4c0392e6SHans Petter Selasky libusb_parse_ss_endpoint_comp(const void *buf, int len, 333*4c0392e6SHans Petter Selasky struct libusb_ss_endpoint_companion_descriptor **ep_comp) 334*4c0392e6SHans Petter Selasky { 335*4c0392e6SHans Petter Selasky if (buf == NULL || ep_comp == NULL || len < 1) 336*4c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 337*4c0392e6SHans Petter Selasky 338*4c0392e6SHans Petter Selasky if (len > 65535) 339*4c0392e6SHans Petter Selasky len = 65535; 340*4c0392e6SHans Petter Selasky 341*4c0392e6SHans Petter Selasky *ep_comp = NULL; 342*4c0392e6SHans Petter Selasky 343*4c0392e6SHans Petter Selasky while (len != 0) { 344*4c0392e6SHans Petter Selasky uint8_t dlen; 345*4c0392e6SHans Petter Selasky uint8_t dtype; 346*4c0392e6SHans Petter Selasky 347*4c0392e6SHans Petter Selasky dlen = ((const uint8_t *)buf)[0]; 348*4c0392e6SHans Petter Selasky dtype = ((const uint8_t *)buf)[1]; 349*4c0392e6SHans Petter Selasky 350*4c0392e6SHans Petter Selasky if (dlen < 2 || dlen > len) 351*4c0392e6SHans Petter Selasky break; 352*4c0392e6SHans Petter Selasky 353*4c0392e6SHans Petter Selasky if (dlen >= LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE && 354*4c0392e6SHans Petter Selasky dtype == LIBUSB_DT_SS_ENDPOINT_COMPANION) { 355*4c0392e6SHans Petter Selasky struct libusb_ss_endpoint_companion_descriptor *ptr; 356*4c0392e6SHans Petter Selasky 357*4c0392e6SHans Petter Selasky ptr = malloc(sizeof(*ptr)); 358*4c0392e6SHans Petter Selasky if (ptr == NULL) 359*4c0392e6SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 360*4c0392e6SHans Petter Selasky 361*4c0392e6SHans Petter Selasky ptr->bLength = LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE; 362*4c0392e6SHans Petter Selasky ptr->bDescriptorType = dtype; 363*4c0392e6SHans Petter Selasky ptr->bMaxBurst = ((const uint8_t *)buf)[2]; 364*4c0392e6SHans Petter Selasky ptr->bmAttributes = ((const uint8_t *)buf)[3]; 365*4c0392e6SHans Petter Selasky ptr->wBytesPerInterval = ((const uint8_t *)buf)[4] | 366*4c0392e6SHans Petter Selasky (((const uint8_t *)buf)[5] << 8); 367*4c0392e6SHans Petter Selasky 368*4c0392e6SHans Petter Selasky *ep_comp = ptr; 369*4c0392e6SHans Petter Selasky 370*4c0392e6SHans Petter Selasky return (0); /* success */ 371*4c0392e6SHans Petter Selasky } 372*4c0392e6SHans Petter Selasky 373*4c0392e6SHans Petter Selasky buf = ((const uint8_t *)buf) + dlen; 374*4c0392e6SHans Petter Selasky len -= dlen; 375*4c0392e6SHans Petter Selasky } 376*4c0392e6SHans Petter Selasky return (LIBUSB_ERROR_IO); 377*4c0392e6SHans Petter Selasky } 378*4c0392e6SHans Petter Selasky 379*4c0392e6SHans Petter Selasky void 380*4c0392e6SHans Petter Selasky libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp) 381*4c0392e6SHans Petter Selasky { 382*4c0392e6SHans Petter Selasky if (ep_comp == NULL) 383*4c0392e6SHans Petter Selasky return; 384*4c0392e6SHans Petter Selasky 385*4c0392e6SHans Petter Selasky free(ep_comp); 386*4c0392e6SHans Petter Selasky } 387*4c0392e6SHans Petter Selasky 388*4c0392e6SHans Petter Selasky int 389*4c0392e6SHans Petter Selasky libusb_parse_bos_descriptor(const void *buf, int len, 390*4c0392e6SHans Petter Selasky struct libusb_bos_descriptor **bos) 391*4c0392e6SHans Petter Selasky { 392*4c0392e6SHans Petter Selasky struct libusb_bos_descriptor *ptr; 393*4c0392e6SHans Petter Selasky struct libusb_usb_2_0_device_capability_descriptor *dcap_20; 394*4c0392e6SHans Petter Selasky struct libusb_ss_usb_device_capability_descriptor *ss_cap; 395*4c0392e6SHans Petter Selasky 396*4c0392e6SHans Petter Selasky if (buf == NULL || bos == NULL || len < 1) 397*4c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 398*4c0392e6SHans Petter Selasky 399*4c0392e6SHans Petter Selasky if (len > 65535) 400*4c0392e6SHans Petter Selasky len = 65535; 401*4c0392e6SHans Petter Selasky 402*4c0392e6SHans Petter Selasky *bos = ptr = NULL; 403*4c0392e6SHans Petter Selasky 404*4c0392e6SHans Petter Selasky while (len != 0) { 405*4c0392e6SHans Petter Selasky uint8_t dlen; 406*4c0392e6SHans Petter Selasky uint8_t dtype; 407*4c0392e6SHans Petter Selasky 408*4c0392e6SHans Petter Selasky dlen = ((const uint8_t *)buf)[0]; 409*4c0392e6SHans Petter Selasky dtype = ((const uint8_t *)buf)[1]; 410*4c0392e6SHans Petter Selasky 411*4c0392e6SHans Petter Selasky if (dlen < 2 || dlen > len) 412*4c0392e6SHans Petter Selasky break; 413*4c0392e6SHans Petter Selasky 414*4c0392e6SHans Petter Selasky if (dlen >= LIBUSB_DT_BOS_SIZE && 415*4c0392e6SHans Petter Selasky dtype == LIBUSB_DT_BOS) { 416*4c0392e6SHans Petter Selasky 417*4c0392e6SHans Petter Selasky ptr = malloc(sizeof(*ptr) + sizeof(*dcap_20) + 418*4c0392e6SHans Petter Selasky sizeof(*ss_cap)); 419*4c0392e6SHans Petter Selasky 420*4c0392e6SHans Petter Selasky if (ptr == NULL) 421*4c0392e6SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 422*4c0392e6SHans Petter Selasky 423*4c0392e6SHans Petter Selasky *bos = ptr; 424*4c0392e6SHans Petter Selasky 425*4c0392e6SHans Petter Selasky ptr->bLength = LIBUSB_DT_BOS_SIZE; 426*4c0392e6SHans Petter Selasky ptr->bDescriptorType = dtype; 427*4c0392e6SHans Petter Selasky ptr->wTotalLength = ((const uint8_t *)buf)[2] | 428*4c0392e6SHans Petter Selasky (((const uint8_t *)buf)[3] << 8); 429*4c0392e6SHans Petter Selasky ptr->bNumDeviceCapabilities = ((const uint8_t *)buf)[4]; 430*4c0392e6SHans Petter Selasky ptr->usb_2_0_ext_cap = NULL; 431*4c0392e6SHans Petter Selasky ptr->ss_usb_cap = NULL; 432*4c0392e6SHans Petter Selasky 433*4c0392e6SHans Petter Selasky dcap_20 = (void *)(ptr + 1); 434*4c0392e6SHans Petter Selasky ss_cap = (void *)(dcap_20 + 1); 435*4c0392e6SHans Petter Selasky } 436*4c0392e6SHans Petter Selasky if (dlen >= 3 && 437*4c0392e6SHans Petter Selasky ptr != NULL && 438*4c0392e6SHans Petter Selasky dtype == LIBUSB_DT_DEVICE_CAPABILITY) { 439*4c0392e6SHans Petter Selasky switch (((const uint8_t *)buf)[2]) { 440*4c0392e6SHans Petter Selasky case LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY: 441*4c0392e6SHans Petter Selasky if (ptr->usb_2_0_ext_cap != NULL) 442*4c0392e6SHans Petter Selasky break; 443*4c0392e6SHans Petter Selasky if (dlen < LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE) 444*4c0392e6SHans Petter Selasky break; 445*4c0392e6SHans Petter Selasky 446*4c0392e6SHans Petter Selasky ptr->usb_2_0_ext_cap = dcap_20; 447*4c0392e6SHans Petter Selasky 448*4c0392e6SHans Petter Selasky dcap_20->bLength = LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE; 449*4c0392e6SHans Petter Selasky dcap_20->bDescriptorType = dtype; 450*4c0392e6SHans Petter Selasky dcap_20->bDevCapabilityType = ((const uint8_t *)buf)[2]; 451*4c0392e6SHans Petter Selasky dcap_20->bmAttributes = ((const uint8_t *)buf)[3] | 452*4c0392e6SHans Petter Selasky (((const uint8_t *)buf)[4] << 8) | 453*4c0392e6SHans Petter Selasky (((const uint8_t *)buf)[5] << 16) | 454*4c0392e6SHans Petter Selasky (((const uint8_t *)buf)[6] << 24); 455*4c0392e6SHans Petter Selasky break; 456*4c0392e6SHans Petter Selasky 457*4c0392e6SHans Petter Selasky case LIBUSB_SS_USB_DEVICE_CAPABILITY: 458*4c0392e6SHans Petter Selasky if (ptr->ss_usb_cap != NULL) 459*4c0392e6SHans Petter Selasky break; 460*4c0392e6SHans Petter Selasky if (dlen < LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE) 461*4c0392e6SHans Petter Selasky break; 462*4c0392e6SHans Petter Selasky 463*4c0392e6SHans Petter Selasky ptr->ss_usb_cap = ss_cap; 464*4c0392e6SHans Petter Selasky 465*4c0392e6SHans Petter Selasky ss_cap->bLength = LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE; 466*4c0392e6SHans Petter Selasky ss_cap->bDescriptorType = dtype; 467*4c0392e6SHans Petter Selasky ss_cap->bDevCapabilityType = ((const uint8_t *)buf)[2]; 468*4c0392e6SHans Petter Selasky ss_cap->bmAttributes = ((const uint8_t *)buf)[3]; 469*4c0392e6SHans Petter Selasky ss_cap->wSpeedSupported = ((const uint8_t *)buf)[4] | 470*4c0392e6SHans Petter Selasky (((const uint8_t *)buf)[5] << 8); 471*4c0392e6SHans Petter Selasky ss_cap->bFunctionalitySupport = ((const uint8_t *)buf)[6]; 472*4c0392e6SHans Petter Selasky ss_cap->bU1DevExitLat = ((const uint8_t *)buf)[7]; 473*4c0392e6SHans Petter Selasky ss_cap->wU2DevExitLat = ((const uint8_t *)buf)[8] | 474*4c0392e6SHans Petter Selasky (((const uint8_t *)buf)[9] << 8); 475*4c0392e6SHans Petter Selasky break; 476*4c0392e6SHans Petter Selasky 477*4c0392e6SHans Petter Selasky default: 478*4c0392e6SHans Petter Selasky break; 479*4c0392e6SHans Petter Selasky } 480*4c0392e6SHans Petter Selasky } 481*4c0392e6SHans Petter Selasky 482*4c0392e6SHans Petter Selasky buf = ((const uint8_t *)buf) + dlen; 483*4c0392e6SHans Petter Selasky len -= dlen; 484*4c0392e6SHans Petter Selasky } 485*4c0392e6SHans Petter Selasky if (ptr != NULL) 486*4c0392e6SHans Petter Selasky return (0); /* success */ 487*4c0392e6SHans Petter Selasky 488*4c0392e6SHans Petter Selasky return (LIBUSB_ERROR_IO); 489*4c0392e6SHans Petter Selasky } 490*4c0392e6SHans Petter Selasky 491*4c0392e6SHans Petter Selasky void 492*4c0392e6SHans Petter Selasky libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) 493*4c0392e6SHans Petter Selasky { 494*4c0392e6SHans Petter Selasky if (bos == NULL) 495*4c0392e6SHans Petter Selasky return; 496*4c0392e6SHans Petter Selasky 497*4c0392e6SHans Petter Selasky free(bos); 498*4c0392e6SHans Petter Selasky } 499