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 32*9c087c5aSAndrew Thompson #define libusb_device_handle libusb20_device 33*9c087c5aSAndrew Thompson 348c8fff31SAndrew Thompson #include "libusb20.h" 358c8fff31SAndrew Thompson #include "libusb20_desc.h" 368c8fff31SAndrew Thompson #include "libusb20_int.h" 378c8fff31SAndrew Thompson #include "libusb.h" 388c8fff31SAndrew Thompson #include "libusb10.h" 398c8fff31SAndrew Thompson 40ccef4ddfSAndrew Thompson #define N_ALIGN(n) (-((-(n)) & (-8UL))) 41ccef4ddfSAndrew Thompson 428c8fff31SAndrew Thompson /* USB descriptors */ 438c8fff31SAndrew Thompson 448c8fff31SAndrew Thompson int 458c8fff31SAndrew Thompson libusb_get_device_descriptor(libusb_device *dev, 468c8fff31SAndrew Thompson struct libusb_device_descriptor *desc) 478c8fff31SAndrew Thompson { 488c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 498c8fff31SAndrew Thompson struct libusb20_device *pdev; 508c8fff31SAndrew Thompson 518c8fff31SAndrew Thompson if ((dev == NULL) || (desc == NULL)) 528c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 538c8fff31SAndrew Thompson 548c8fff31SAndrew Thompson pdev = dev->os_priv; 558c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 568c8fff31SAndrew Thompson 578c8fff31SAndrew Thompson desc->bLength = pdesc->bLength; 588c8fff31SAndrew Thompson desc->bDescriptorType = pdesc->bDescriptorType; 598c8fff31SAndrew Thompson desc->bcdUSB = pdesc->bcdUSB; 608c8fff31SAndrew Thompson desc->bDeviceClass = pdesc->bDeviceClass; 618c8fff31SAndrew Thompson desc->bDeviceSubClass = pdesc->bDeviceSubClass; 628c8fff31SAndrew Thompson desc->bDeviceProtocol = pdesc->bDeviceProtocol; 638c8fff31SAndrew Thompson desc->bMaxPacketSize0 = pdesc->bMaxPacketSize0; 648c8fff31SAndrew Thompson desc->idVendor = pdesc->idVendor; 658c8fff31SAndrew Thompson desc->idProduct = pdesc->idProduct; 668c8fff31SAndrew Thompson desc->bcdDevice = pdesc->bcdDevice; 678c8fff31SAndrew Thompson desc->iManufacturer = pdesc->iManufacturer; 688c8fff31SAndrew Thompson desc->iProduct = pdesc->iProduct; 698c8fff31SAndrew Thompson desc->iSerialNumber = pdesc->iSerialNumber; 708c8fff31SAndrew Thompson desc->bNumConfigurations = pdesc->bNumConfigurations; 718c8fff31SAndrew Thompson 728c8fff31SAndrew Thompson return (0); 738c8fff31SAndrew Thompson } 748c8fff31SAndrew Thompson 758c8fff31SAndrew Thompson int 768c8fff31SAndrew Thompson libusb_get_active_config_descriptor(libusb_device *dev, 778c8fff31SAndrew Thompson struct libusb_config_descriptor **config) 788c8fff31SAndrew Thompson { 798c8fff31SAndrew Thompson struct libusb20_device *pdev; 80390065b1SAlfred Perlstein uint8_t config_index; 818c8fff31SAndrew Thompson 828c8fff31SAndrew Thompson pdev = dev->os_priv; 83390065b1SAlfred Perlstein config_index = libusb20_dev_get_config_index(pdev); 848c8fff31SAndrew Thompson 85390065b1SAlfred Perlstein return (libusb_get_config_descriptor(dev, config_index, config)); 868c8fff31SAndrew Thompson } 878c8fff31SAndrew Thompson 888c8fff31SAndrew Thompson int 898c8fff31SAndrew Thompson libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, 908c8fff31SAndrew Thompson struct libusb_config_descriptor **config) 918c8fff31SAndrew Thompson { 928c8fff31SAndrew Thompson struct libusb20_device *pdev; 938c8fff31SAndrew Thompson struct libusb20_config *pconf; 948c8fff31SAndrew Thompson struct libusb20_interface *pinf; 958c8fff31SAndrew Thompson struct libusb20_endpoint *pend; 96390065b1SAlfred Perlstein struct libusb_config_descriptor *pconfd; 97390065b1SAlfred Perlstein struct libusb_interface_descriptor *ifd; 98390065b1SAlfred Perlstein struct libusb_endpoint_descriptor *endd; 99390065b1SAlfred Perlstein uint8_t *pextra; 100390065b1SAlfred Perlstein uint16_t nextra; 101390065b1SAlfred Perlstein uint8_t nif; 102390065b1SAlfred Perlstein uint8_t nep; 103390065b1SAlfred Perlstein uint8_t nalt; 104390065b1SAlfred Perlstein uint8_t i; 105390065b1SAlfred Perlstein uint8_t j; 106390065b1SAlfred Perlstein uint8_t k; 1078c8fff31SAndrew Thompson 1088c8fff31SAndrew Thompson if (dev == NULL || config == NULL) 1098c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 1108c8fff31SAndrew Thompson 111390065b1SAlfred Perlstein *config = NULL; 112390065b1SAlfred Perlstein 1138c8fff31SAndrew Thompson pdev = dev->os_priv; 1148c8fff31SAndrew Thompson pconf = libusb20_dev_alloc_config(pdev, config_index); 1158c8fff31SAndrew Thompson 1168c8fff31SAndrew Thompson if (pconf == NULL) 1178c8fff31SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 1188c8fff31SAndrew Thompson 1198c8fff31SAndrew Thompson nalt = nif = pconf->num_interface; 120390065b1SAlfred Perlstein nep = 0; 121ccef4ddfSAndrew Thompson nextra = N_ALIGN(pconf->extra.len); 122390065b1SAlfred Perlstein 1238c8fff31SAndrew Thompson for (i = 0; i < nif; i++) { 124390065b1SAlfred Perlstein 125390065b1SAlfred Perlstein pinf = pconf->interface + i; 126ccef4ddfSAndrew Thompson nextra += N_ALIGN(pinf->extra.len); 127390065b1SAlfred Perlstein nep += pinf->num_endpoints; 128390065b1SAlfred Perlstein k = pinf->num_endpoints; 129390065b1SAlfred Perlstein pend = pinf->endpoints; 130390065b1SAlfred Perlstein while (k--) { 131ccef4ddfSAndrew Thompson nextra += N_ALIGN(pend->extra.len); 132390065b1SAlfred Perlstein pend++; 1338c8fff31SAndrew Thompson } 1348c8fff31SAndrew Thompson 135390065b1SAlfred Perlstein j = pinf->num_altsetting; 136390065b1SAlfred Perlstein nalt += pinf->num_altsetting; 137390065b1SAlfred Perlstein pinf = pinf->altsetting; 138390065b1SAlfred Perlstein while (j--) { 139ccef4ddfSAndrew Thompson nextra += N_ALIGN(pinf->extra.len); 140390065b1SAlfred Perlstein nep += pinf->num_endpoints; 141390065b1SAlfred Perlstein k = pinf->num_endpoints; 142390065b1SAlfred Perlstein pend = pinf->endpoints; 143390065b1SAlfred Perlstein while (k--) { 144ccef4ddfSAndrew Thompson nextra += N_ALIGN(pend->extra.len); 145390065b1SAlfred Perlstein pend++; 146390065b1SAlfred Perlstein } 147390065b1SAlfred Perlstein pinf++; 148390065b1SAlfred Perlstein } 149390065b1SAlfred Perlstein } 150390065b1SAlfred Perlstein 151390065b1SAlfred Perlstein nextra = nextra + 152390065b1SAlfred Perlstein (1 * sizeof(libusb_config_descriptor)) + 1538c8fff31SAndrew Thompson (nif * sizeof(libusb_interface)) + 1548c8fff31SAndrew Thompson (nalt * sizeof(libusb_interface_descriptor)) + 155390065b1SAlfred Perlstein (nep * sizeof(libusb_endpoint_descriptor)); 156390065b1SAlfred Perlstein 157ccef4ddfSAndrew Thompson nextra = N_ALIGN(nextra); 158ccef4ddfSAndrew Thompson 159390065b1SAlfred Perlstein pconfd = malloc(nextra); 160390065b1SAlfred Perlstein 161390065b1SAlfred Perlstein if (pconfd == NULL) { 1628c8fff31SAndrew Thompson free(pconf); 1638c8fff31SAndrew Thompson return (LIBUSB_ERROR_NO_MEM); 1648c8fff31SAndrew Thompson } 165ccef4ddfSAndrew Thompson /* make sure memory is initialised */ 166390065b1SAlfred Perlstein memset(pconfd, 0, nextra); 1678c8fff31SAndrew Thompson 168ccef4ddfSAndrew Thompson pconfd->interface = (libusb_interface *) (pconfd + 1); 1698c8fff31SAndrew Thompson 170390065b1SAlfred Perlstein ifd = (libusb_interface_descriptor *) (pconfd->interface + nif); 171390065b1SAlfred Perlstein endd = (libusb_endpoint_descriptor *) (ifd + nalt); 172390065b1SAlfred Perlstein pextra = (uint8_t *)(endd + nep); 173390065b1SAlfred Perlstein 174390065b1SAlfred Perlstein /* fill in config descriptor */ 175390065b1SAlfred Perlstein 176390065b1SAlfred Perlstein pconfd->bLength = pconf->desc.bLength; 177390065b1SAlfred Perlstein pconfd->bDescriptorType = pconf->desc.bDescriptorType; 178390065b1SAlfred Perlstein pconfd->wTotalLength = pconf->desc.wTotalLength; 179390065b1SAlfred Perlstein pconfd->bNumInterfaces = pconf->desc.bNumInterfaces; 180390065b1SAlfred Perlstein pconfd->bConfigurationValue = pconf->desc.bConfigurationValue; 181390065b1SAlfred Perlstein pconfd->iConfiguration = pconf->desc.iConfiguration; 182390065b1SAlfred Perlstein pconfd->bmAttributes = pconf->desc.bmAttributes; 183390065b1SAlfred Perlstein pconfd->MaxPower = pconf->desc.bMaxPower; 184390065b1SAlfred Perlstein 185390065b1SAlfred Perlstein if (pconf->extra.len != 0) { 186390065b1SAlfred Perlstein pconfd->extra_length = pconf->extra.len; 187390065b1SAlfred Perlstein pconfd->extra = pextra; 188390065b1SAlfred Perlstein memcpy(pextra, pconf->extra.ptr, pconfd->extra_length); 189ccef4ddfSAndrew Thompson pextra += N_ALIGN(pconfd->extra_length); 1908c8fff31SAndrew Thompson } 191390065b1SAlfred Perlstein /* setup all interface and endpoint pointers */ 192390065b1SAlfred Perlstein 193390065b1SAlfred Perlstein for (i = 0; i < nif; i++) { 194390065b1SAlfred Perlstein 195390065b1SAlfred Perlstein pconfd->interface[i].altsetting = ifd; 196390065b1SAlfred Perlstein ifd->endpoint = endd; 197390065b1SAlfred Perlstein endd += pconf->interface[i].num_endpoints; 198390065b1SAlfred Perlstein ifd++; 199390065b1SAlfred Perlstein 200390065b1SAlfred Perlstein for (j = 0; j < pconf->interface[i].num_altsetting; j++) { 201390065b1SAlfred Perlstein ifd->endpoint = endd; 202390065b1SAlfred Perlstein endd += pconf->interface[i].altsetting[j].num_endpoints; 203390065b1SAlfred Perlstein ifd++; 2048c8fff31SAndrew Thompson } 2058c8fff31SAndrew Thompson } 2068c8fff31SAndrew Thompson 207390065b1SAlfred Perlstein /* fill in all interface and endpoint data */ 2088c8fff31SAndrew Thompson 2098c8fff31SAndrew Thompson for (i = 0; i < nif; i++) { 2108c8fff31SAndrew Thompson pinf = &pconf->interface[i]; 211390065b1SAlfred Perlstein pconfd->interface[i].num_altsetting = pinf->num_altsetting + 1; 212390065b1SAlfred Perlstein for (j = 0; j < pconfd->interface[i].num_altsetting; j++) { 2138c8fff31SAndrew Thompson if (j != 0) 2148c8fff31SAndrew Thompson pinf = &pconf->interface[i].altsetting[j - 1]; 215390065b1SAlfred Perlstein ifd = &pconfd->interface[i].altsetting[j]; 2168c8fff31SAndrew Thompson ifd->bLength = pinf->desc.bLength; 2178c8fff31SAndrew Thompson ifd->bDescriptorType = pinf->desc.bDescriptorType; 2188c8fff31SAndrew Thompson ifd->bInterfaceNumber = pinf->desc.bInterfaceNumber; 2198c8fff31SAndrew Thompson ifd->bAlternateSetting = pinf->desc.bAlternateSetting; 2208c8fff31SAndrew Thompson ifd->bNumEndpoints = pinf->desc.bNumEndpoints; 2218c8fff31SAndrew Thompson ifd->bInterfaceClass = pinf->desc.bInterfaceClass; 2228c8fff31SAndrew Thompson ifd->bInterfaceSubClass = pinf->desc.bInterfaceSubClass; 2238c8fff31SAndrew Thompson ifd->bInterfaceProtocol = pinf->desc.bInterfaceProtocol; 2248c8fff31SAndrew Thompson ifd->iInterface = pinf->desc.iInterface; 225390065b1SAlfred Perlstein if (pinf->extra.len != 0) { 2268c8fff31SAndrew Thompson ifd->extra_length = pinf->extra.len; 227390065b1SAlfred Perlstein ifd->extra = pextra; 228390065b1SAlfred Perlstein memcpy(pextra, pinf->extra.ptr, pinf->extra.len); 229ccef4ddfSAndrew Thompson pextra += N_ALIGN(pinf->extra.len); 230390065b1SAlfred Perlstein } 2318c8fff31SAndrew Thompson for (k = 0; k < pinf->num_endpoints; k++) { 2328c8fff31SAndrew Thompson pend = &pinf->endpoints[k]; 2338c8fff31SAndrew Thompson endd = &ifd->endpoint[k]; 2348c8fff31SAndrew Thompson endd->bLength = pend->desc.bLength; 2358c8fff31SAndrew Thompson endd->bDescriptorType = pend->desc.bDescriptorType; 2368c8fff31SAndrew Thompson endd->bEndpointAddress = pend->desc.bEndpointAddress; 2378c8fff31SAndrew Thompson endd->bmAttributes = pend->desc.bmAttributes; 2388c8fff31SAndrew Thompson endd->wMaxPacketSize = pend->desc.wMaxPacketSize; 2398c8fff31SAndrew Thompson endd->bInterval = pend->desc.bInterval; 2408c8fff31SAndrew Thompson endd->bRefresh = pend->desc.bRefresh; 2418c8fff31SAndrew Thompson endd->bSynchAddress = pend->desc.bSynchAddress; 242390065b1SAlfred Perlstein if (pend->extra.len != 0) { 2438c8fff31SAndrew Thompson endd->extra_length = pend->extra.len; 244390065b1SAlfred Perlstein endd->extra = pextra; 245390065b1SAlfred Perlstein memcpy(pextra, pend->extra.ptr, pend->extra.len); 246ccef4ddfSAndrew Thompson pextra += N_ALIGN(pend->extra.len); 247390065b1SAlfred Perlstein } 2488c8fff31SAndrew Thompson } 2498c8fff31SAndrew Thompson } 2508c8fff31SAndrew Thompson } 2518c8fff31SAndrew Thompson 2528c8fff31SAndrew Thompson free(pconf); 253390065b1SAlfred Perlstein 254390065b1SAlfred Perlstein *config = pconfd; 255390065b1SAlfred Perlstein 256390065b1SAlfred Perlstein return (0); /* success */ 2578c8fff31SAndrew Thompson } 2588c8fff31SAndrew Thompson 2598c8fff31SAndrew Thompson int 2608c8fff31SAndrew Thompson libusb_get_config_descriptor_by_value(libusb_device *dev, 2618c8fff31SAndrew Thompson uint8_t bConfigurationValue, struct libusb_config_descriptor **config) 2628c8fff31SAndrew Thompson { 2638c8fff31SAndrew Thompson struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 2648c8fff31SAndrew Thompson struct libusb20_device *pdev; 2658c8fff31SAndrew Thompson int i; 266390065b1SAlfred Perlstein int err; 2678c8fff31SAndrew Thompson 2688c8fff31SAndrew Thompson if (dev == NULL || config == NULL) 2698c8fff31SAndrew Thompson return (LIBUSB_ERROR_INVALID_PARAM); 2708c8fff31SAndrew Thompson 2718c8fff31SAndrew Thompson pdev = dev->os_priv; 2728c8fff31SAndrew Thompson pdesc = libusb20_dev_get_device_desc(pdev); 2738c8fff31SAndrew Thompson 2748c8fff31SAndrew Thompson for (i = 0; i < pdesc->bNumConfigurations; i++) { 275390065b1SAlfred Perlstein err = libusb_get_config_descriptor(dev, i, config); 276390065b1SAlfred Perlstein if (err) 277390065b1SAlfred Perlstein return (err); 2788c8fff31SAndrew Thompson 279390065b1SAlfred Perlstein if ((*config)->bConfigurationValue == bConfigurationValue) 280390065b1SAlfred Perlstein return (0); /* success */ 281390065b1SAlfred Perlstein 282390065b1SAlfred Perlstein libusb_free_config_descriptor(*config); 2838c8fff31SAndrew Thompson } 2848c8fff31SAndrew Thompson 285390065b1SAlfred Perlstein *config = NULL; 286390065b1SAlfred Perlstein 2878c8fff31SAndrew Thompson return (LIBUSB_ERROR_NOT_FOUND); 2888c8fff31SAndrew Thompson } 2898c8fff31SAndrew Thompson 2908c8fff31SAndrew Thompson void 2918c8fff31SAndrew Thompson libusb_free_config_descriptor(struct libusb_config_descriptor *config) 2928c8fff31SAndrew Thompson { 2938c8fff31SAndrew Thompson free(config); 2948c8fff31SAndrew Thompson } 2958c8fff31SAndrew Thompson 2968c8fff31SAndrew Thompson int 297390065b1SAlfred Perlstein libusb_get_string_descriptor_ascii(libusb_device_handle *pdev, 2988c8fff31SAndrew Thompson uint8_t desc_index, unsigned char *data, int length) 2998c8fff31SAndrew Thompson { 300390065b1SAlfred Perlstein if (pdev == NULL || data == NULL || length < 1) 3018c8fff31SAndrew Thompson return (LIBUSB20_ERROR_INVALID_PARAM); 3028c8fff31SAndrew Thompson 303390065b1SAlfred Perlstein /* put some default data into the destination buffer */ 304390065b1SAlfred Perlstein data[0] = 0; 305390065b1SAlfred Perlstein 3068c8fff31SAndrew Thompson if (libusb20_dev_req_string_simple_sync(pdev, desc_index, 3078c8fff31SAndrew Thompson data, length) == 0) 3088c8fff31SAndrew Thompson return (strlen(data)); 3098c8fff31SAndrew Thompson 3108c8fff31SAndrew Thompson return (LIBUSB_ERROR_OTHER); 3118c8fff31SAndrew Thompson } 312ccef4ddfSAndrew Thompson 313ccef4ddfSAndrew Thompson int 314ccef4ddfSAndrew Thompson libusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, 315ccef4ddfSAndrew Thompson uint8_t desc_index, uint8_t *data, int length) 316ccef4ddfSAndrew Thompson { 317ccef4ddfSAndrew Thompson return (libusb_control_transfer(devh, LIBUSB_ENDPOINT_IN, 318ccef4ddfSAndrew Thompson LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, 319ccef4ddfSAndrew Thompson length, 1000)); 320ccef4ddfSAndrew Thompson } 321