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 297*78ed0e49SHans Petter Selasky libusb_get_string_descriptor(libusb_device_handle *pdev, 298*78ed0e49SHans Petter Selasky uint8_t desc_index, uint16_t langid, unsigned char *data, 299*78ed0e49SHans Petter Selasky int length) 300*78ed0e49SHans Petter Selasky { 301*78ed0e49SHans Petter Selasky if (pdev == NULL || data == NULL || length < 1) 302*78ed0e49SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 303*78ed0e49SHans Petter Selasky 304*78ed0e49SHans Petter Selasky if (length > 65535) 305*78ed0e49SHans Petter Selasky length = 65535; 306*78ed0e49SHans Petter Selasky 307*78ed0e49SHans Petter Selasky /* put some default data into the destination buffer */ 308*78ed0e49SHans Petter Selasky data[0] = 0; 309*78ed0e49SHans Petter Selasky 310*78ed0e49SHans Petter Selasky return (libusb_control_transfer(pdev, LIBUSB_ENDPOINT_IN, 311*78ed0e49SHans Petter Selasky LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc_index, 312*78ed0e49SHans Petter Selasky langid, data, length, 1000)); 313*78ed0e49SHans Petter Selasky } 314*78ed0e49SHans Petter Selasky 315*78ed0e49SHans Petter Selasky int 316390065b1SAlfred Perlstein libusb_get_string_descriptor_ascii(libusb_device_handle *pdev, 3178c8fff31SAndrew Thompson uint8_t desc_index, unsigned char *data, int length) 3188c8fff31SAndrew Thompson { 319390065b1SAlfred Perlstein if (pdev == NULL || data == NULL || length < 1) 3204c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 3218c8fff31SAndrew Thompson 3224eb5923dSHans Petter Selasky if (length > 65535) 3234eb5923dSHans Petter Selasky length = 65535; 3244eb5923dSHans Petter Selasky 325390065b1SAlfred Perlstein /* put some default data into the destination buffer */ 326390065b1SAlfred Perlstein data[0] = 0; 327390065b1SAlfred Perlstein 3288c8fff31SAndrew Thompson if (libusb20_dev_req_string_simple_sync(pdev, desc_index, 3298c8fff31SAndrew Thompson data, length) == 0) 3308c8fff31SAndrew Thompson return (strlen(data)); 3318c8fff31SAndrew Thompson 3328c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 3338c8fff31SAndrew Thompson } 334ccef4ddfSAndrew Thompson 335ccef4ddfSAndrew Thompson int 336ccef4ddfSAndrew Thompson libusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, 337ccef4ddfSAndrew Thompson uint8_t desc_index, uint8_t *data, int length) 338ccef4ddfSAndrew Thompson { 3394eb5923dSHans Petter Selasky if (devh == NULL || data == NULL || length < 1) 3404c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 3414eb5923dSHans Petter Selasky 3424eb5923dSHans Petter Selasky if (length > 65535) 3434eb5923dSHans Petter Selasky length = 65535; 3444eb5923dSHans Petter Selasky 345ccef4ddfSAndrew Thompson return (libusb_control_transfer(devh, LIBUSB_ENDPOINT_IN, 346ccef4ddfSAndrew Thompson LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, 347ccef4ddfSAndrew Thompson length, 1000)); 348ccef4ddfSAndrew Thompson } 3494c0392e6SHans Petter Selasky 3504c0392e6SHans Petter Selasky int 3514c0392e6SHans Petter Selasky libusb_parse_ss_endpoint_comp(const void *buf, int len, 3524c0392e6SHans Petter Selasky struct libusb_ss_endpoint_companion_descriptor **ep_comp) 3534c0392e6SHans Petter Selasky { 3544c0392e6SHans Petter Selasky if (buf == NULL || ep_comp == NULL || len < 1) 3554c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 3564c0392e6SHans Petter Selasky 3574c0392e6SHans Petter Selasky if (len > 65535) 3584c0392e6SHans Petter Selasky len = 65535; 3594c0392e6SHans Petter Selasky 3604c0392e6SHans Petter Selasky *ep_comp = NULL; 3614c0392e6SHans Petter Selasky 3624c0392e6SHans Petter Selasky while (len != 0) { 3634c0392e6SHans Petter Selasky uint8_t dlen; 3644c0392e6SHans Petter Selasky uint8_t dtype; 3654c0392e6SHans Petter Selasky 3664c0392e6SHans Petter Selasky dlen = ((const uint8_t *)buf)[0]; 3674c0392e6SHans Petter Selasky dtype = ((const uint8_t *)buf)[1]; 3684c0392e6SHans Petter Selasky 3694c0392e6SHans Petter Selasky if (dlen < 2 || dlen > len) 3704c0392e6SHans Petter Selasky break; 3714c0392e6SHans Petter Selasky 3724c0392e6SHans Petter Selasky if (dlen >= LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE && 3734c0392e6SHans Petter Selasky dtype == LIBUSB_DT_SS_ENDPOINT_COMPANION) { 3744c0392e6SHans Petter Selasky struct libusb_ss_endpoint_companion_descriptor *ptr; 3754c0392e6SHans Petter Selasky 3764c0392e6SHans Petter Selasky ptr = malloc(sizeof(*ptr)); 3774c0392e6SHans Petter Selasky if (ptr == NULL) 3784c0392e6SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 3794c0392e6SHans Petter Selasky 3804c0392e6SHans Petter Selasky ptr->bLength = LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE; 3814c0392e6SHans Petter Selasky ptr->bDescriptorType = dtype; 3824c0392e6SHans Petter Selasky ptr->bMaxBurst = ((const uint8_t *)buf)[2]; 3834c0392e6SHans Petter Selasky ptr->bmAttributes = ((const uint8_t *)buf)[3]; 3844c0392e6SHans Petter Selasky ptr->wBytesPerInterval = ((const uint8_t *)buf)[4] | 3854c0392e6SHans Petter Selasky (((const uint8_t *)buf)[5] << 8); 3864c0392e6SHans Petter Selasky 3874c0392e6SHans Petter Selasky *ep_comp = ptr; 3884c0392e6SHans Petter Selasky 3894c0392e6SHans Petter Selasky return (0); /* success */ 3904c0392e6SHans Petter Selasky } 3914c0392e6SHans Petter Selasky 3924c0392e6SHans Petter Selasky buf = ((const uint8_t *)buf) + dlen; 3934c0392e6SHans Petter Selasky len -= dlen; 3944c0392e6SHans Petter Selasky } 3954c0392e6SHans Petter Selasky return (LIBUSB_ERROR_IO); 3964c0392e6SHans Petter Selasky } 3974c0392e6SHans Petter Selasky 3984c0392e6SHans Petter Selasky void 3994c0392e6SHans Petter Selasky libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp) 4004c0392e6SHans Petter Selasky { 4014c0392e6SHans Petter Selasky if (ep_comp == NULL) 4024c0392e6SHans Petter Selasky return; 4034c0392e6SHans Petter Selasky 4044c0392e6SHans Petter Selasky free(ep_comp); 4054c0392e6SHans Petter Selasky } 4064c0392e6SHans Petter Selasky 4074c0392e6SHans Petter Selasky int 4084c0392e6SHans Petter Selasky libusb_parse_bos_descriptor(const void *buf, int len, 4094c0392e6SHans Petter Selasky struct libusb_bos_descriptor **bos) 4104c0392e6SHans Petter Selasky { 4114c0392e6SHans Petter Selasky struct libusb_bos_descriptor *ptr; 412d81535d1SHans Petter Selasky struct libusb_usb_2_0_device_capability_descriptor *dcap_20 = NULL; 413d81535d1SHans Petter Selasky struct libusb_ss_usb_device_capability_descriptor *ss_cap = NULL; 4144c0392e6SHans Petter Selasky 4154c0392e6SHans Petter Selasky if (buf == NULL || bos == NULL || len < 1) 4164c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 4174c0392e6SHans Petter Selasky 4184c0392e6SHans Petter Selasky if (len > 65535) 4194c0392e6SHans Petter Selasky len = 65535; 4204c0392e6SHans Petter Selasky 4214c0392e6SHans Petter Selasky *bos = ptr = NULL; 4224c0392e6SHans Petter Selasky 4234c0392e6SHans Petter Selasky while (len != 0) { 4244c0392e6SHans Petter Selasky uint8_t dlen; 4254c0392e6SHans Petter Selasky uint8_t dtype; 4264c0392e6SHans Petter Selasky 4274c0392e6SHans Petter Selasky dlen = ((const uint8_t *)buf)[0]; 4284c0392e6SHans Petter Selasky dtype = ((const uint8_t *)buf)[1]; 4294c0392e6SHans Petter Selasky 4304c0392e6SHans Petter Selasky if (dlen < 2 || dlen > len) 4314c0392e6SHans Petter Selasky break; 4324c0392e6SHans Petter Selasky 4334c0392e6SHans Petter Selasky if (dlen >= LIBUSB_DT_BOS_SIZE && 4344c0392e6SHans Petter Selasky dtype == LIBUSB_DT_BOS) { 4354c0392e6SHans Petter Selasky 4364c0392e6SHans Petter Selasky ptr = malloc(sizeof(*ptr) + sizeof(*dcap_20) + 4374c0392e6SHans Petter Selasky sizeof(*ss_cap)); 4384c0392e6SHans Petter Selasky 4394c0392e6SHans Petter Selasky if (ptr == NULL) 4404c0392e6SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 4414c0392e6SHans Petter Selasky 4424c0392e6SHans Petter Selasky *bos = ptr; 4434c0392e6SHans Petter Selasky 4444c0392e6SHans Petter Selasky ptr->bLength = LIBUSB_DT_BOS_SIZE; 4454c0392e6SHans Petter Selasky ptr->bDescriptorType = dtype; 4464c0392e6SHans Petter Selasky ptr->wTotalLength = ((const uint8_t *)buf)[2] | 4474c0392e6SHans Petter Selasky (((const uint8_t *)buf)[3] << 8); 4484c0392e6SHans Petter Selasky ptr->bNumDeviceCapabilities = ((const uint8_t *)buf)[4]; 4494c0392e6SHans Petter Selasky ptr->usb_2_0_ext_cap = NULL; 4504c0392e6SHans Petter Selasky ptr->ss_usb_cap = NULL; 4514c0392e6SHans Petter Selasky 4524c0392e6SHans Petter Selasky dcap_20 = (void *)(ptr + 1); 4534c0392e6SHans Petter Selasky ss_cap = (void *)(dcap_20 + 1); 4544c0392e6SHans Petter Selasky } 4554c0392e6SHans Petter Selasky if (dlen >= 3 && 4564c0392e6SHans Petter Selasky ptr != NULL && 4574c0392e6SHans Petter Selasky dtype == LIBUSB_DT_DEVICE_CAPABILITY) { 4584c0392e6SHans Petter Selasky switch (((const uint8_t *)buf)[2]) { 4594c0392e6SHans Petter Selasky case LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY: 460d81535d1SHans Petter Selasky if (ptr->usb_2_0_ext_cap != NULL || dcap_20 == NULL) 4614c0392e6SHans Petter Selasky break; 4624c0392e6SHans Petter Selasky if (dlen < LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE) 4634c0392e6SHans Petter Selasky break; 4644c0392e6SHans Petter Selasky 4654c0392e6SHans Petter Selasky ptr->usb_2_0_ext_cap = dcap_20; 4664c0392e6SHans Petter Selasky 4674c0392e6SHans Petter Selasky dcap_20->bLength = LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE; 4684c0392e6SHans Petter Selasky dcap_20->bDescriptorType = dtype; 4694c0392e6SHans Petter Selasky dcap_20->bDevCapabilityType = ((const uint8_t *)buf)[2]; 4704c0392e6SHans Petter Selasky dcap_20->bmAttributes = ((const uint8_t *)buf)[3] | 4714c0392e6SHans Petter Selasky (((const uint8_t *)buf)[4] << 8) | 4724c0392e6SHans Petter Selasky (((const uint8_t *)buf)[5] << 16) | 4734c0392e6SHans Petter Selasky (((const uint8_t *)buf)[6] << 24); 4744c0392e6SHans Petter Selasky break; 4754c0392e6SHans Petter Selasky 4764c0392e6SHans Petter Selasky case LIBUSB_SS_USB_DEVICE_CAPABILITY: 477d81535d1SHans Petter Selasky if (ptr->ss_usb_cap != NULL || ss_cap == NULL) 4784c0392e6SHans Petter Selasky break; 4794c0392e6SHans Petter Selasky if (dlen < LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE) 4804c0392e6SHans Petter Selasky break; 4814c0392e6SHans Petter Selasky 4824c0392e6SHans Petter Selasky ptr->ss_usb_cap = ss_cap; 4834c0392e6SHans Petter Selasky 4844c0392e6SHans Petter Selasky ss_cap->bLength = LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE; 4854c0392e6SHans Petter Selasky ss_cap->bDescriptorType = dtype; 4864c0392e6SHans Petter Selasky ss_cap->bDevCapabilityType = ((const uint8_t *)buf)[2]; 4874c0392e6SHans Petter Selasky ss_cap->bmAttributes = ((const uint8_t *)buf)[3]; 4884c0392e6SHans Petter Selasky ss_cap->wSpeedSupported = ((const uint8_t *)buf)[4] | 4894c0392e6SHans Petter Selasky (((const uint8_t *)buf)[5] << 8); 4904c0392e6SHans Petter Selasky ss_cap->bFunctionalitySupport = ((const uint8_t *)buf)[6]; 4914c0392e6SHans Petter Selasky ss_cap->bU1DevExitLat = ((const uint8_t *)buf)[7]; 4924c0392e6SHans Petter Selasky ss_cap->wU2DevExitLat = ((const uint8_t *)buf)[8] | 4934c0392e6SHans Petter Selasky (((const uint8_t *)buf)[9] << 8); 4944c0392e6SHans Petter Selasky break; 4954c0392e6SHans Petter Selasky 4964c0392e6SHans Petter Selasky default: 4974c0392e6SHans Petter Selasky break; 4984c0392e6SHans Petter Selasky } 4994c0392e6SHans Petter Selasky } 5004c0392e6SHans Petter Selasky 5014c0392e6SHans Petter Selasky buf = ((const uint8_t *)buf) + dlen; 5024c0392e6SHans Petter Selasky len -= dlen; 5034c0392e6SHans Petter Selasky } 5044c0392e6SHans Petter Selasky if (ptr != NULL) 5054c0392e6SHans Petter Selasky return (0); /* success */ 5064c0392e6SHans Petter Selasky 5074c0392e6SHans Petter Selasky return (LIBUSB_ERROR_IO); 5084c0392e6SHans Petter Selasky } 5094c0392e6SHans Petter Selasky 5104c0392e6SHans Petter Selasky void 5114c0392e6SHans Petter Selasky libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) 5124c0392e6SHans Petter Selasky { 5134c0392e6SHans Petter Selasky if (bos == NULL) 5144c0392e6SHans Petter Selasky return; 5154c0392e6SHans Petter Selasky 5164c0392e6SHans Petter Selasky free(bos); 5174c0392e6SHans Petter Selasky } 518