18c8fff31SAndrew Thompson /* $FreeBSD$ */ 28c8fff31SAndrew Thompson /*- 3*5e53a4f9SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 4*5e53a4f9SPedro F. Giffuni * 58c8fff31SAndrew Thompson * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 68c8fff31SAndrew Thompson * 78c8fff31SAndrew Thompson * Redistribution and use in source and binary forms, with or without 88c8fff31SAndrew Thompson * modification, are permitted provided that the following conditions 98c8fff31SAndrew Thompson * are met: 108c8fff31SAndrew Thompson * 1. Redistributions of source code must retain the above copyright 118c8fff31SAndrew Thompson * notice, this list of conditions and the following disclaimer. 128c8fff31SAndrew Thompson * 2. Redistributions in binary form must reproduce the above copyright 138c8fff31SAndrew Thompson * notice, this list of conditions and the following disclaimer in the 148c8fff31SAndrew Thompson * documentation and/or other materials provided with the distribution. 158c8fff31SAndrew Thompson * 168c8fff31SAndrew Thompson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 178c8fff31SAndrew Thompson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 188c8fff31SAndrew Thompson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 198c8fff31SAndrew Thompson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 208c8fff31SAndrew Thompson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 218c8fff31SAndrew Thompson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 228c8fff31SAndrew Thompson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 238c8fff31SAndrew Thompson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 248c8fff31SAndrew Thompson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 258c8fff31SAndrew Thompson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 268c8fff31SAndrew Thompson * SUCH DAMAGE. 278c8fff31SAndrew Thompson */ 288c8fff31SAndrew Thompson 2966194130SHans Petter Selasky #ifdef LIBUSB_GLOBAL_INCLUDE_FILE 3066194130SHans Petter Selasky #include LIBUSB_GLOBAL_INCLUDE_FILE 3166194130SHans Petter Selasky #else 32f3cba95cSWojciech A. Koszek #include <stdio.h> 33f3cba95cSWojciech A. Koszek #include <stdlib.h> 3466194130SHans Petter Selasky #include <string.h> 3566194130SHans Petter Selasky #include <time.h> 3666194130SHans Petter Selasky #include <sys/queue.h> 3766194130SHans Petter Selasky #endif 38f3cba95cSWojciech A. Koszek 399c087c5aSAndrew Thompson #define libusb_device_handle libusb20_device 409c087c5aSAndrew Thompson 418c8fff31SAndrew Thompson #include "libusb20.h" 428c8fff31SAndrew Thompson #include "libusb20_desc.h" 438c8fff31SAndrew Thompson #include "libusb20_int.h" 448c8fff31SAndrew Thompson #include "libusb.h" 458c8fff31SAndrew Thompson #include "libusb10.h" 468c8fff31SAndrew Thompson 47ccef4ddfSAndrew Thompson #define N_ALIGN(n) (-((-(n)) & (-8UL))) 48ccef4ddfSAndrew Thompson 498c8fff31SAndrew Thompson /* USB descriptors */ 508c8fff31SAndrew Thompson 518c8fff31SAndrew Thompson int 528c8fff31SAndrew Thompson libusb_get_device_descriptor(libusb_device *dev, 538c8fff31SAndrew Thompson struct libusb_device_descriptor *desc) 548c8fff31SAndrew Thompson { 558c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 568c8fff31SAndrew Thompson struct libusb20_device *pdev; 578c8fff31SAndrew Thompson 588c8fff31SAndrew Thompson if ((dev == NULL) || (desc == NULL)) 598c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 608c8fff31SAndrew Thompson 618c8fff31SAndrew Thompson pdev = dev->os_priv; 628c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 638c8fff31SAndrew Thompson 648c8fff31SAndrew Thompson desc->bLength = pdesc->bLength; 658c8fff31SAndrew Thompson desc->bDescriptorType = pdesc->bDescriptorType; 668c8fff31SAndrew Thompson desc->bcdUSB = pdesc->bcdUSB; 678c8fff31SAndrew Thompson desc->bDeviceClass = pdesc->bDeviceClass; 688c8fff31SAndrew Thompson desc->bDeviceSubClass = pdesc->bDeviceSubClass; 698c8fff31SAndrew Thompson desc->bDeviceProtocol = pdesc->bDeviceProtocol; 708c8fff31SAndrew Thompson desc->bMaxPacketSize0 = pdesc->bMaxPacketSize0; 718c8fff31SAndrew Thompson desc->idVendor = pdesc->idVendor; 728c8fff31SAndrew Thompson desc->idProduct = pdesc->idProduct; 738c8fff31SAndrew Thompson desc->bcdDevice = pdesc->bcdDevice; 748c8fff31SAndrew Thompson desc->iManufacturer = pdesc->iManufacturer; 758c8fff31SAndrew Thompson desc->iProduct = pdesc->iProduct; 768c8fff31SAndrew Thompson desc->iSerialNumber = pdesc->iSerialNumber; 778c8fff31SAndrew Thompson desc->bNumConfigurations = pdesc->bNumConfigurations; 788c8fff31SAndrew Thompson 798c8fff31SAndrew Thompson return (0); 808c8fff31SAndrew Thompson } 818c8fff31SAndrew Thompson 828c8fff31SAndrew Thompson int 838c8fff31SAndrew Thompson libusb_get_active_config_descriptor(libusb_device *dev, 848c8fff31SAndrew Thompson struct libusb_config_descriptor **config) 858c8fff31SAndrew Thompson { 868c8fff31SAndrew Thompson struct libusb20_device *pdev; 87390065b1SAlfred Perlstein uint8_t config_index; 888c8fff31SAndrew Thompson 898c8fff31SAndrew Thompson pdev = dev->os_priv; 90390065b1SAlfred Perlstein config_index = libusb20_dev_get_config_index(pdev); 918c8fff31SAndrew Thompson 92390065b1SAlfred Perlstein return (libusb_get_config_descriptor(dev, config_index, config)); 938c8fff31SAndrew Thompson } 948c8fff31SAndrew Thompson 958c8fff31SAndrew Thompson int 968c8fff31SAndrew Thompson libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, 978c8fff31SAndrew Thompson struct libusb_config_descriptor **config) 988c8fff31SAndrew Thompson { 998c8fff31SAndrew Thompson struct libusb20_device *pdev; 1008c8fff31SAndrew Thompson struct libusb20_config *pconf; 1018c8fff31SAndrew Thompson struct libusb20_interface *pinf; 1028c8fff31SAndrew Thompson struct libusb20_endpoint *pend; 103390065b1SAlfred Perlstein struct libusb_config_descriptor *pconfd; 104390065b1SAlfred Perlstein struct libusb_interface_descriptor *ifd; 105390065b1SAlfred Perlstein struct libusb_endpoint_descriptor *endd; 106390065b1SAlfred Perlstein uint8_t *pextra; 107390065b1SAlfred Perlstein uint16_t nextra; 108390065b1SAlfred Perlstein uint8_t nif; 109390065b1SAlfred Perlstein uint8_t nep; 110390065b1SAlfred Perlstein uint8_t nalt; 111390065b1SAlfred Perlstein uint8_t i; 112390065b1SAlfred Perlstein uint8_t j; 113390065b1SAlfred Perlstein uint8_t k; 1148c8fff31SAndrew Thompson 1158c8fff31SAndrew Thompson if (dev == NULL || config == NULL) 1168c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 1178c8fff31SAndrew Thompson 118390065b1SAlfred Perlstein *config = NULL; 119390065b1SAlfred Perlstein 1208c8fff31SAndrew Thompson pdev = dev->os_priv; 1218c8fff31SAndrew Thompson pconf = libusb20_dev_alloc_config(pdev, config_index); 1228c8fff31SAndrew Thompson 1238c8fff31SAndrew Thompson if (pconf == NULL) 1248c8fff31SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 1258c8fff31SAndrew Thompson 1268c8fff31SAndrew Thompson nalt = nif = pconf->num_interface; 127390065b1SAlfred Perlstein nep = 0; 128ccef4ddfSAndrew Thompson nextra = N_ALIGN(pconf->extra.len); 129390065b1SAlfred Perlstein 1308c8fff31SAndrew Thompson for (i = 0; i < nif; i++) { 131390065b1SAlfred Perlstein 132390065b1SAlfred Perlstein pinf = pconf->interface + i; 133ccef4ddfSAndrew Thompson nextra += N_ALIGN(pinf->extra.len); 134390065b1SAlfred Perlstein nep += pinf->num_endpoints; 135390065b1SAlfred Perlstein k = pinf->num_endpoints; 136390065b1SAlfred Perlstein pend = pinf->endpoints; 137390065b1SAlfred Perlstein while (k--) { 138ccef4ddfSAndrew Thompson nextra += N_ALIGN(pend->extra.len); 139390065b1SAlfred Perlstein pend++; 1408c8fff31SAndrew Thompson } 1418c8fff31SAndrew Thompson 142390065b1SAlfred Perlstein j = pinf->num_altsetting; 143390065b1SAlfred Perlstein nalt += pinf->num_altsetting; 144390065b1SAlfred Perlstein pinf = pinf->altsetting; 145390065b1SAlfred Perlstein while (j--) { 146ccef4ddfSAndrew Thompson nextra += N_ALIGN(pinf->extra.len); 147390065b1SAlfred Perlstein nep += pinf->num_endpoints; 148390065b1SAlfred Perlstein k = pinf->num_endpoints; 149390065b1SAlfred Perlstein pend = pinf->endpoints; 150390065b1SAlfred Perlstein while (k--) { 151ccef4ddfSAndrew Thompson nextra += N_ALIGN(pend->extra.len); 152390065b1SAlfred Perlstein pend++; 153390065b1SAlfred Perlstein } 154390065b1SAlfred Perlstein pinf++; 155390065b1SAlfred Perlstein } 156390065b1SAlfred Perlstein } 157390065b1SAlfred Perlstein 158390065b1SAlfred Perlstein nextra = nextra + 159390065b1SAlfred Perlstein (1 * sizeof(libusb_config_descriptor)) + 1608c8fff31SAndrew Thompson (nif * sizeof(libusb_interface)) + 1618c8fff31SAndrew Thompson (nalt * sizeof(libusb_interface_descriptor)) + 162390065b1SAlfred Perlstein (nep * sizeof(libusb_endpoint_descriptor)); 163390065b1SAlfred Perlstein 164ccef4ddfSAndrew Thompson nextra = N_ALIGN(nextra); 165ccef4ddfSAndrew Thompson 166390065b1SAlfred Perlstein pconfd = malloc(nextra); 167390065b1SAlfred Perlstein 168390065b1SAlfred Perlstein if (pconfd == NULL) { 1698c8fff31SAndrew Thompson free(pconf); 1708c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 1718c8fff31SAndrew Thompson } 172ccef4ddfSAndrew Thompson /* make sure memory is initialised */ 173390065b1SAlfred Perlstein memset(pconfd, 0, nextra); 1748c8fff31SAndrew Thompson 175ccef4ddfSAndrew Thompson pconfd->interface = (libusb_interface *) (pconfd + 1); 1768c8fff31SAndrew Thompson 177390065b1SAlfred Perlstein ifd = (libusb_interface_descriptor *) (pconfd->interface + nif); 178390065b1SAlfred Perlstein endd = (libusb_endpoint_descriptor *) (ifd + nalt); 179390065b1SAlfred Perlstein pextra = (uint8_t *)(endd + nep); 180390065b1SAlfred Perlstein 181390065b1SAlfred Perlstein /* fill in config descriptor */ 182390065b1SAlfred Perlstein 183390065b1SAlfred Perlstein pconfd->bLength = pconf->desc.bLength; 184390065b1SAlfred Perlstein pconfd->bDescriptorType = pconf->desc.bDescriptorType; 185390065b1SAlfred Perlstein pconfd->wTotalLength = pconf->desc.wTotalLength; 186390065b1SAlfred Perlstein pconfd->bNumInterfaces = pconf->desc.bNumInterfaces; 187390065b1SAlfred Perlstein pconfd->bConfigurationValue = pconf->desc.bConfigurationValue; 188390065b1SAlfred Perlstein pconfd->iConfiguration = pconf->desc.iConfiguration; 189390065b1SAlfred Perlstein pconfd->bmAttributes = pconf->desc.bmAttributes; 190390065b1SAlfred Perlstein pconfd->MaxPower = pconf->desc.bMaxPower; 191390065b1SAlfred Perlstein 192390065b1SAlfred Perlstein if (pconf->extra.len != 0) { 193390065b1SAlfred Perlstein pconfd->extra_length = pconf->extra.len; 194390065b1SAlfred Perlstein pconfd->extra = pextra; 195390065b1SAlfred Perlstein memcpy(pextra, pconf->extra.ptr, pconfd->extra_length); 196ccef4ddfSAndrew Thompson pextra += N_ALIGN(pconfd->extra_length); 1978c8fff31SAndrew Thompson } 198390065b1SAlfred Perlstein /* setup all interface and endpoint pointers */ 199390065b1SAlfred Perlstein 200390065b1SAlfred Perlstein for (i = 0; i < nif; i++) { 201390065b1SAlfred Perlstein 202390065b1SAlfred Perlstein pconfd->interface[i].altsetting = ifd; 203390065b1SAlfred Perlstein ifd->endpoint = endd; 204390065b1SAlfred Perlstein endd += pconf->interface[i].num_endpoints; 205390065b1SAlfred Perlstein ifd++; 206390065b1SAlfred Perlstein 207390065b1SAlfred Perlstein for (j = 0; j < pconf->interface[i].num_altsetting; j++) { 208390065b1SAlfred Perlstein ifd->endpoint = endd; 209390065b1SAlfred Perlstein endd += pconf->interface[i].altsetting[j].num_endpoints; 210390065b1SAlfred Perlstein ifd++; 2118c8fff31SAndrew Thompson } 2128c8fff31SAndrew Thompson } 2138c8fff31SAndrew Thompson 214390065b1SAlfred Perlstein /* fill in all interface and endpoint data */ 2158c8fff31SAndrew Thompson 2168c8fff31SAndrew Thompson for (i = 0; i < nif; i++) { 2178c8fff31SAndrew Thompson pinf = &pconf->interface[i]; 218390065b1SAlfred Perlstein pconfd->interface[i].num_altsetting = pinf->num_altsetting + 1; 219390065b1SAlfred Perlstein for (j = 0; j < pconfd->interface[i].num_altsetting; j++) { 2208c8fff31SAndrew Thompson if (j != 0) 2218c8fff31SAndrew Thompson pinf = &pconf->interface[i].altsetting[j - 1]; 222390065b1SAlfred Perlstein ifd = &pconfd->interface[i].altsetting[j]; 2238c8fff31SAndrew Thompson ifd->bLength = pinf->desc.bLength; 2248c8fff31SAndrew Thompson ifd->bDescriptorType = pinf->desc.bDescriptorType; 2258c8fff31SAndrew Thompson ifd->bInterfaceNumber = pinf->desc.bInterfaceNumber; 2268c8fff31SAndrew Thompson ifd->bAlternateSetting = pinf->desc.bAlternateSetting; 2278c8fff31SAndrew Thompson ifd->bNumEndpoints = pinf->desc.bNumEndpoints; 2288c8fff31SAndrew Thompson ifd->bInterfaceClass = pinf->desc.bInterfaceClass; 2298c8fff31SAndrew Thompson ifd->bInterfaceSubClass = pinf->desc.bInterfaceSubClass; 2308c8fff31SAndrew Thompson ifd->bInterfaceProtocol = pinf->desc.bInterfaceProtocol; 2318c8fff31SAndrew Thompson ifd->iInterface = pinf->desc.iInterface; 232390065b1SAlfred Perlstein if (pinf->extra.len != 0) { 2338c8fff31SAndrew Thompson ifd->extra_length = pinf->extra.len; 234390065b1SAlfred Perlstein ifd->extra = pextra; 235390065b1SAlfred Perlstein memcpy(pextra, pinf->extra.ptr, pinf->extra.len); 236ccef4ddfSAndrew Thompson pextra += N_ALIGN(pinf->extra.len); 237390065b1SAlfred Perlstein } 2388c8fff31SAndrew Thompson for (k = 0; k < pinf->num_endpoints; k++) { 2398c8fff31SAndrew Thompson pend = &pinf->endpoints[k]; 2408c8fff31SAndrew Thompson endd = &ifd->endpoint[k]; 2418c8fff31SAndrew Thompson endd->bLength = pend->desc.bLength; 2428c8fff31SAndrew Thompson endd->bDescriptorType = pend->desc.bDescriptorType; 2438c8fff31SAndrew Thompson endd->bEndpointAddress = pend->desc.bEndpointAddress; 2448c8fff31SAndrew Thompson endd->bmAttributes = pend->desc.bmAttributes; 2458c8fff31SAndrew Thompson endd->wMaxPacketSize = pend->desc.wMaxPacketSize; 2468c8fff31SAndrew Thompson endd->bInterval = pend->desc.bInterval; 2478c8fff31SAndrew Thompson endd->bRefresh = pend->desc.bRefresh; 2488c8fff31SAndrew Thompson endd->bSynchAddress = pend->desc.bSynchAddress; 249390065b1SAlfred Perlstein if (pend->extra.len != 0) { 2508c8fff31SAndrew Thompson endd->extra_length = pend->extra.len; 251390065b1SAlfred Perlstein endd->extra = pextra; 252390065b1SAlfred Perlstein memcpy(pextra, pend->extra.ptr, pend->extra.len); 253ccef4ddfSAndrew Thompson pextra += N_ALIGN(pend->extra.len); 254390065b1SAlfred Perlstein } 2558c8fff31SAndrew Thompson } 2568c8fff31SAndrew Thompson } 2578c8fff31SAndrew Thompson } 2588c8fff31SAndrew Thompson 2598c8fff31SAndrew Thompson free(pconf); 260390065b1SAlfred Perlstein 261390065b1SAlfred Perlstein *config = pconfd; 262390065b1SAlfred Perlstein 263390065b1SAlfred Perlstein return (0); /* success */ 2648c8fff31SAndrew Thompson } 2658c8fff31SAndrew Thompson 2668c8fff31SAndrew Thompson int 2678c8fff31SAndrew Thompson libusb_get_config_descriptor_by_value(libusb_device *dev, 2688c8fff31SAndrew Thompson uint8_t bConfigurationValue, struct libusb_config_descriptor **config) 2698c8fff31SAndrew Thompson { 2708c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 2718c8fff31SAndrew Thompson struct libusb20_device *pdev; 2728c8fff31SAndrew Thompson int i; 273390065b1SAlfred Perlstein int err; 2748c8fff31SAndrew Thompson 2758c8fff31SAndrew Thompson if (dev == NULL || config == NULL) 2768c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 2778c8fff31SAndrew Thompson 2788c8fff31SAndrew Thompson pdev = dev->os_priv; 2798c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 2808c8fff31SAndrew Thompson 2818c8fff31SAndrew Thompson for (i = 0; i < pdesc->bNumConfigurations; i++) { 282390065b1SAlfred Perlstein err = libusb_get_config_descriptor(dev, i, config); 283390065b1SAlfred Perlstein if (err) 284390065b1SAlfred Perlstein return (err); 2858c8fff31SAndrew Thompson 286390065b1SAlfred Perlstein if ((*config)->bConfigurationValue == bConfigurationValue) 287390065b1SAlfred Perlstein return (0); /* success */ 288390065b1SAlfred Perlstein 289390065b1SAlfred Perlstein libusb_free_config_descriptor(*config); 2908c8fff31SAndrew Thompson } 2918c8fff31SAndrew Thompson 292390065b1SAlfred Perlstein *config = NULL; 293390065b1SAlfred Perlstein 2948c8fff31SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 2958c8fff31SAndrew Thompson } 2968c8fff31SAndrew Thompson 2978c8fff31SAndrew Thompson void 2988c8fff31SAndrew Thompson libusb_free_config_descriptor(struct libusb_config_descriptor *config) 2998c8fff31SAndrew Thompson { 3008c8fff31SAndrew Thompson free(config); 3018c8fff31SAndrew Thompson } 3028c8fff31SAndrew Thompson 3038c8fff31SAndrew Thompson int 30478ed0e49SHans Petter Selasky libusb_get_string_descriptor(libusb_device_handle *pdev, 30578ed0e49SHans Petter Selasky uint8_t desc_index, uint16_t langid, unsigned char *data, 30678ed0e49SHans Petter Selasky int length) 30778ed0e49SHans Petter Selasky { 30878ed0e49SHans Petter Selasky if (pdev == NULL || data == NULL || length < 1) 30978ed0e49SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 31078ed0e49SHans Petter Selasky 31178ed0e49SHans Petter Selasky if (length > 65535) 31278ed0e49SHans Petter Selasky length = 65535; 31378ed0e49SHans Petter Selasky 31478ed0e49SHans Petter Selasky /* put some default data into the destination buffer */ 31578ed0e49SHans Petter Selasky data[0] = 0; 31678ed0e49SHans Petter Selasky 31778ed0e49SHans Petter Selasky return (libusb_control_transfer(pdev, LIBUSB_ENDPOINT_IN, 31878ed0e49SHans Petter Selasky LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc_index, 31978ed0e49SHans Petter Selasky langid, data, length, 1000)); 32078ed0e49SHans Petter Selasky } 32178ed0e49SHans Petter Selasky 32278ed0e49SHans Petter Selasky int 323390065b1SAlfred Perlstein libusb_get_string_descriptor_ascii(libusb_device_handle *pdev, 3248c8fff31SAndrew Thompson uint8_t desc_index, unsigned char *data, int length) 3258c8fff31SAndrew Thompson { 326390065b1SAlfred Perlstein if (pdev == NULL || data == NULL || length < 1) 3274c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 3288c8fff31SAndrew Thompson 3294eb5923dSHans Petter Selasky if (length > 65535) 3304eb5923dSHans Petter Selasky length = 65535; 3314eb5923dSHans Petter Selasky 332390065b1SAlfred Perlstein /* put some default data into the destination buffer */ 333390065b1SAlfred Perlstein data[0] = 0; 334390065b1SAlfred Perlstein 3358c8fff31SAndrew Thompson if (libusb20_dev_req_string_simple_sync(pdev, desc_index, 3368c8fff31SAndrew Thompson data, length) == 0) 337f357b4f6SHans Petter Selasky return (strlen((char *)data)); 3388c8fff31SAndrew Thompson 3398c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 3408c8fff31SAndrew Thompson } 341ccef4ddfSAndrew Thompson 342ccef4ddfSAndrew Thompson int 343ccef4ddfSAndrew Thompson libusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, 344ccef4ddfSAndrew Thompson uint8_t desc_index, uint8_t *data, int length) 345ccef4ddfSAndrew Thompson { 3464eb5923dSHans Petter Selasky if (devh == NULL || data == NULL || length < 1) 3474c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 3484eb5923dSHans Petter Selasky 3494eb5923dSHans Petter Selasky if (length > 65535) 3504eb5923dSHans Petter Selasky length = 65535; 3514eb5923dSHans Petter Selasky 352ccef4ddfSAndrew Thompson return (libusb_control_transfer(devh, LIBUSB_ENDPOINT_IN, 353ccef4ddfSAndrew Thompson LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, 354ccef4ddfSAndrew Thompson length, 1000)); 355ccef4ddfSAndrew Thompson } 3564c0392e6SHans Petter Selasky 3574c0392e6SHans Petter Selasky int 3584c0392e6SHans Petter Selasky libusb_parse_ss_endpoint_comp(const void *buf, int len, 3594c0392e6SHans Petter Selasky struct libusb_ss_endpoint_companion_descriptor **ep_comp) 3604c0392e6SHans Petter Selasky { 3614c0392e6SHans Petter Selasky if (buf == NULL || ep_comp == NULL || len < 1) 3624c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 3634c0392e6SHans Petter Selasky 3644c0392e6SHans Petter Selasky if (len > 65535) 3654c0392e6SHans Petter Selasky len = 65535; 3664c0392e6SHans Petter Selasky 3674c0392e6SHans Petter Selasky *ep_comp = NULL; 3684c0392e6SHans Petter Selasky 3694c0392e6SHans Petter Selasky while (len != 0) { 3704c0392e6SHans Petter Selasky uint8_t dlen; 3714c0392e6SHans Petter Selasky uint8_t dtype; 3724c0392e6SHans Petter Selasky 3734c0392e6SHans Petter Selasky dlen = ((const uint8_t *)buf)[0]; 3744c0392e6SHans Petter Selasky dtype = ((const uint8_t *)buf)[1]; 3754c0392e6SHans Petter Selasky 3764c0392e6SHans Petter Selasky if (dlen < 2 || dlen > len) 3774c0392e6SHans Petter Selasky break; 3784c0392e6SHans Petter Selasky 3794c0392e6SHans Petter Selasky if (dlen >= LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE && 3804c0392e6SHans Petter Selasky dtype == LIBUSB_DT_SS_ENDPOINT_COMPANION) { 3814c0392e6SHans Petter Selasky struct libusb_ss_endpoint_companion_descriptor *ptr; 3824c0392e6SHans Petter Selasky 3834c0392e6SHans Petter Selasky ptr = malloc(sizeof(*ptr)); 3844c0392e6SHans Petter Selasky if (ptr == NULL) 3854c0392e6SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 3864c0392e6SHans Petter Selasky 3874c0392e6SHans Petter Selasky ptr->bLength = LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE; 3884c0392e6SHans Petter Selasky ptr->bDescriptorType = dtype; 3894c0392e6SHans Petter Selasky ptr->bMaxBurst = ((const uint8_t *)buf)[2]; 3904c0392e6SHans Petter Selasky ptr->bmAttributes = ((const uint8_t *)buf)[3]; 3914c0392e6SHans Petter Selasky ptr->wBytesPerInterval = ((const uint8_t *)buf)[4] | 3924c0392e6SHans Petter Selasky (((const uint8_t *)buf)[5] << 8); 3934c0392e6SHans Petter Selasky 3944c0392e6SHans Petter Selasky *ep_comp = ptr; 3954c0392e6SHans Petter Selasky 3964c0392e6SHans Petter Selasky return (0); /* success */ 3974c0392e6SHans Petter Selasky } 3984c0392e6SHans Petter Selasky 3994c0392e6SHans Petter Selasky buf = ((const uint8_t *)buf) + dlen; 4004c0392e6SHans Petter Selasky len -= dlen; 4014c0392e6SHans Petter Selasky } 4024c0392e6SHans Petter Selasky return (LIBUSB_ERROR_IO); 4034c0392e6SHans Petter Selasky } 4044c0392e6SHans Petter Selasky 4054c0392e6SHans Petter Selasky void 4064c0392e6SHans Petter Selasky libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp) 4074c0392e6SHans Petter Selasky { 4084c0392e6SHans Petter Selasky if (ep_comp == NULL) 4094c0392e6SHans Petter Selasky return; 4104c0392e6SHans Petter Selasky 4114c0392e6SHans Petter Selasky free(ep_comp); 4124c0392e6SHans Petter Selasky } 4134c0392e6SHans Petter Selasky 4144c0392e6SHans Petter Selasky int 41537d0636aSHans Petter Selasky libusb_get_ss_endpoint_companion_descriptor(struct libusb_context *ctx, 41637d0636aSHans Petter Selasky const struct libusb_endpoint_descriptor *endpoint, 41737d0636aSHans Petter Selasky struct libusb_ss_endpoint_companion_descriptor **ep_comp) 41837d0636aSHans Petter Selasky { 41937d0636aSHans Petter Selasky if (endpoint == NULL) 42037d0636aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 42137d0636aSHans Petter Selasky return (libusb_parse_ss_endpoint_comp(endpoint->extra, endpoint->extra_length, ep_comp)); 42237d0636aSHans Petter Selasky } 42337d0636aSHans Petter Selasky 42437d0636aSHans Petter Selasky void 42537d0636aSHans Petter Selasky libusb_free_ss_endpoint_companion_descriptor(struct libusb_ss_endpoint_companion_descriptor *ep_comp) 42637d0636aSHans Petter Selasky { 42737d0636aSHans Petter Selasky 42837d0636aSHans Petter Selasky libusb_free_ss_endpoint_comp(ep_comp); 42937d0636aSHans Petter Selasky } 43037d0636aSHans Petter Selasky 43137d0636aSHans Petter Selasky int 4324c0392e6SHans Petter Selasky libusb_parse_bos_descriptor(const void *buf, int len, 4334c0392e6SHans Petter Selasky struct libusb_bos_descriptor **bos) 4344c0392e6SHans Petter Selasky { 4354c0392e6SHans Petter Selasky struct libusb_bos_descriptor *ptr; 436d81535d1SHans Petter Selasky struct libusb_usb_2_0_device_capability_descriptor *dcap_20 = NULL; 437d81535d1SHans Petter Selasky struct libusb_ss_usb_device_capability_descriptor *ss_cap = NULL; 438f75f5a35SKyle Evans uint8_t index = 0; 4394c0392e6SHans Petter Selasky 4404c0392e6SHans Petter Selasky if (buf == NULL || bos == NULL || len < 1) 4414c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 4424c0392e6SHans Petter Selasky 4434c0392e6SHans Petter Selasky if (len > 65535) 4444c0392e6SHans Petter Selasky len = 65535; 4454c0392e6SHans Petter Selasky 4464c0392e6SHans Petter Selasky *bos = ptr = NULL; 4474c0392e6SHans Petter Selasky 4484c0392e6SHans Petter Selasky while (len != 0) { 4494c0392e6SHans Petter Selasky uint8_t dlen; 4504c0392e6SHans Petter Selasky uint8_t dtype; 4514c0392e6SHans Petter Selasky 4524c0392e6SHans Petter Selasky dlen = ((const uint8_t *)buf)[0]; 4534c0392e6SHans Petter Selasky dtype = ((const uint8_t *)buf)[1]; 4544c0392e6SHans Petter Selasky 4554c0392e6SHans Petter Selasky if (dlen < 2 || dlen > len) 4564c0392e6SHans Petter Selasky break; 4574c0392e6SHans Petter Selasky 4584c0392e6SHans Petter Selasky if (dlen >= LIBUSB_DT_BOS_SIZE && 459f75f5a35SKyle Evans dtype == LIBUSB_DT_BOS && 460f75f5a35SKyle Evans ptr == NULL) { 4614c0392e6SHans Petter Selasky 4624c0392e6SHans Petter Selasky ptr = malloc(sizeof(*ptr) + sizeof(*dcap_20) + 4634c0392e6SHans Petter Selasky sizeof(*ss_cap)); 4644c0392e6SHans Petter Selasky 4654c0392e6SHans Petter Selasky if (ptr == NULL) 4664c0392e6SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 4674c0392e6SHans Petter Selasky 4684c0392e6SHans Petter Selasky *bos = ptr; 4694c0392e6SHans Petter Selasky 4704c0392e6SHans Petter Selasky ptr->bLength = LIBUSB_DT_BOS_SIZE; 4714c0392e6SHans Petter Selasky ptr->bDescriptorType = dtype; 4724c0392e6SHans Petter Selasky ptr->wTotalLength = ((const uint8_t *)buf)[2] | 4734c0392e6SHans Petter Selasky (((const uint8_t *)buf)[3] << 8); 4744c0392e6SHans Petter Selasky ptr->bNumDeviceCapabilities = ((const uint8_t *)buf)[4]; 4754c0392e6SHans Petter Selasky ptr->usb_2_0_ext_cap = NULL; 4764c0392e6SHans Petter Selasky ptr->ss_usb_cap = NULL; 477f75f5a35SKyle Evans ptr->dev_capability = calloc(ptr->bNumDeviceCapabilities, sizeof(void *)); 478f75f5a35SKyle Evans if (ptr->dev_capability == NULL) { 479f75f5a35SKyle Evans free(ptr); 480f75f5a35SKyle Evans return (LIBUSB_ERROR_NO_MEM); 481f75f5a35SKyle Evans } 4824c0392e6SHans Petter Selasky 4834c0392e6SHans Petter Selasky dcap_20 = (void *)(ptr + 1); 4844c0392e6SHans Petter Selasky ss_cap = (void *)(dcap_20 + 1); 4854c0392e6SHans Petter Selasky } 4864c0392e6SHans Petter Selasky if (dlen >= 3 && 4874c0392e6SHans Petter Selasky ptr != NULL && 4884c0392e6SHans Petter Selasky dtype == LIBUSB_DT_DEVICE_CAPABILITY) { 489f75f5a35SKyle Evans if (index != ptr->bNumDeviceCapabilities) { 490f75f5a35SKyle Evans ptr->dev_capability[index] = malloc(dlen); 491f75f5a35SKyle Evans if (ptr->dev_capability[index] == NULL) { 492f75f5a35SKyle Evans libusb_free_bos_descriptor(ptr); 493f75f5a35SKyle Evans return LIBUSB_ERROR_NO_MEM; 494f75f5a35SKyle Evans } 495f75f5a35SKyle Evans memcpy(ptr->dev_capability[index], buf, dlen); 496f75f5a35SKyle Evans index++; 497f75f5a35SKyle Evans } 4984c0392e6SHans Petter Selasky switch (((const uint8_t *)buf)[2]) { 4994c0392e6SHans Petter Selasky case LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY: 500d81535d1SHans Petter Selasky if (ptr->usb_2_0_ext_cap != NULL || dcap_20 == NULL) 5014c0392e6SHans Petter Selasky break; 5024c0392e6SHans Petter Selasky if (dlen < LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE) 5034c0392e6SHans Petter Selasky break; 5044c0392e6SHans Petter Selasky 5054c0392e6SHans Petter Selasky ptr->usb_2_0_ext_cap = dcap_20; 5064c0392e6SHans Petter Selasky 5074c0392e6SHans Petter Selasky dcap_20->bLength = LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE; 5084c0392e6SHans Petter Selasky dcap_20->bDescriptorType = dtype; 5094c0392e6SHans Petter Selasky dcap_20->bDevCapabilityType = ((const uint8_t *)buf)[2]; 5104c0392e6SHans Petter Selasky dcap_20->bmAttributes = ((const uint8_t *)buf)[3] | 5114c0392e6SHans Petter Selasky (((const uint8_t *)buf)[4] << 8) | 5124c0392e6SHans Petter Selasky (((const uint8_t *)buf)[5] << 16) | 5134c0392e6SHans Petter Selasky (((const uint8_t *)buf)[6] << 24); 5144c0392e6SHans Petter Selasky break; 5154c0392e6SHans Petter Selasky 5164c0392e6SHans Petter Selasky case LIBUSB_SS_USB_DEVICE_CAPABILITY: 517d81535d1SHans Petter Selasky if (ptr->ss_usb_cap != NULL || ss_cap == NULL) 5184c0392e6SHans Petter Selasky break; 5194c0392e6SHans Petter Selasky if (dlen < LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE) 5204c0392e6SHans Petter Selasky break; 5214c0392e6SHans Petter Selasky 5224c0392e6SHans Petter Selasky ptr->ss_usb_cap = ss_cap; 5234c0392e6SHans Petter Selasky 5244c0392e6SHans Petter Selasky ss_cap->bLength = LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE; 5254c0392e6SHans Petter Selasky ss_cap->bDescriptorType = dtype; 5264c0392e6SHans Petter Selasky ss_cap->bDevCapabilityType = ((const uint8_t *)buf)[2]; 5274c0392e6SHans Petter Selasky ss_cap->bmAttributes = ((const uint8_t *)buf)[3]; 5284c0392e6SHans Petter Selasky ss_cap->wSpeedSupported = ((const uint8_t *)buf)[4] | 5294c0392e6SHans Petter Selasky (((const uint8_t *)buf)[5] << 8); 5304c0392e6SHans Petter Selasky ss_cap->bFunctionalitySupport = ((const uint8_t *)buf)[6]; 5314c0392e6SHans Petter Selasky ss_cap->bU1DevExitLat = ((const uint8_t *)buf)[7]; 5324c0392e6SHans Petter Selasky ss_cap->wU2DevExitLat = ((const uint8_t *)buf)[8] | 5334c0392e6SHans Petter Selasky (((const uint8_t *)buf)[9] << 8); 5344c0392e6SHans Petter Selasky break; 5354c0392e6SHans Petter Selasky 5364c0392e6SHans Petter Selasky default: 5374c0392e6SHans Petter Selasky break; 5384c0392e6SHans Petter Selasky } 5394c0392e6SHans Petter Selasky } 5404c0392e6SHans Petter Selasky 5414c0392e6SHans Petter Selasky buf = ((const uint8_t *)buf) + dlen; 5424c0392e6SHans Petter Selasky len -= dlen; 5434c0392e6SHans Petter Selasky } 544f75f5a35SKyle Evans 545f75f5a35SKyle Evans if (ptr != NULL) { 546f75f5a35SKyle Evans ptr->bNumDeviceCapabilities = index; 5474c0392e6SHans Petter Selasky return (0); /* success */ 548f75f5a35SKyle Evans } 5494c0392e6SHans Petter Selasky 5504c0392e6SHans Petter Selasky return (LIBUSB_ERROR_IO); 5514c0392e6SHans Petter Selasky } 5524c0392e6SHans Petter Selasky 5534c0392e6SHans Petter Selasky void 5544c0392e6SHans Petter Selasky libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) 5554c0392e6SHans Petter Selasky { 556f75f5a35SKyle Evans uint8_t i; 557f75f5a35SKyle Evans 5584c0392e6SHans Petter Selasky if (bos == NULL) 5594c0392e6SHans Petter Selasky return; 5604c0392e6SHans Petter Selasky 561f75f5a35SKyle Evans for (i = 0; i != bos->bNumDeviceCapabilities; i++) 562f75f5a35SKyle Evans free(bos->dev_capability[i]); 563f75f5a35SKyle Evans free(bos->dev_capability); 5644c0392e6SHans Petter Selasky free(bos); 5654c0392e6SHans Petter Selasky } 56637d0636aSHans Petter Selasky 56737d0636aSHans Petter Selasky int 56837d0636aSHans Petter Selasky libusb_get_bos_descriptor(libusb_device_handle *handle, 56937d0636aSHans Petter Selasky struct libusb_bos_descriptor **bos) 57037d0636aSHans Petter Selasky { 57137d0636aSHans Petter Selasky uint8_t bos_header[LIBUSB_DT_BOS_SIZE] = {0}; 57237d0636aSHans Petter Selasky uint16_t wTotalLength; 57337d0636aSHans Petter Selasky uint8_t *bos_data; 57437d0636aSHans Petter Selasky int err; 57537d0636aSHans Petter Selasky 57637d0636aSHans Petter Selasky err = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, 57737d0636aSHans Petter Selasky bos_header, sizeof(bos_header)); 57837d0636aSHans Petter Selasky if (err < 0) 57937d0636aSHans Petter Selasky return (err); 58037d0636aSHans Petter Selasky 58137d0636aSHans Petter Selasky wTotalLength = bos_header[2] | (bos_header[3] << 8); 58237d0636aSHans Petter Selasky if (wTotalLength < LIBUSB_DT_BOS_SIZE) 58337d0636aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 58437d0636aSHans Petter Selasky 58537d0636aSHans Petter Selasky bos_data = calloc(wTotalLength, 1); 58637d0636aSHans Petter Selasky if (bos_data == NULL) 58737d0636aSHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 58837d0636aSHans Petter Selasky 58937d0636aSHans Petter Selasky err = libusb_get_descriptor(handle, LIBUSB_DT_BOS, 0, 59037d0636aSHans Petter Selasky bos_data, wTotalLength); 59137d0636aSHans Petter Selasky if (err < 0) 59237d0636aSHans Petter Selasky goto done; 59337d0636aSHans Petter Selasky 59437d0636aSHans Petter Selasky /* avoid descriptor length mismatches */ 59537d0636aSHans Petter Selasky bos_data[2] = (wTotalLength & 0xFF); 59637d0636aSHans Petter Selasky bos_data[3] = (wTotalLength >> 8); 59737d0636aSHans Petter Selasky 59837d0636aSHans Petter Selasky err = libusb_parse_bos_descriptor(bos_data, wTotalLength, bos); 59937d0636aSHans Petter Selasky done: 60037d0636aSHans Petter Selasky free(bos_data); 60137d0636aSHans Petter Selasky return (err); 60237d0636aSHans Petter Selasky } 60337d0636aSHans Petter Selasky 60437d0636aSHans Petter Selasky int 60537d0636aSHans Petter Selasky libusb_get_usb_2_0_extension_descriptor(struct libusb_context *ctx, 60637d0636aSHans Petter Selasky struct libusb_bos_dev_capability_descriptor *dev_cap, 60737d0636aSHans Petter Selasky struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension) 60837d0636aSHans Petter Selasky { 60937d0636aSHans Petter Selasky struct libusb_usb_2_0_extension_descriptor *desc; 61037d0636aSHans Petter Selasky 61137d0636aSHans Petter Selasky if (dev_cap == NULL || usb_2_0_extension == NULL || 61237d0636aSHans Petter Selasky dev_cap->bDevCapabilityType != LIBUSB_BT_USB_2_0_EXTENSION) 61337d0636aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 61437d0636aSHans Petter Selasky if (dev_cap->bLength < LIBUSB_BT_USB_2_0_EXTENSION_SIZE) 61537d0636aSHans Petter Selasky return (LIBUSB_ERROR_IO); 61637d0636aSHans Petter Selasky 61737d0636aSHans Petter Selasky desc = malloc(sizeof(*desc)); 61837d0636aSHans Petter Selasky if (desc == NULL) 61937d0636aSHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 62037d0636aSHans Petter Selasky 62137d0636aSHans Petter Selasky desc->bLength = LIBUSB_BT_USB_2_0_EXTENSION_SIZE; 62237d0636aSHans Petter Selasky desc->bDescriptorType = dev_cap->bDescriptorType; 62337d0636aSHans Petter Selasky desc->bDevCapabilityType = dev_cap->bDevCapabilityType; 62437d0636aSHans Petter Selasky desc->bmAttributes = 62537d0636aSHans Petter Selasky (dev_cap->dev_capability_data[0]) | 62637d0636aSHans Petter Selasky (dev_cap->dev_capability_data[1] << 8) | 62737d0636aSHans Petter Selasky (dev_cap->dev_capability_data[2] << 16) | 62837d0636aSHans Petter Selasky (dev_cap->dev_capability_data[3] << 24); 62937d0636aSHans Petter Selasky 63037d0636aSHans Petter Selasky *usb_2_0_extension = desc; 63137d0636aSHans Petter Selasky return (0); 63237d0636aSHans Petter Selasky } 63337d0636aSHans Petter Selasky 63437d0636aSHans Petter Selasky void 63537d0636aSHans Petter Selasky libusb_free_usb_2_0_extension_descriptor( 63637d0636aSHans Petter Selasky struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension) 63737d0636aSHans Petter Selasky { 63837d0636aSHans Petter Selasky 63937d0636aSHans Petter Selasky free(usb_2_0_extension); 64037d0636aSHans Petter Selasky } 64137d0636aSHans Petter Selasky 64237d0636aSHans Petter Selasky int 64337d0636aSHans Petter Selasky libusb_get_ss_usb_device_capability_descriptor(struct libusb_context *ctx, 64437d0636aSHans Petter Selasky struct libusb_bos_dev_capability_descriptor *dev_cap, 64537d0636aSHans Petter Selasky struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_capability) 64637d0636aSHans Petter Selasky { 64737d0636aSHans Petter Selasky struct libusb_ss_usb_device_capability_descriptor *desc; 64837d0636aSHans Petter Selasky 64937d0636aSHans Petter Selasky if (dev_cap == NULL || ss_usb_device_capability == NULL || 65037d0636aSHans Petter Selasky dev_cap->bDevCapabilityType != LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) 65137d0636aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 65237d0636aSHans Petter Selasky if (dev_cap->bLength < LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) 65337d0636aSHans Petter Selasky return (LIBUSB_ERROR_IO); 65437d0636aSHans Petter Selasky 65537d0636aSHans Petter Selasky desc = malloc(sizeof(*desc)); 65637d0636aSHans Petter Selasky if (desc == NULL) 65737d0636aSHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 65837d0636aSHans Petter Selasky 65937d0636aSHans Petter Selasky desc->bLength = LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE; 66037d0636aSHans Petter Selasky desc->bDescriptorType = dev_cap->bDescriptorType; 66137d0636aSHans Petter Selasky desc->bDevCapabilityType = dev_cap->bDevCapabilityType; 66237d0636aSHans Petter Selasky desc->bmAttributes = dev_cap->dev_capability_data[0]; 66337d0636aSHans Petter Selasky desc->wSpeedSupported = dev_cap->dev_capability_data[1] | 66437d0636aSHans Petter Selasky (dev_cap->dev_capability_data[2] << 8); 66537d0636aSHans Petter Selasky desc->bFunctionalitySupport = dev_cap->dev_capability_data[3]; 66637d0636aSHans Petter Selasky desc->bU1DevExitLat = dev_cap->dev_capability_data[4]; 66737d0636aSHans Petter Selasky desc->wU2DevExitLat = dev_cap->dev_capability_data[5] | 66837d0636aSHans Petter Selasky (dev_cap->dev_capability_data[6] << 8); 66937d0636aSHans Petter Selasky 67037d0636aSHans Petter Selasky *ss_usb_device_capability = desc; 67137d0636aSHans Petter Selasky return (0); 67237d0636aSHans Petter Selasky } 67337d0636aSHans Petter Selasky 67437d0636aSHans Petter Selasky void 67537d0636aSHans Petter Selasky libusb_free_ss_usb_device_capability_descriptor( 67637d0636aSHans Petter Selasky struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_capability) 67737d0636aSHans Petter Selasky { 67837d0636aSHans Petter Selasky 67937d0636aSHans Petter Selasky free(ss_usb_device_capability); 68037d0636aSHans Petter Selasky } 68137d0636aSHans Petter Selasky 68237d0636aSHans Petter Selasky int 68337d0636aSHans Petter Selasky libusb_get_container_id_descriptor(struct libusb_context *ctx, 68437d0636aSHans Petter Selasky struct libusb_bos_dev_capability_descriptor *dev_cap, 68537d0636aSHans Petter Selasky struct libusb_container_id_descriptor **container_id) 68637d0636aSHans Petter Selasky { 68737d0636aSHans Petter Selasky struct libusb_container_id_descriptor *desc; 68837d0636aSHans Petter Selasky 68937d0636aSHans Petter Selasky if (dev_cap == NULL || container_id == NULL || 69037d0636aSHans Petter Selasky dev_cap->bDevCapabilityType != LIBUSB_BT_CONTAINER_ID) 69137d0636aSHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 69237d0636aSHans Petter Selasky if (dev_cap->bLength < LIBUSB_BT_CONTAINER_ID_SIZE) 69337d0636aSHans Petter Selasky return (LIBUSB_ERROR_IO); 69437d0636aSHans Petter Selasky 69537d0636aSHans Petter Selasky desc = malloc(sizeof(*desc)); 69637d0636aSHans Petter Selasky if (desc == NULL) 69737d0636aSHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 69837d0636aSHans Petter Selasky 69937d0636aSHans Petter Selasky desc->bLength = LIBUSB_BT_CONTAINER_ID_SIZE; 70037d0636aSHans Petter Selasky desc->bDescriptorType = dev_cap->bDescriptorType; 70137d0636aSHans Petter Selasky desc->bDevCapabilityType = dev_cap->bDevCapabilityType; 70237d0636aSHans Petter Selasky desc->bReserved = dev_cap->dev_capability_data[0]; 70337d0636aSHans Petter Selasky memcpy(desc->ContainerID, dev_cap->dev_capability_data + 1, 70437d0636aSHans Petter Selasky sizeof(desc->ContainerID)); 70537d0636aSHans Petter Selasky 70637d0636aSHans Petter Selasky *container_id = desc; 70737d0636aSHans Petter Selasky return (0); 70837d0636aSHans Petter Selasky } 70937d0636aSHans Petter Selasky 71037d0636aSHans Petter Selasky void 71137d0636aSHans Petter Selasky libusb_free_container_id_descriptor( 71237d0636aSHans Petter Selasky struct libusb_container_id_descriptor *container_id) 71337d0636aSHans Petter Selasky { 71437d0636aSHans Petter Selasky 71537d0636aSHans Petter Selasky free(container_id); 71637d0636aSHans Petter Selasky } 717