libusb10_desc.c revision 199055
1194676Sthompsa/* $FreeBSD: head/lib/libusb/libusb10_desc.c 199055 2009-11-08 20:03:52Z thompsa $ */ 2194676Sthompsa/*- 3194676Sthompsa * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 4194676Sthompsa * 5194676Sthompsa * Redistribution and use in source and binary forms, with or without 6194676Sthompsa * modification, are permitted provided that the following conditions 7194676Sthompsa * are met: 8194676Sthompsa * 1. Redistributions of source code must retain the above copyright 9194676Sthompsa * notice, this list of conditions and the following disclaimer. 10194676Sthompsa * 2. Redistributions in binary form must reproduce the above copyright 11194676Sthompsa * notice, this list of conditions and the following disclaimer in the 12194676Sthompsa * documentation and/or other materials provided with the distribution. 13194676Sthompsa * 14194676Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15194676Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16194676Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17194676Sthompsa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18194676Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19194676Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20194676Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21194676Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22194676Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23194676Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24194676Sthompsa * SUCH DAMAGE. 25194676Sthompsa */ 26194676Sthompsa 27194676Sthompsa#include <stdlib.h> 28194676Sthompsa#include <stdio.h> 29194676Sthompsa#include <pthread.h> 30195957Salfred#include <sys/queue.h> 31194676Sthompsa 32194676Sthompsa#include "libusb20.h" 33194676Sthompsa#include "libusb20_desc.h" 34194676Sthompsa#include "libusb20_int.h" 35194676Sthompsa#include "libusb.h" 36194676Sthompsa#include "libusb10.h" 37194676Sthompsa 38199055Sthompsa#define N_ALIGN(n) (-((-(n)) & (-8UL))) 39199055Sthompsa 40194676Sthompsa/* USB descriptors */ 41194676Sthompsa 42194676Sthompsaint 43195957Salfredlibusb_get_device_descriptor(libusb_device *dev, 44194676Sthompsa struct libusb_device_descriptor *desc) 45194676Sthompsa{ 46194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 47194676Sthompsa struct libusb20_device *pdev; 48194676Sthompsa 49194676Sthompsa if ((dev == NULL) || (desc == NULL)) 50194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 51194676Sthompsa 52194676Sthompsa pdev = dev->os_priv; 53194676Sthompsa pdesc = libusb20_dev_get_device_desc(pdev); 54194676Sthompsa 55194676Sthompsa desc->bLength = pdesc->bLength; 56194676Sthompsa desc->bDescriptorType = pdesc->bDescriptorType; 57194676Sthompsa desc->bcdUSB = pdesc->bcdUSB; 58194676Sthompsa desc->bDeviceClass = pdesc->bDeviceClass; 59194676Sthompsa desc->bDeviceSubClass = pdesc->bDeviceSubClass; 60194676Sthompsa desc->bDeviceProtocol = pdesc->bDeviceProtocol; 61194676Sthompsa desc->bMaxPacketSize0 = pdesc->bMaxPacketSize0; 62194676Sthompsa desc->idVendor = pdesc->idVendor; 63194676Sthompsa desc->idProduct = pdesc->idProduct; 64194676Sthompsa desc->bcdDevice = pdesc->bcdDevice; 65194676Sthompsa desc->iManufacturer = pdesc->iManufacturer; 66194676Sthompsa desc->iProduct = pdesc->iProduct; 67194676Sthompsa desc->iSerialNumber = pdesc->iSerialNumber; 68194676Sthompsa desc->bNumConfigurations = pdesc->bNumConfigurations; 69194676Sthompsa 70194676Sthompsa return (0); 71194676Sthompsa} 72194676Sthompsa 73194676Sthompsaint 74195957Salfredlibusb_get_active_config_descriptor(libusb_device *dev, 75194676Sthompsa struct libusb_config_descriptor **config) 76194676Sthompsa{ 77194676Sthompsa struct libusb20_device *pdev; 78195957Salfred uint8_t config_index; 79194676Sthompsa 80194676Sthompsa pdev = dev->os_priv; 81195957Salfred config_index = libusb20_dev_get_config_index(pdev); 82194676Sthompsa 83195957Salfred return (libusb_get_config_descriptor(dev, config_index, config)); 84194676Sthompsa} 85194676Sthompsa 86194676Sthompsaint 87195957Salfredlibusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, 88194676Sthompsa struct libusb_config_descriptor **config) 89194676Sthompsa{ 90194676Sthompsa struct libusb20_device *pdev; 91194676Sthompsa struct libusb20_config *pconf; 92194676Sthompsa struct libusb20_interface *pinf; 93194676Sthompsa struct libusb20_endpoint *pend; 94195957Salfred struct libusb_config_descriptor *pconfd; 95195957Salfred struct libusb_interface_descriptor *ifd; 96195957Salfred struct libusb_endpoint_descriptor *endd; 97195957Salfred uint8_t *pextra; 98195957Salfred uint16_t nextra; 99195957Salfred uint8_t nif; 100195957Salfred uint8_t nep; 101195957Salfred uint8_t nalt; 102195957Salfred uint8_t i; 103195957Salfred uint8_t j; 104195957Salfred uint8_t k; 105194676Sthompsa 106194676Sthompsa if (dev == NULL || config == NULL) 107194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 108194676Sthompsa 109195957Salfred *config = NULL; 110195957Salfred 111194676Sthompsa pdev = dev->os_priv; 112194676Sthompsa pconf = libusb20_dev_alloc_config(pdev, config_index); 113194676Sthompsa 114194676Sthompsa if (pconf == NULL) 115194676Sthompsa return (LIBUSB_ERROR_NOT_FOUND); 116194676Sthompsa 117194676Sthompsa nalt = nif = pconf->num_interface; 118195957Salfred nep = 0; 119199055Sthompsa nextra = N_ALIGN(pconf->extra.len); 120195957Salfred 121195957Salfred for (i = 0; i < nif; i++) { 122195957Salfred 123195957Salfred pinf = pconf->interface + i; 124199055Sthompsa nextra += N_ALIGN(pinf->extra.len); 125195957Salfred nep += pinf->num_endpoints; 126195957Salfred k = pinf->num_endpoints; 127195957Salfred pend = pinf->endpoints; 128195957Salfred while (k--) { 129199055Sthompsa nextra += N_ALIGN(pend->extra.len); 130195957Salfred pend++; 131195957Salfred } 132195957Salfred 133195957Salfred j = pinf->num_altsetting; 134195957Salfred nalt += pinf->num_altsetting; 135195957Salfred pinf = pinf->altsetting; 136195957Salfred while (j--) { 137199055Sthompsa nextra += N_ALIGN(pinf->extra.len); 138195957Salfred nep += pinf->num_endpoints; 139195957Salfred k = pinf->num_endpoints; 140195957Salfred pend = pinf->endpoints; 141195957Salfred while (k--) { 142199055Sthompsa nextra += N_ALIGN(pend->extra.len); 143195957Salfred pend++; 144194676Sthompsa } 145195957Salfred pinf++; 146194676Sthompsa } 147194676Sthompsa } 148194676Sthompsa 149195957Salfred nextra = nextra + 150195957Salfred (1 * sizeof(libusb_config_descriptor)) + 151194676Sthompsa (nif * sizeof(libusb_interface)) + 152194676Sthompsa (nalt * sizeof(libusb_interface_descriptor)) + 153195957Salfred (nep * sizeof(libusb_endpoint_descriptor)); 154195957Salfred 155199055Sthompsa nextra = N_ALIGN(nextra); 156199055Sthompsa 157195957Salfred pconfd = malloc(nextra); 158195957Salfred 159195957Salfred if (pconfd == NULL) { 160194676Sthompsa free(pconf); 161194676Sthompsa return (LIBUSB_ERROR_NO_MEM); 162194676Sthompsa } 163199055Sthompsa /* make sure memory is initialised */ 164195957Salfred memset(pconfd, 0, nextra); 165194676Sthompsa 166199055Sthompsa pconfd->interface = (libusb_interface *) (pconfd + 1); 167194676Sthompsa 168195957Salfred ifd = (libusb_interface_descriptor *) (pconfd->interface + nif); 169195957Salfred endd = (libusb_endpoint_descriptor *) (ifd + nalt); 170195957Salfred pextra = (uint8_t *)(endd + nep); 171195957Salfred 172195957Salfred /* fill in config descriptor */ 173195957Salfred 174195957Salfred pconfd->bLength = pconf->desc.bLength; 175195957Salfred pconfd->bDescriptorType = pconf->desc.bDescriptorType; 176195957Salfred pconfd->wTotalLength = pconf->desc.wTotalLength; 177195957Salfred pconfd->bNumInterfaces = pconf->desc.bNumInterfaces; 178195957Salfred pconfd->bConfigurationValue = pconf->desc.bConfigurationValue; 179195957Salfred pconfd->iConfiguration = pconf->desc.iConfiguration; 180195957Salfred pconfd->bmAttributes = pconf->desc.bmAttributes; 181195957Salfred pconfd->MaxPower = pconf->desc.bMaxPower; 182195957Salfred 183195957Salfred if (pconf->extra.len != 0) { 184195957Salfred pconfd->extra_length = pconf->extra.len; 185195957Salfred pconfd->extra = pextra; 186195957Salfred memcpy(pextra, pconf->extra.ptr, pconfd->extra_length); 187199055Sthompsa pextra += N_ALIGN(pconfd->extra_length); 188195957Salfred } 189195957Salfred /* setup all interface and endpoint pointers */ 190195957Salfred 191195957Salfred for (i = 0; i < nif; i++) { 192195957Salfred 193195957Salfred pconfd->interface[i].altsetting = ifd; 194195957Salfred ifd->endpoint = endd; 195195957Salfred endd += pconf->interface[i].num_endpoints; 196195957Salfred ifd++; 197195957Salfred 198195957Salfred for (j = 0; j < pconf->interface[i].num_altsetting; j++) { 199195957Salfred ifd->endpoint = endd; 200195957Salfred endd += pconf->interface[i].altsetting[j].num_endpoints; 201195957Salfred ifd++; 202194676Sthompsa } 203194676Sthompsa } 204194676Sthompsa 205195957Salfred /* fill in all interface and endpoint data */ 206194676Sthompsa 207195957Salfred for (i = 0; i < nif; i++) { 208194676Sthompsa pinf = &pconf->interface[i]; 209195957Salfred pconfd->interface[i].num_altsetting = pinf->num_altsetting + 1; 210195957Salfred for (j = 0; j < pconfd->interface[i].num_altsetting; j++) { 211194676Sthompsa if (j != 0) 212194676Sthompsa pinf = &pconf->interface[i].altsetting[j - 1]; 213195957Salfred ifd = &pconfd->interface[i].altsetting[j]; 214194676Sthompsa ifd->bLength = pinf->desc.bLength; 215194676Sthompsa ifd->bDescriptorType = pinf->desc.bDescriptorType; 216194676Sthompsa ifd->bInterfaceNumber = pinf->desc.bInterfaceNumber; 217194676Sthompsa ifd->bAlternateSetting = pinf->desc.bAlternateSetting; 218194676Sthompsa ifd->bNumEndpoints = pinf->desc.bNumEndpoints; 219194676Sthompsa ifd->bInterfaceClass = pinf->desc.bInterfaceClass; 220194676Sthompsa ifd->bInterfaceSubClass = pinf->desc.bInterfaceSubClass; 221194676Sthompsa ifd->bInterfaceProtocol = pinf->desc.bInterfaceProtocol; 222194676Sthompsa ifd->iInterface = pinf->desc.iInterface; 223195957Salfred if (pinf->extra.len != 0) { 224195957Salfred ifd->extra_length = pinf->extra.len; 225195957Salfred ifd->extra = pextra; 226195957Salfred memcpy(pextra, pinf->extra.ptr, pinf->extra.len); 227199055Sthompsa pextra += N_ALIGN(pinf->extra.len); 228195957Salfred } 229195957Salfred for (k = 0; k < pinf->num_endpoints; k++) { 230194676Sthompsa pend = &pinf->endpoints[k]; 231194676Sthompsa endd = &ifd->endpoint[k]; 232194676Sthompsa endd->bLength = pend->desc.bLength; 233194676Sthompsa endd->bDescriptorType = pend->desc.bDescriptorType; 234194676Sthompsa endd->bEndpointAddress = pend->desc.bEndpointAddress; 235194676Sthompsa endd->bmAttributes = pend->desc.bmAttributes; 236194676Sthompsa endd->wMaxPacketSize = pend->desc.wMaxPacketSize; 237194676Sthompsa endd->bInterval = pend->desc.bInterval; 238194676Sthompsa endd->bRefresh = pend->desc.bRefresh; 239194676Sthompsa endd->bSynchAddress = pend->desc.bSynchAddress; 240195957Salfred if (pend->extra.len != 0) { 241195957Salfred endd->extra_length = pend->extra.len; 242195957Salfred endd->extra = pextra; 243195957Salfred memcpy(pextra, pend->extra.ptr, pend->extra.len); 244199055Sthompsa pextra += N_ALIGN(pend->extra.len); 245195957Salfred } 246194676Sthompsa } 247195957Salfred } 248194676Sthompsa } 249194676Sthompsa 250194676Sthompsa free(pconf); 251195957Salfred 252195957Salfred *config = pconfd; 253195957Salfred 254195957Salfred return (0); /* success */ 255194676Sthompsa} 256194676Sthompsa 257194676Sthompsaint 258195957Salfredlibusb_get_config_descriptor_by_value(libusb_device *dev, 259194676Sthompsa uint8_t bConfigurationValue, struct libusb_config_descriptor **config) 260194676Sthompsa{ 261194676Sthompsa struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 262194676Sthompsa struct libusb20_device *pdev; 263194676Sthompsa int i; 264195957Salfred int err; 265194676Sthompsa 266194676Sthompsa if (dev == NULL || config == NULL) 267194676Sthompsa return (LIBUSB_ERROR_INVALID_PARAM); 268195957Salfred 269194676Sthompsa pdev = dev->os_priv; 270194676Sthompsa pdesc = libusb20_dev_get_device_desc(pdev); 271194676Sthompsa 272195957Salfred for (i = 0; i < pdesc->bNumConfigurations; i++) { 273195957Salfred err = libusb_get_config_descriptor(dev, i, config); 274195957Salfred if (err) 275195957Salfred return (err); 276194676Sthompsa 277195957Salfred if ((*config)->bConfigurationValue == bConfigurationValue) 278195957Salfred return (0); /* success */ 279195957Salfred 280195957Salfred libusb_free_config_descriptor(*config); 281194676Sthompsa } 282194676Sthompsa 283195957Salfred *config = NULL; 284195957Salfred 285194676Sthompsa return (LIBUSB_ERROR_NOT_FOUND); 286194676Sthompsa} 287194676Sthompsa 288194676Sthompsavoid 289194676Sthompsalibusb_free_config_descriptor(struct libusb_config_descriptor *config) 290194676Sthompsa{ 291194676Sthompsa free(config); 292194676Sthompsa} 293194676Sthompsa 294194676Sthompsaint 295195957Salfredlibusb_get_string_descriptor_ascii(libusb_device_handle *pdev, 296194676Sthompsa uint8_t desc_index, unsigned char *data, int length) 297194676Sthompsa{ 298195957Salfred if (pdev == NULL || data == NULL || length < 1) 299195957Salfred return (LIBUSB20_ERROR_INVALID_PARAM); 300194676Sthompsa 301195957Salfred /* put some default data into the destination buffer */ 302195957Salfred data[0] = 0; 303194676Sthompsa 304195957Salfred if (libusb20_dev_req_string_simple_sync(pdev, desc_index, 305194676Sthompsa data, length) == 0) 306194676Sthompsa return (strlen(data)); 307194676Sthompsa 308194676Sthompsa return (LIBUSB_ERROR_OTHER); 309194676Sthompsa} 310199055Sthompsa 311199055Sthompsaint 312199055Sthompsalibusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, 313199055Sthompsa uint8_t desc_index, uint8_t *data, int length) 314199055Sthompsa{ 315199055Sthompsa return (libusb_control_transfer(devh, LIBUSB_ENDPOINT_IN, 316199055Sthompsa LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, 317199055Sthompsa length, 1000)); 318199055Sthompsa} 319