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 278c8fff31SAndrew Thompson #include <stdlib.h> 288c8fff31SAndrew Thompson #include <stdio.h> 298c8fff31SAndrew Thompson #include <pthread.h> 30390065b1SAlfred Perlstein #include <sys/queue.h> 318c8fff31SAndrew Thompson 328c8fff31SAndrew Thompson #include "libusb20.h" 338c8fff31SAndrew Thompson #include "libusb20_desc.h" 348c8fff31SAndrew Thompson #include "libusb20_int.h" 358c8fff31SAndrew Thompson #include "libusb.h" 368c8fff31SAndrew Thompson #include "libusb10.h" 378c8fff31SAndrew Thompson 38ccef4ddfSAndrew Thompson #define N_ALIGN(n) (-((-(n)) & (-8UL))) 39ccef4ddfSAndrew Thompson 408c8fff31SAndrew Thompson /* USB descriptors */ 418c8fff31SAndrew Thompson 428c8fff31SAndrew Thompson int 438c8fff31SAndrew Thompson libusb_get_device_descriptor(libusb_device *dev, 448c8fff31SAndrew Thompson struct libusb_device_descriptor *desc) 458c8fff31SAndrew Thompson { 468c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 478c8fff31SAndrew Thompson struct libusb20_device *pdev; 488c8fff31SAndrew Thompson 498c8fff31SAndrew Thompson if ((dev == NULL) || (desc == NULL)) 508c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 518c8fff31SAndrew Thompson 528c8fff31SAndrew Thompson pdev = dev->os_priv; 538c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 548c8fff31SAndrew Thompson 558c8fff31SAndrew Thompson desc->bLength = pdesc->bLength; 568c8fff31SAndrew Thompson desc->bDescriptorType = pdesc->bDescriptorType; 578c8fff31SAndrew Thompson desc->bcdUSB = pdesc->bcdUSB; 588c8fff31SAndrew Thompson desc->bDeviceClass = pdesc->bDeviceClass; 598c8fff31SAndrew Thompson desc->bDeviceSubClass = pdesc->bDeviceSubClass; 608c8fff31SAndrew Thompson desc->bDeviceProtocol = pdesc->bDeviceProtocol; 618c8fff31SAndrew Thompson desc->bMaxPacketSize0 = pdesc->bMaxPacketSize0; 628c8fff31SAndrew Thompson desc->idVendor = pdesc->idVendor; 638c8fff31SAndrew Thompson desc->idProduct = pdesc->idProduct; 648c8fff31SAndrew Thompson desc->bcdDevice = pdesc->bcdDevice; 658c8fff31SAndrew Thompson desc->iManufacturer = pdesc->iManufacturer; 668c8fff31SAndrew Thompson desc->iProduct = pdesc->iProduct; 678c8fff31SAndrew Thompson desc->iSerialNumber = pdesc->iSerialNumber; 688c8fff31SAndrew Thompson desc->bNumConfigurations = pdesc->bNumConfigurations; 698c8fff31SAndrew Thompson 708c8fff31SAndrew Thompson return (0); 718c8fff31SAndrew Thompson } 728c8fff31SAndrew Thompson 738c8fff31SAndrew Thompson int 748c8fff31SAndrew Thompson libusb_get_active_config_descriptor(libusb_device *dev, 758c8fff31SAndrew Thompson struct libusb_config_descriptor **config) 768c8fff31SAndrew Thompson { 778c8fff31SAndrew Thompson struct libusb20_device *pdev; 78390065b1SAlfred Perlstein uint8_t config_index; 798c8fff31SAndrew Thompson 808c8fff31SAndrew Thompson pdev = dev->os_priv; 81390065b1SAlfred Perlstein config_index = libusb20_dev_get_config_index(pdev); 828c8fff31SAndrew Thompson 83390065b1SAlfred Perlstein return (libusb_get_config_descriptor(dev, config_index, config)); 848c8fff31SAndrew Thompson } 858c8fff31SAndrew Thompson 868c8fff31SAndrew Thompson int 878c8fff31SAndrew Thompson libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, 888c8fff31SAndrew Thompson struct libusb_config_descriptor **config) 898c8fff31SAndrew Thompson { 908c8fff31SAndrew Thompson struct libusb20_device *pdev; 918c8fff31SAndrew Thompson struct libusb20_config *pconf; 928c8fff31SAndrew Thompson struct libusb20_interface *pinf; 938c8fff31SAndrew Thompson struct libusb20_endpoint *pend; 94390065b1SAlfred Perlstein struct libusb_config_descriptor *pconfd; 95390065b1SAlfred Perlstein struct libusb_interface_descriptor *ifd; 96390065b1SAlfred Perlstein struct libusb_endpoint_descriptor *endd; 97390065b1SAlfred Perlstein uint8_t *pextra; 98390065b1SAlfred Perlstein uint16_t nextra; 99390065b1SAlfred Perlstein uint8_t nif; 100390065b1SAlfred Perlstein uint8_t nep; 101390065b1SAlfred Perlstein uint8_t nalt; 102390065b1SAlfred Perlstein uint8_t i; 103390065b1SAlfred Perlstein uint8_t j; 104390065b1SAlfred Perlstein uint8_t k; 1058c8fff31SAndrew Thompson 1068c8fff31SAndrew Thompson if (dev == NULL || config == NULL) 1078c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 1088c8fff31SAndrew Thompson 109390065b1SAlfred Perlstein *config = NULL; 110390065b1SAlfred Perlstein 1118c8fff31SAndrew Thompson pdev = dev->os_priv; 1128c8fff31SAndrew Thompson pconf = libusb20_dev_alloc_config(pdev, config_index); 1138c8fff31SAndrew Thompson 1148c8fff31SAndrew Thompson if (pconf == NULL) 1158c8fff31SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 1168c8fff31SAndrew Thompson 1178c8fff31SAndrew Thompson nalt = nif = pconf->num_interface; 118390065b1SAlfred Perlstein nep = 0; 119ccef4ddfSAndrew Thompson nextra = N_ALIGN(pconf->extra.len); 120390065b1SAlfred Perlstein 1218c8fff31SAndrew Thompson for (i = 0; i < nif; i++) { 122390065b1SAlfred Perlstein 123390065b1SAlfred Perlstein pinf = pconf->interface + i; 124ccef4ddfSAndrew Thompson nextra += N_ALIGN(pinf->extra.len); 125390065b1SAlfred Perlstein nep += pinf->num_endpoints; 126390065b1SAlfred Perlstein k = pinf->num_endpoints; 127390065b1SAlfred Perlstein pend = pinf->endpoints; 128390065b1SAlfred Perlstein while (k--) { 129ccef4ddfSAndrew Thompson nextra += N_ALIGN(pend->extra.len); 130390065b1SAlfred Perlstein pend++; 1318c8fff31SAndrew Thompson } 1328c8fff31SAndrew Thompson 133390065b1SAlfred Perlstein j = pinf->num_altsetting; 134390065b1SAlfred Perlstein nalt += pinf->num_altsetting; 135390065b1SAlfred Perlstein pinf = pinf->altsetting; 136390065b1SAlfred Perlstein while (j--) { 137ccef4ddfSAndrew Thompson nextra += N_ALIGN(pinf->extra.len); 138390065b1SAlfred Perlstein nep += pinf->num_endpoints; 139390065b1SAlfred Perlstein k = pinf->num_endpoints; 140390065b1SAlfred Perlstein pend = pinf->endpoints; 141390065b1SAlfred Perlstein while (k--) { 142ccef4ddfSAndrew Thompson nextra += N_ALIGN(pend->extra.len); 143390065b1SAlfred Perlstein pend++; 144390065b1SAlfred Perlstein } 145390065b1SAlfred Perlstein pinf++; 146390065b1SAlfred Perlstein } 147390065b1SAlfred Perlstein } 148390065b1SAlfred Perlstein 149390065b1SAlfred Perlstein nextra = nextra + 150390065b1SAlfred Perlstein (1 * sizeof(libusb_config_descriptor)) + 1518c8fff31SAndrew Thompson (nif * sizeof(libusb_interface)) + 1528c8fff31SAndrew Thompson (nalt * sizeof(libusb_interface_descriptor)) + 153390065b1SAlfred Perlstein (nep * sizeof(libusb_endpoint_descriptor)); 154390065b1SAlfred Perlstein 155ccef4ddfSAndrew Thompson nextra = N_ALIGN(nextra); 156ccef4ddfSAndrew Thompson 157390065b1SAlfred Perlstein pconfd = malloc(nextra); 158390065b1SAlfred Perlstein 159390065b1SAlfred Perlstein if (pconfd == NULL) { 1608c8fff31SAndrew Thompson free(pconf); 1618c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 1628c8fff31SAndrew Thompson } 163ccef4ddfSAndrew Thompson /* make sure memory is initialised */ 164390065b1SAlfred Perlstein memset(pconfd, 0, nextra); 1658c8fff31SAndrew Thompson 166ccef4ddfSAndrew Thompson pconfd->interface = (libusb_interface *) (pconfd + 1); 1678c8fff31SAndrew Thompson 168390065b1SAlfred Perlstein ifd = (libusb_interface_descriptor *) (pconfd->interface + nif); 169390065b1SAlfred Perlstein endd = (libusb_endpoint_descriptor *) (ifd + nalt); 170390065b1SAlfred Perlstein pextra = (uint8_t *)(endd + nep); 171390065b1SAlfred Perlstein 172390065b1SAlfred Perlstein /* fill in config descriptor */ 173390065b1SAlfred Perlstein 174390065b1SAlfred Perlstein pconfd->bLength = pconf->desc.bLength; 175390065b1SAlfred Perlstein pconfd->bDescriptorType = pconf->desc.bDescriptorType; 176390065b1SAlfred Perlstein pconfd->wTotalLength = pconf->desc.wTotalLength; 177390065b1SAlfred Perlstein pconfd->bNumInterfaces = pconf->desc.bNumInterfaces; 178390065b1SAlfred Perlstein pconfd->bConfigurationValue = pconf->desc.bConfigurationValue; 179390065b1SAlfred Perlstein pconfd->iConfiguration = pconf->desc.iConfiguration; 180390065b1SAlfred Perlstein pconfd->bmAttributes = pconf->desc.bmAttributes; 181390065b1SAlfred Perlstein pconfd->MaxPower = pconf->desc.bMaxPower; 182390065b1SAlfred Perlstein 183390065b1SAlfred Perlstein if (pconf->extra.len != 0) { 184390065b1SAlfred Perlstein pconfd->extra_length = pconf->extra.len; 185390065b1SAlfred Perlstein pconfd->extra = pextra; 186390065b1SAlfred Perlstein memcpy(pextra, pconf->extra.ptr, pconfd->extra_length); 187ccef4ddfSAndrew Thompson pextra += N_ALIGN(pconfd->extra_length); 1888c8fff31SAndrew Thompson } 189390065b1SAlfred Perlstein /* setup all interface and endpoint pointers */ 190390065b1SAlfred Perlstein 191390065b1SAlfred Perlstein for (i = 0; i < nif; i++) { 192390065b1SAlfred Perlstein 193390065b1SAlfred Perlstein pconfd->interface[i].altsetting = ifd; 194390065b1SAlfred Perlstein ifd->endpoint = endd; 195390065b1SAlfred Perlstein endd += pconf->interface[i].num_endpoints; 196390065b1SAlfred Perlstein ifd++; 197390065b1SAlfred Perlstein 198390065b1SAlfred Perlstein for (j = 0; j < pconf->interface[i].num_altsetting; j++) { 199390065b1SAlfred Perlstein ifd->endpoint = endd; 200390065b1SAlfred Perlstein endd += pconf->interface[i].altsetting[j].num_endpoints; 201390065b1SAlfred Perlstein ifd++; 2028c8fff31SAndrew Thompson } 2038c8fff31SAndrew Thompson } 2048c8fff31SAndrew Thompson 205390065b1SAlfred Perlstein /* fill in all interface and endpoint data */ 2068c8fff31SAndrew Thompson 2078c8fff31SAndrew Thompson for (i = 0; i < nif; i++) { 2088c8fff31SAndrew Thompson pinf = &pconf->interface[i]; 209390065b1SAlfred Perlstein pconfd->interface[i].num_altsetting = pinf->num_altsetting + 1; 210390065b1SAlfred Perlstein for (j = 0; j < pconfd->interface[i].num_altsetting; j++) { 2118c8fff31SAndrew Thompson if (j != 0) 2128c8fff31SAndrew Thompson pinf = &pconf->interface[i].altsetting[j - 1]; 213390065b1SAlfred Perlstein ifd = &pconfd->interface[i].altsetting[j]; 2148c8fff31SAndrew Thompson ifd->bLength = pinf->desc.bLength; 2158c8fff31SAndrew Thompson ifd->bDescriptorType = pinf->desc.bDescriptorType; 2168c8fff31SAndrew Thompson ifd->bInterfaceNumber = pinf->desc.bInterfaceNumber; 2178c8fff31SAndrew Thompson ifd->bAlternateSetting = pinf->desc.bAlternateSetting; 2188c8fff31SAndrew Thompson ifd->bNumEndpoints = pinf->desc.bNumEndpoints; 2198c8fff31SAndrew Thompson ifd->bInterfaceClass = pinf->desc.bInterfaceClass; 2208c8fff31SAndrew Thompson ifd->bInterfaceSubClass = pinf->desc.bInterfaceSubClass; 2218c8fff31SAndrew Thompson ifd->bInterfaceProtocol = pinf->desc.bInterfaceProtocol; 2228c8fff31SAndrew Thompson ifd->iInterface = pinf->desc.iInterface; 223390065b1SAlfred Perlstein if (pinf->extra.len != 0) { 2248c8fff31SAndrew Thompson ifd->extra_length = pinf->extra.len; 225390065b1SAlfred Perlstein ifd->extra = pextra; 226390065b1SAlfred Perlstein memcpy(pextra, pinf->extra.ptr, pinf->extra.len); 227ccef4ddfSAndrew Thompson pextra += N_ALIGN(pinf->extra.len); 228390065b1SAlfred Perlstein } 2298c8fff31SAndrew Thompson for (k = 0; k < pinf->num_endpoints; k++) { 2308c8fff31SAndrew Thompson pend = &pinf->endpoints[k]; 2318c8fff31SAndrew Thompson endd = &ifd->endpoint[k]; 2328c8fff31SAndrew Thompson endd->bLength = pend->desc.bLength; 2338c8fff31SAndrew Thompson endd->bDescriptorType = pend->desc.bDescriptorType; 2348c8fff31SAndrew Thompson endd->bEndpointAddress = pend->desc.bEndpointAddress; 2358c8fff31SAndrew Thompson endd->bmAttributes = pend->desc.bmAttributes; 2368c8fff31SAndrew Thompson endd->wMaxPacketSize = pend->desc.wMaxPacketSize; 2378c8fff31SAndrew Thompson endd->bInterval = pend->desc.bInterval; 2388c8fff31SAndrew Thompson endd->bRefresh = pend->desc.bRefresh; 2398c8fff31SAndrew Thompson endd->bSynchAddress = pend->desc.bSynchAddress; 240390065b1SAlfred Perlstein if (pend->extra.len != 0) { 2418c8fff31SAndrew Thompson endd->extra_length = pend->extra.len; 242390065b1SAlfred Perlstein endd->extra = pextra; 243390065b1SAlfred Perlstein memcpy(pextra, pend->extra.ptr, pend->extra.len); 244ccef4ddfSAndrew Thompson pextra += N_ALIGN(pend->extra.len); 245390065b1SAlfred Perlstein } 2468c8fff31SAndrew Thompson } 2478c8fff31SAndrew Thompson } 2488c8fff31SAndrew Thompson } 2498c8fff31SAndrew Thompson 2508c8fff31SAndrew Thompson free(pconf); 251390065b1SAlfred Perlstein 252390065b1SAlfred Perlstein *config = pconfd; 253390065b1SAlfred Perlstein 254390065b1SAlfred Perlstein return (0); /* success */ 2558c8fff31SAndrew Thompson } 2568c8fff31SAndrew Thompson 2578c8fff31SAndrew Thompson int 2588c8fff31SAndrew Thompson libusb_get_config_descriptor_by_value(libusb_device *dev, 2598c8fff31SAndrew Thompson uint8_t bConfigurationValue, struct libusb_config_descriptor **config) 2608c8fff31SAndrew Thompson { 2618c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 2628c8fff31SAndrew Thompson struct libusb20_device *pdev; 2638c8fff31SAndrew Thompson int i; 264390065b1SAlfred Perlstein int err; 2658c8fff31SAndrew Thompson 2668c8fff31SAndrew Thompson if (dev == NULL || config == NULL) 2678c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 2688c8fff31SAndrew Thompson 2698c8fff31SAndrew Thompson pdev = dev->os_priv; 2708c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 2718c8fff31SAndrew Thompson 2728c8fff31SAndrew Thompson for (i = 0; i < pdesc->bNumConfigurations; i++) { 273390065b1SAlfred Perlstein err = libusb_get_config_descriptor(dev, i, config); 274390065b1SAlfred Perlstein if (err) 275390065b1SAlfred Perlstein return (err); 2768c8fff31SAndrew Thompson 277390065b1SAlfred Perlstein if ((*config)->bConfigurationValue == bConfigurationValue) 278390065b1SAlfred Perlstein return (0); /* success */ 279390065b1SAlfred Perlstein 280390065b1SAlfred Perlstein libusb_free_config_descriptor(*config); 2818c8fff31SAndrew Thompson } 2828c8fff31SAndrew Thompson 283390065b1SAlfred Perlstein *config = NULL; 284390065b1SAlfred Perlstein 2858c8fff31SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 2868c8fff31SAndrew Thompson } 2878c8fff31SAndrew Thompson 2888c8fff31SAndrew Thompson void 2898c8fff31SAndrew Thompson libusb_free_config_descriptor(struct libusb_config_descriptor *config) 2908c8fff31SAndrew Thompson { 2918c8fff31SAndrew Thompson free(config); 2928c8fff31SAndrew Thompson } 2938c8fff31SAndrew Thompson 2948c8fff31SAndrew Thompson int 295390065b1SAlfred Perlstein libusb_get_string_descriptor_ascii(libusb_device_handle *pdev, 2968c8fff31SAndrew Thompson uint8_t desc_index, unsigned char *data, int length) 2978c8fff31SAndrew Thompson { 298390065b1SAlfred Perlstein if (pdev == NULL || data == NULL || length < 1) 2998c8fff31SAndrew Thompson return (LIBUSB20_ERROR_INVALID_PARAM); 3008c8fff31SAndrew Thompson 301390065b1SAlfred Perlstein /* put some default data into the destination buffer */ 302390065b1SAlfred Perlstein data[0] = 0; 303390065b1SAlfred Perlstein 3048c8fff31SAndrew Thompson if (libusb20_dev_req_string_simple_sync(pdev, desc_index, 3058c8fff31SAndrew Thompson data, length) == 0) 3068c8fff31SAndrew Thompson return (strlen(data)); 3078c8fff31SAndrew Thompson 3088c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 3098c8fff31SAndrew Thompson } 310ccef4ddfSAndrew Thompson 311ccef4ddfSAndrew Thompson int 312ccef4ddfSAndrew Thompson libusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, 313ccef4ddfSAndrew Thompson uint8_t desc_index, uint8_t *data, int length) 314ccef4ddfSAndrew Thompson { 315ccef4ddfSAndrew Thompson return (libusb_control_transfer(devh, LIBUSB_ENDPOINT_IN, 316ccef4ddfSAndrew Thompson LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, 317ccef4ddfSAndrew Thompson length, 1000)); 318ccef4ddfSAndrew Thompson } 319