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 2766194130SHans Petter Selasky #ifdef LIBUSB_GLOBAL_INCLUDE_FILE 2866194130SHans Petter Selasky #include LIBUSB_GLOBAL_INCLUDE_FILE 2966194130SHans Petter Selasky #else 30f3cba95cSWojciech A. Koszek #include <stdio.h> 31f3cba95cSWojciech A. Koszek #include <stdlib.h> 3266194130SHans Petter Selasky #include <string.h> 3366194130SHans Petter Selasky #include <time.h> 3466194130SHans Petter Selasky #include <sys/queue.h> 3566194130SHans Petter Selasky #endif 36f3cba95cSWojciech A. Koszek 379c087c5aSAndrew Thompson #define libusb_device_handle libusb20_device 389c087c5aSAndrew Thompson 398c8fff31SAndrew Thompson #include "libusb20.h" 408c8fff31SAndrew Thompson #include "libusb20_desc.h" 418c8fff31SAndrew Thompson #include "libusb20_int.h" 428c8fff31SAndrew Thompson #include "libusb.h" 438c8fff31SAndrew Thompson #include "libusb10.h" 448c8fff31SAndrew Thompson 45ccef4ddfSAndrew Thompson #define N_ALIGN(n) (-((-(n)) & (-8UL))) 46ccef4ddfSAndrew Thompson 478c8fff31SAndrew Thompson /* USB descriptors */ 488c8fff31SAndrew Thompson 498c8fff31SAndrew Thompson int 508c8fff31SAndrew Thompson libusb_get_device_descriptor(libusb_device *dev, 518c8fff31SAndrew Thompson struct libusb_device_descriptor *desc) 528c8fff31SAndrew Thompson { 538c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 548c8fff31SAndrew Thompson struct libusb20_device *pdev; 558c8fff31SAndrew Thompson 568c8fff31SAndrew Thompson if ((dev == NULL) || (desc == NULL)) 578c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 588c8fff31SAndrew Thompson 598c8fff31SAndrew Thompson pdev = dev->os_priv; 608c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 618c8fff31SAndrew Thompson 628c8fff31SAndrew Thompson desc->bLength = pdesc->bLength; 638c8fff31SAndrew Thompson desc->bDescriptorType = pdesc->bDescriptorType; 648c8fff31SAndrew Thompson desc->bcdUSB = pdesc->bcdUSB; 658c8fff31SAndrew Thompson desc->bDeviceClass = pdesc->bDeviceClass; 668c8fff31SAndrew Thompson desc->bDeviceSubClass = pdesc->bDeviceSubClass; 678c8fff31SAndrew Thompson desc->bDeviceProtocol = pdesc->bDeviceProtocol; 688c8fff31SAndrew Thompson desc->bMaxPacketSize0 = pdesc->bMaxPacketSize0; 698c8fff31SAndrew Thompson desc->idVendor = pdesc->idVendor; 708c8fff31SAndrew Thompson desc->idProduct = pdesc->idProduct; 718c8fff31SAndrew Thompson desc->bcdDevice = pdesc->bcdDevice; 728c8fff31SAndrew Thompson desc->iManufacturer = pdesc->iManufacturer; 738c8fff31SAndrew Thompson desc->iProduct = pdesc->iProduct; 748c8fff31SAndrew Thompson desc->iSerialNumber = pdesc->iSerialNumber; 758c8fff31SAndrew Thompson desc->bNumConfigurations = pdesc->bNumConfigurations; 768c8fff31SAndrew Thompson 778c8fff31SAndrew Thompson return (0); 788c8fff31SAndrew Thompson } 798c8fff31SAndrew Thompson 808c8fff31SAndrew Thompson int 818c8fff31SAndrew Thompson libusb_get_active_config_descriptor(libusb_device *dev, 828c8fff31SAndrew Thompson struct libusb_config_descriptor **config) 838c8fff31SAndrew Thompson { 848c8fff31SAndrew Thompson struct libusb20_device *pdev; 85390065b1SAlfred Perlstein uint8_t config_index; 868c8fff31SAndrew Thompson 878c8fff31SAndrew Thompson pdev = dev->os_priv; 88390065b1SAlfred Perlstein config_index = libusb20_dev_get_config_index(pdev); 898c8fff31SAndrew Thompson 90390065b1SAlfred Perlstein return (libusb_get_config_descriptor(dev, config_index, config)); 918c8fff31SAndrew Thompson } 928c8fff31SAndrew Thompson 938c8fff31SAndrew Thompson int 948c8fff31SAndrew Thompson libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, 958c8fff31SAndrew Thompson struct libusb_config_descriptor **config) 968c8fff31SAndrew Thompson { 978c8fff31SAndrew Thompson struct libusb20_device *pdev; 988c8fff31SAndrew Thompson struct libusb20_config *pconf; 998c8fff31SAndrew Thompson struct libusb20_interface *pinf; 1008c8fff31SAndrew Thompson struct libusb20_endpoint *pend; 101390065b1SAlfred Perlstein struct libusb_config_descriptor *pconfd; 102390065b1SAlfred Perlstein struct libusb_interface_descriptor *ifd; 103390065b1SAlfred Perlstein struct libusb_endpoint_descriptor *endd; 104390065b1SAlfred Perlstein uint8_t *pextra; 105390065b1SAlfred Perlstein uint16_t nextra; 106390065b1SAlfred Perlstein uint8_t nif; 107390065b1SAlfred Perlstein uint8_t nep; 108390065b1SAlfred Perlstein uint8_t nalt; 109390065b1SAlfred Perlstein uint8_t i; 110390065b1SAlfred Perlstein uint8_t j; 111390065b1SAlfred Perlstein uint8_t k; 1128c8fff31SAndrew Thompson 1138c8fff31SAndrew Thompson if (dev == NULL || config == NULL) 1148c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 1158c8fff31SAndrew Thompson 116390065b1SAlfred Perlstein *config = NULL; 117390065b1SAlfred Perlstein 1188c8fff31SAndrew Thompson pdev = dev->os_priv; 1198c8fff31SAndrew Thompson pconf = libusb20_dev_alloc_config(pdev, config_index); 1208c8fff31SAndrew Thompson 1218c8fff31SAndrew Thompson if (pconf == NULL) 1228c8fff31SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 1238c8fff31SAndrew Thompson 1248c8fff31SAndrew Thompson nalt = nif = pconf->num_interface; 125390065b1SAlfred Perlstein nep = 0; 126ccef4ddfSAndrew Thompson nextra = N_ALIGN(pconf->extra.len); 127390065b1SAlfred Perlstein 1288c8fff31SAndrew Thompson for (i = 0; i < nif; i++) { 129390065b1SAlfred Perlstein 130390065b1SAlfred Perlstein pinf = pconf->interface + i; 131ccef4ddfSAndrew Thompson nextra += N_ALIGN(pinf->extra.len); 132390065b1SAlfred Perlstein nep += pinf->num_endpoints; 133390065b1SAlfred Perlstein k = pinf->num_endpoints; 134390065b1SAlfred Perlstein pend = pinf->endpoints; 135390065b1SAlfred Perlstein while (k--) { 136ccef4ddfSAndrew Thompson nextra += N_ALIGN(pend->extra.len); 137390065b1SAlfred Perlstein pend++; 1388c8fff31SAndrew Thompson } 1398c8fff31SAndrew Thompson 140390065b1SAlfred Perlstein j = pinf->num_altsetting; 141390065b1SAlfred Perlstein nalt += pinf->num_altsetting; 142390065b1SAlfred Perlstein pinf = pinf->altsetting; 143390065b1SAlfred Perlstein while (j--) { 144ccef4ddfSAndrew Thompson nextra += N_ALIGN(pinf->extra.len); 145390065b1SAlfred Perlstein nep += pinf->num_endpoints; 146390065b1SAlfred Perlstein k = pinf->num_endpoints; 147390065b1SAlfred Perlstein pend = pinf->endpoints; 148390065b1SAlfred Perlstein while (k--) { 149ccef4ddfSAndrew Thompson nextra += N_ALIGN(pend->extra.len); 150390065b1SAlfred Perlstein pend++; 151390065b1SAlfred Perlstein } 152390065b1SAlfred Perlstein pinf++; 153390065b1SAlfred Perlstein } 154390065b1SAlfred Perlstein } 155390065b1SAlfred Perlstein 156390065b1SAlfred Perlstein nextra = nextra + 157390065b1SAlfred Perlstein (1 * sizeof(libusb_config_descriptor)) + 1588c8fff31SAndrew Thompson (nif * sizeof(libusb_interface)) + 1598c8fff31SAndrew Thompson (nalt * sizeof(libusb_interface_descriptor)) + 160390065b1SAlfred Perlstein (nep * sizeof(libusb_endpoint_descriptor)); 161390065b1SAlfred Perlstein 162ccef4ddfSAndrew Thompson nextra = N_ALIGN(nextra); 163ccef4ddfSAndrew Thompson 164390065b1SAlfred Perlstein pconfd = malloc(nextra); 165390065b1SAlfred Perlstein 166390065b1SAlfred Perlstein if (pconfd == NULL) { 1678c8fff31SAndrew Thompson free(pconf); 1688c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 1698c8fff31SAndrew Thompson } 170ccef4ddfSAndrew Thompson /* make sure memory is initialised */ 171390065b1SAlfred Perlstein memset(pconfd, 0, nextra); 1728c8fff31SAndrew Thompson 173ccef4ddfSAndrew Thompson pconfd->interface = (libusb_interface *) (pconfd + 1); 1748c8fff31SAndrew Thompson 175390065b1SAlfred Perlstein ifd = (libusb_interface_descriptor *) (pconfd->interface + nif); 176390065b1SAlfred Perlstein endd = (libusb_endpoint_descriptor *) (ifd + nalt); 177390065b1SAlfred Perlstein pextra = (uint8_t *)(endd + nep); 178390065b1SAlfred Perlstein 179390065b1SAlfred Perlstein /* fill in config descriptor */ 180390065b1SAlfred Perlstein 181390065b1SAlfred Perlstein pconfd->bLength = pconf->desc.bLength; 182390065b1SAlfred Perlstein pconfd->bDescriptorType = pconf->desc.bDescriptorType; 183390065b1SAlfred Perlstein pconfd->wTotalLength = pconf->desc.wTotalLength; 184390065b1SAlfred Perlstein pconfd->bNumInterfaces = pconf->desc.bNumInterfaces; 185390065b1SAlfred Perlstein pconfd->bConfigurationValue = pconf->desc.bConfigurationValue; 186390065b1SAlfred Perlstein pconfd->iConfiguration = pconf->desc.iConfiguration; 187390065b1SAlfred Perlstein pconfd->bmAttributes = pconf->desc.bmAttributes; 188390065b1SAlfred Perlstein pconfd->MaxPower = pconf->desc.bMaxPower; 189390065b1SAlfred Perlstein 190390065b1SAlfred Perlstein if (pconf->extra.len != 0) { 191390065b1SAlfred Perlstein pconfd->extra_length = pconf->extra.len; 192390065b1SAlfred Perlstein pconfd->extra = pextra; 193390065b1SAlfred Perlstein memcpy(pextra, pconf->extra.ptr, pconfd->extra_length); 194ccef4ddfSAndrew Thompson pextra += N_ALIGN(pconfd->extra_length); 1958c8fff31SAndrew Thompson } 196390065b1SAlfred Perlstein /* setup all interface and endpoint pointers */ 197390065b1SAlfred Perlstein 198390065b1SAlfred Perlstein for (i = 0; i < nif; i++) { 199390065b1SAlfred Perlstein 200390065b1SAlfred Perlstein pconfd->interface[i].altsetting = ifd; 201390065b1SAlfred Perlstein ifd->endpoint = endd; 202390065b1SAlfred Perlstein endd += pconf->interface[i].num_endpoints; 203390065b1SAlfred Perlstein ifd++; 204390065b1SAlfred Perlstein 205390065b1SAlfred Perlstein for (j = 0; j < pconf->interface[i].num_altsetting; j++) { 206390065b1SAlfred Perlstein ifd->endpoint = endd; 207390065b1SAlfred Perlstein endd += pconf->interface[i].altsetting[j].num_endpoints; 208390065b1SAlfred Perlstein ifd++; 2098c8fff31SAndrew Thompson } 2108c8fff31SAndrew Thompson } 2118c8fff31SAndrew Thompson 212390065b1SAlfred Perlstein /* fill in all interface and endpoint data */ 2138c8fff31SAndrew Thompson 2148c8fff31SAndrew Thompson for (i = 0; i < nif; i++) { 2158c8fff31SAndrew Thompson pinf = &pconf->interface[i]; 216390065b1SAlfred Perlstein pconfd->interface[i].num_altsetting = pinf->num_altsetting + 1; 217390065b1SAlfred Perlstein for (j = 0; j < pconfd->interface[i].num_altsetting; j++) { 2188c8fff31SAndrew Thompson if (j != 0) 2198c8fff31SAndrew Thompson pinf = &pconf->interface[i].altsetting[j - 1]; 220390065b1SAlfred Perlstein ifd = &pconfd->interface[i].altsetting[j]; 2218c8fff31SAndrew Thompson ifd->bLength = pinf->desc.bLength; 2228c8fff31SAndrew Thompson ifd->bDescriptorType = pinf->desc.bDescriptorType; 2238c8fff31SAndrew Thompson ifd->bInterfaceNumber = pinf->desc.bInterfaceNumber; 2248c8fff31SAndrew Thompson ifd->bAlternateSetting = pinf->desc.bAlternateSetting; 2258c8fff31SAndrew Thompson ifd->bNumEndpoints = pinf->desc.bNumEndpoints; 2268c8fff31SAndrew Thompson ifd->bInterfaceClass = pinf->desc.bInterfaceClass; 2278c8fff31SAndrew Thompson ifd->bInterfaceSubClass = pinf->desc.bInterfaceSubClass; 2288c8fff31SAndrew Thompson ifd->bInterfaceProtocol = pinf->desc.bInterfaceProtocol; 2298c8fff31SAndrew Thompson ifd->iInterface = pinf->desc.iInterface; 230390065b1SAlfred Perlstein if (pinf->extra.len != 0) { 2318c8fff31SAndrew Thompson ifd->extra_length = pinf->extra.len; 232390065b1SAlfred Perlstein ifd->extra = pextra; 233390065b1SAlfred Perlstein memcpy(pextra, pinf->extra.ptr, pinf->extra.len); 234ccef4ddfSAndrew Thompson pextra += N_ALIGN(pinf->extra.len); 235390065b1SAlfred Perlstein } 2368c8fff31SAndrew Thompson for (k = 0; k < pinf->num_endpoints; k++) { 2378c8fff31SAndrew Thompson pend = &pinf->endpoints[k]; 2388c8fff31SAndrew Thompson endd = &ifd->endpoint[k]; 2398c8fff31SAndrew Thompson endd->bLength = pend->desc.bLength; 2408c8fff31SAndrew Thompson endd->bDescriptorType = pend->desc.bDescriptorType; 2418c8fff31SAndrew Thompson endd->bEndpointAddress = pend->desc.bEndpointAddress; 2428c8fff31SAndrew Thompson endd->bmAttributes = pend->desc.bmAttributes; 2438c8fff31SAndrew Thompson endd->wMaxPacketSize = pend->desc.wMaxPacketSize; 2448c8fff31SAndrew Thompson endd->bInterval = pend->desc.bInterval; 2458c8fff31SAndrew Thompson endd->bRefresh = pend->desc.bRefresh; 2468c8fff31SAndrew Thompson endd->bSynchAddress = pend->desc.bSynchAddress; 247390065b1SAlfred Perlstein if (pend->extra.len != 0) { 2488c8fff31SAndrew Thompson endd->extra_length = pend->extra.len; 249390065b1SAlfred Perlstein endd->extra = pextra; 250390065b1SAlfred Perlstein memcpy(pextra, pend->extra.ptr, pend->extra.len); 251ccef4ddfSAndrew Thompson pextra += N_ALIGN(pend->extra.len); 252390065b1SAlfred Perlstein } 2538c8fff31SAndrew Thompson } 2548c8fff31SAndrew Thompson } 2558c8fff31SAndrew Thompson } 2568c8fff31SAndrew Thompson 2578c8fff31SAndrew Thompson free(pconf); 258390065b1SAlfred Perlstein 259390065b1SAlfred Perlstein *config = pconfd; 260390065b1SAlfred Perlstein 261390065b1SAlfred Perlstein return (0); /* success */ 2628c8fff31SAndrew Thompson } 2638c8fff31SAndrew Thompson 2648c8fff31SAndrew Thompson int 2658c8fff31SAndrew Thompson libusb_get_config_descriptor_by_value(libusb_device *dev, 2668c8fff31SAndrew Thompson uint8_t bConfigurationValue, struct libusb_config_descriptor **config) 2678c8fff31SAndrew Thompson { 2688c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 2698c8fff31SAndrew Thompson struct libusb20_device *pdev; 2708c8fff31SAndrew Thompson int i; 271390065b1SAlfred Perlstein int err; 2728c8fff31SAndrew Thompson 2738c8fff31SAndrew Thompson if (dev == NULL || config == NULL) 2748c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 2758c8fff31SAndrew Thompson 2768c8fff31SAndrew Thompson pdev = dev->os_priv; 2778c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 2788c8fff31SAndrew Thompson 2798c8fff31SAndrew Thompson for (i = 0; i < pdesc->bNumConfigurations; i++) { 280390065b1SAlfred Perlstein err = libusb_get_config_descriptor(dev, i, config); 281390065b1SAlfred Perlstein if (err) 282390065b1SAlfred Perlstein return (err); 2838c8fff31SAndrew Thompson 284390065b1SAlfred Perlstein if ((*config)->bConfigurationValue == bConfigurationValue) 285390065b1SAlfred Perlstein return (0); /* success */ 286390065b1SAlfred Perlstein 287390065b1SAlfred Perlstein libusb_free_config_descriptor(*config); 2888c8fff31SAndrew Thompson } 2898c8fff31SAndrew Thompson 290390065b1SAlfred Perlstein *config = NULL; 291390065b1SAlfred Perlstein 2928c8fff31SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 2938c8fff31SAndrew Thompson } 2948c8fff31SAndrew Thompson 2958c8fff31SAndrew Thompson void 2968c8fff31SAndrew Thompson libusb_free_config_descriptor(struct libusb_config_descriptor *config) 2978c8fff31SAndrew Thompson { 2988c8fff31SAndrew Thompson free(config); 2998c8fff31SAndrew Thompson } 3008c8fff31SAndrew Thompson 3018c8fff31SAndrew Thompson int 30278ed0e49SHans Petter Selasky libusb_get_string_descriptor(libusb_device_handle *pdev, 30378ed0e49SHans Petter Selasky uint8_t desc_index, uint16_t langid, unsigned char *data, 30478ed0e49SHans Petter Selasky int length) 30578ed0e49SHans Petter Selasky { 30678ed0e49SHans Petter Selasky if (pdev == NULL || data == NULL || length < 1) 30778ed0e49SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 30878ed0e49SHans Petter Selasky 30978ed0e49SHans Petter Selasky if (length > 65535) 31078ed0e49SHans Petter Selasky length = 65535; 31178ed0e49SHans Petter Selasky 31278ed0e49SHans Petter Selasky /* put some default data into the destination buffer */ 31378ed0e49SHans Petter Selasky data[0] = 0; 31478ed0e49SHans Petter Selasky 31578ed0e49SHans Petter Selasky return (libusb_control_transfer(pdev, LIBUSB_ENDPOINT_IN, 31678ed0e49SHans Petter Selasky LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | desc_index, 31778ed0e49SHans Petter Selasky langid, data, length, 1000)); 31878ed0e49SHans Petter Selasky } 31978ed0e49SHans Petter Selasky 32078ed0e49SHans Petter Selasky int 321390065b1SAlfred Perlstein libusb_get_string_descriptor_ascii(libusb_device_handle *pdev, 3228c8fff31SAndrew Thompson uint8_t desc_index, unsigned char *data, int length) 3238c8fff31SAndrew Thompson { 324390065b1SAlfred Perlstein if (pdev == NULL || data == NULL || length < 1) 3254c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 3268c8fff31SAndrew Thompson 3274eb5923dSHans Petter Selasky if (length > 65535) 3284eb5923dSHans Petter Selasky length = 65535; 3294eb5923dSHans Petter Selasky 330390065b1SAlfred Perlstein /* put some default data into the destination buffer */ 331390065b1SAlfred Perlstein data[0] = 0; 332390065b1SAlfred Perlstein 3338c8fff31SAndrew Thompson if (libusb20_dev_req_string_simple_sync(pdev, desc_index, 3348c8fff31SAndrew Thompson data, length) == 0) 335*f357b4f6SHans Petter Selasky return (strlen((char *)data)); 3368c8fff31SAndrew Thompson 3378c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 3388c8fff31SAndrew Thompson } 339ccef4ddfSAndrew Thompson 340ccef4ddfSAndrew Thompson int 341ccef4ddfSAndrew Thompson libusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, 342ccef4ddfSAndrew Thompson uint8_t desc_index, uint8_t *data, int length) 343ccef4ddfSAndrew Thompson { 3444eb5923dSHans Petter Selasky if (devh == NULL || data == NULL || length < 1) 3454c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 3464eb5923dSHans Petter Selasky 3474eb5923dSHans Petter Selasky if (length > 65535) 3484eb5923dSHans Petter Selasky length = 65535; 3494eb5923dSHans Petter Selasky 350ccef4ddfSAndrew Thompson return (libusb_control_transfer(devh, LIBUSB_ENDPOINT_IN, 351ccef4ddfSAndrew Thompson LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, 352ccef4ddfSAndrew Thompson length, 1000)); 353ccef4ddfSAndrew Thompson } 3544c0392e6SHans Petter Selasky 3554c0392e6SHans Petter Selasky int 3564c0392e6SHans Petter Selasky libusb_parse_ss_endpoint_comp(const void *buf, int len, 3574c0392e6SHans Petter Selasky struct libusb_ss_endpoint_companion_descriptor **ep_comp) 3584c0392e6SHans Petter Selasky { 3594c0392e6SHans Petter Selasky if (buf == NULL || ep_comp == NULL || len < 1) 3604c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 3614c0392e6SHans Petter Selasky 3624c0392e6SHans Petter Selasky if (len > 65535) 3634c0392e6SHans Petter Selasky len = 65535; 3644c0392e6SHans Petter Selasky 3654c0392e6SHans Petter Selasky *ep_comp = NULL; 3664c0392e6SHans Petter Selasky 3674c0392e6SHans Petter Selasky while (len != 0) { 3684c0392e6SHans Petter Selasky uint8_t dlen; 3694c0392e6SHans Petter Selasky uint8_t dtype; 3704c0392e6SHans Petter Selasky 3714c0392e6SHans Petter Selasky dlen = ((const uint8_t *)buf)[0]; 3724c0392e6SHans Petter Selasky dtype = ((const uint8_t *)buf)[1]; 3734c0392e6SHans Petter Selasky 3744c0392e6SHans Petter Selasky if (dlen < 2 || dlen > len) 3754c0392e6SHans Petter Selasky break; 3764c0392e6SHans Petter Selasky 3774c0392e6SHans Petter Selasky if (dlen >= LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE && 3784c0392e6SHans Petter Selasky dtype == LIBUSB_DT_SS_ENDPOINT_COMPANION) { 3794c0392e6SHans Petter Selasky struct libusb_ss_endpoint_companion_descriptor *ptr; 3804c0392e6SHans Petter Selasky 3814c0392e6SHans Petter Selasky ptr = malloc(sizeof(*ptr)); 3824c0392e6SHans Petter Selasky if (ptr == NULL) 3834c0392e6SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 3844c0392e6SHans Petter Selasky 3854c0392e6SHans Petter Selasky ptr->bLength = LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE; 3864c0392e6SHans Petter Selasky ptr->bDescriptorType = dtype; 3874c0392e6SHans Petter Selasky ptr->bMaxBurst = ((const uint8_t *)buf)[2]; 3884c0392e6SHans Petter Selasky ptr->bmAttributes = ((const uint8_t *)buf)[3]; 3894c0392e6SHans Petter Selasky ptr->wBytesPerInterval = ((const uint8_t *)buf)[4] | 3904c0392e6SHans Petter Selasky (((const uint8_t *)buf)[5] << 8); 3914c0392e6SHans Petter Selasky 3924c0392e6SHans Petter Selasky *ep_comp = ptr; 3934c0392e6SHans Petter Selasky 3944c0392e6SHans Petter Selasky return (0); /* success */ 3954c0392e6SHans Petter Selasky } 3964c0392e6SHans Petter Selasky 3974c0392e6SHans Petter Selasky buf = ((const uint8_t *)buf) + dlen; 3984c0392e6SHans Petter Selasky len -= dlen; 3994c0392e6SHans Petter Selasky } 4004c0392e6SHans Petter Selasky return (LIBUSB_ERROR_IO); 4014c0392e6SHans Petter Selasky } 4024c0392e6SHans Petter Selasky 4034c0392e6SHans Petter Selasky void 4044c0392e6SHans Petter Selasky libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor *ep_comp) 4054c0392e6SHans Petter Selasky { 4064c0392e6SHans Petter Selasky if (ep_comp == NULL) 4074c0392e6SHans Petter Selasky return; 4084c0392e6SHans Petter Selasky 4094c0392e6SHans Petter Selasky free(ep_comp); 4104c0392e6SHans Petter Selasky } 4114c0392e6SHans Petter Selasky 4124c0392e6SHans Petter Selasky int 4134c0392e6SHans Petter Selasky libusb_parse_bos_descriptor(const void *buf, int len, 4144c0392e6SHans Petter Selasky struct libusb_bos_descriptor **bos) 4154c0392e6SHans Petter Selasky { 4164c0392e6SHans Petter Selasky struct libusb_bos_descriptor *ptr; 417d81535d1SHans Petter Selasky struct libusb_usb_2_0_device_capability_descriptor *dcap_20 = NULL; 418d81535d1SHans Petter Selasky struct libusb_ss_usb_device_capability_descriptor *ss_cap = NULL; 4194c0392e6SHans Petter Selasky 4204c0392e6SHans Petter Selasky if (buf == NULL || bos == NULL || len < 1) 4214c0392e6SHans Petter Selasky return (LIBUSB_ERROR_INVALID_PARAM); 4224c0392e6SHans Petter Selasky 4234c0392e6SHans Petter Selasky if (len > 65535) 4244c0392e6SHans Petter Selasky len = 65535; 4254c0392e6SHans Petter Selasky 4264c0392e6SHans Petter Selasky *bos = ptr = NULL; 4274c0392e6SHans Petter Selasky 4284c0392e6SHans Petter Selasky while (len != 0) { 4294c0392e6SHans Petter Selasky uint8_t dlen; 4304c0392e6SHans Petter Selasky uint8_t dtype; 4314c0392e6SHans Petter Selasky 4324c0392e6SHans Petter Selasky dlen = ((const uint8_t *)buf)[0]; 4334c0392e6SHans Petter Selasky dtype = ((const uint8_t *)buf)[1]; 4344c0392e6SHans Petter Selasky 4354c0392e6SHans Petter Selasky if (dlen < 2 || dlen > len) 4364c0392e6SHans Petter Selasky break; 4374c0392e6SHans Petter Selasky 4384c0392e6SHans Petter Selasky if (dlen >= LIBUSB_DT_BOS_SIZE && 4394c0392e6SHans Petter Selasky dtype == LIBUSB_DT_BOS) { 4404c0392e6SHans Petter Selasky 4414c0392e6SHans Petter Selasky ptr = malloc(sizeof(*ptr) + sizeof(*dcap_20) + 4424c0392e6SHans Petter Selasky sizeof(*ss_cap)); 4434c0392e6SHans Petter Selasky 4444c0392e6SHans Petter Selasky if (ptr == NULL) 4454c0392e6SHans Petter Selasky return (LIBUSB_ERROR_NO_MEM); 4464c0392e6SHans Petter Selasky 4474c0392e6SHans Petter Selasky *bos = ptr; 4484c0392e6SHans Petter Selasky 4494c0392e6SHans Petter Selasky ptr->bLength = LIBUSB_DT_BOS_SIZE; 4504c0392e6SHans Petter Selasky ptr->bDescriptorType = dtype; 4514c0392e6SHans Petter Selasky ptr->wTotalLength = ((const uint8_t *)buf)[2] | 4524c0392e6SHans Petter Selasky (((const uint8_t *)buf)[3] << 8); 4534c0392e6SHans Petter Selasky ptr->bNumDeviceCapabilities = ((const uint8_t *)buf)[4]; 4544c0392e6SHans Petter Selasky ptr->usb_2_0_ext_cap = NULL; 4554c0392e6SHans Petter Selasky ptr->ss_usb_cap = NULL; 4564c0392e6SHans Petter Selasky 4574c0392e6SHans Petter Selasky dcap_20 = (void *)(ptr + 1); 4584c0392e6SHans Petter Selasky ss_cap = (void *)(dcap_20 + 1); 4594c0392e6SHans Petter Selasky } 4604c0392e6SHans Petter Selasky if (dlen >= 3 && 4614c0392e6SHans Petter Selasky ptr != NULL && 4624c0392e6SHans Petter Selasky dtype == LIBUSB_DT_DEVICE_CAPABILITY) { 4634c0392e6SHans Petter Selasky switch (((const uint8_t *)buf)[2]) { 4644c0392e6SHans Petter Selasky case LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY: 465d81535d1SHans Petter Selasky if (ptr->usb_2_0_ext_cap != NULL || dcap_20 == NULL) 4664c0392e6SHans Petter Selasky break; 4674c0392e6SHans Petter Selasky if (dlen < LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE) 4684c0392e6SHans Petter Selasky break; 4694c0392e6SHans Petter Selasky 4704c0392e6SHans Petter Selasky ptr->usb_2_0_ext_cap = dcap_20; 4714c0392e6SHans Petter Selasky 4724c0392e6SHans Petter Selasky dcap_20->bLength = LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE; 4734c0392e6SHans Petter Selasky dcap_20->bDescriptorType = dtype; 4744c0392e6SHans Petter Selasky dcap_20->bDevCapabilityType = ((const uint8_t *)buf)[2]; 4754c0392e6SHans Petter Selasky dcap_20->bmAttributes = ((const uint8_t *)buf)[3] | 4764c0392e6SHans Petter Selasky (((const uint8_t *)buf)[4] << 8) | 4774c0392e6SHans Petter Selasky (((const uint8_t *)buf)[5] << 16) | 4784c0392e6SHans Petter Selasky (((const uint8_t *)buf)[6] << 24); 4794c0392e6SHans Petter Selasky break; 4804c0392e6SHans Petter Selasky 4814c0392e6SHans Petter Selasky case LIBUSB_SS_USB_DEVICE_CAPABILITY: 482d81535d1SHans Petter Selasky if (ptr->ss_usb_cap != NULL || ss_cap == NULL) 4834c0392e6SHans Petter Selasky break; 4844c0392e6SHans Petter Selasky if (dlen < LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE) 4854c0392e6SHans Petter Selasky break; 4864c0392e6SHans Petter Selasky 4874c0392e6SHans Petter Selasky ptr->ss_usb_cap = ss_cap; 4884c0392e6SHans Petter Selasky 4894c0392e6SHans Petter Selasky ss_cap->bLength = LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE; 4904c0392e6SHans Petter Selasky ss_cap->bDescriptorType = dtype; 4914c0392e6SHans Petter Selasky ss_cap->bDevCapabilityType = ((const uint8_t *)buf)[2]; 4924c0392e6SHans Petter Selasky ss_cap->bmAttributes = ((const uint8_t *)buf)[3]; 4934c0392e6SHans Petter Selasky ss_cap->wSpeedSupported = ((const uint8_t *)buf)[4] | 4944c0392e6SHans Petter Selasky (((const uint8_t *)buf)[5] << 8); 4954c0392e6SHans Petter Selasky ss_cap->bFunctionalitySupport = ((const uint8_t *)buf)[6]; 4964c0392e6SHans Petter Selasky ss_cap->bU1DevExitLat = ((const uint8_t *)buf)[7]; 4974c0392e6SHans Petter Selasky ss_cap->wU2DevExitLat = ((const uint8_t *)buf)[8] | 4984c0392e6SHans Petter Selasky (((const uint8_t *)buf)[9] << 8); 4994c0392e6SHans Petter Selasky break; 5004c0392e6SHans Petter Selasky 5014c0392e6SHans Petter Selasky default: 5024c0392e6SHans Petter Selasky break; 5034c0392e6SHans Petter Selasky } 5044c0392e6SHans Petter Selasky } 5054c0392e6SHans Petter Selasky 5064c0392e6SHans Petter Selasky buf = ((const uint8_t *)buf) + dlen; 5074c0392e6SHans Petter Selasky len -= dlen; 5084c0392e6SHans Petter Selasky } 5094c0392e6SHans Petter Selasky if (ptr != NULL) 5104c0392e6SHans Petter Selasky return (0); /* success */ 5114c0392e6SHans Petter Selasky 5124c0392e6SHans Petter Selasky return (LIBUSB_ERROR_IO); 5134c0392e6SHans Petter Selasky } 5144c0392e6SHans Petter Selasky 5154c0392e6SHans Petter Selasky void 5164c0392e6SHans Petter Selasky libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) 5174c0392e6SHans Petter Selasky { 5184c0392e6SHans Petter Selasky if (bos == NULL) 5194c0392e6SHans Petter Selasky return; 5204c0392e6SHans Petter Selasky 5214c0392e6SHans Petter Selasky free(bos); 5224c0392e6SHans Petter Selasky } 523