1 /* $FreeBSD$ */ 2 /*- 3 * Copyright (c) 2009 Sylvestre Gallon. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/queue.h> 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 32 #define libusb_device_handle libusb20_device 33 34 #include "libusb20.h" 35 #include "libusb20_desc.h" 36 #include "libusb20_int.h" 37 #include "libusb.h" 38 #include "libusb10.h" 39 40 #define N_ALIGN(n) (-((-(n)) & (-8UL))) 41 42 /* USB descriptors */ 43 44 int 45 libusb_get_device_descriptor(libusb_device *dev, 46 struct libusb_device_descriptor *desc) 47 { 48 struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 49 struct libusb20_device *pdev; 50 51 if ((dev == NULL) || (desc == NULL)) 52 return (LIBUSB_ERROR_INVALID_PARAM); 53 54 pdev = dev->os_priv; 55 pdesc = libusb20_dev_get_device_desc(pdev); 56 57 desc->bLength = pdesc->bLength; 58 desc->bDescriptorType = pdesc->bDescriptorType; 59 desc->bcdUSB = pdesc->bcdUSB; 60 desc->bDeviceClass = pdesc->bDeviceClass; 61 desc->bDeviceSubClass = pdesc->bDeviceSubClass; 62 desc->bDeviceProtocol = pdesc->bDeviceProtocol; 63 desc->bMaxPacketSize0 = pdesc->bMaxPacketSize0; 64 desc->idVendor = pdesc->idVendor; 65 desc->idProduct = pdesc->idProduct; 66 desc->bcdDevice = pdesc->bcdDevice; 67 desc->iManufacturer = pdesc->iManufacturer; 68 desc->iProduct = pdesc->iProduct; 69 desc->iSerialNumber = pdesc->iSerialNumber; 70 desc->bNumConfigurations = pdesc->bNumConfigurations; 71 72 return (0); 73 } 74 75 int 76 libusb_get_active_config_descriptor(libusb_device *dev, 77 struct libusb_config_descriptor **config) 78 { 79 struct libusb20_device *pdev; 80 uint8_t config_index; 81 82 pdev = dev->os_priv; 83 config_index = libusb20_dev_get_config_index(pdev); 84 85 return (libusb_get_config_descriptor(dev, config_index, config)); 86 } 87 88 int 89 libusb_get_config_descriptor(libusb_device *dev, uint8_t config_index, 90 struct libusb_config_descriptor **config) 91 { 92 struct libusb20_device *pdev; 93 struct libusb20_config *pconf; 94 struct libusb20_interface *pinf; 95 struct libusb20_endpoint *pend; 96 struct libusb_config_descriptor *pconfd; 97 struct libusb_interface_descriptor *ifd; 98 struct libusb_endpoint_descriptor *endd; 99 uint8_t *pextra; 100 uint16_t nextra; 101 uint8_t nif; 102 uint8_t nep; 103 uint8_t nalt; 104 uint8_t i; 105 uint8_t j; 106 uint8_t k; 107 108 if (dev == NULL || config == NULL) 109 return (LIBUSB_ERROR_INVALID_PARAM); 110 111 *config = NULL; 112 113 pdev = dev->os_priv; 114 pconf = libusb20_dev_alloc_config(pdev, config_index); 115 116 if (pconf == NULL) 117 return (LIBUSB_ERROR_NOT_FOUND); 118 119 nalt = nif = pconf->num_interface; 120 nep = 0; 121 nextra = N_ALIGN(pconf->extra.len); 122 123 for (i = 0; i < nif; i++) { 124 125 pinf = pconf->interface + i; 126 nextra += N_ALIGN(pinf->extra.len); 127 nep += pinf->num_endpoints; 128 k = pinf->num_endpoints; 129 pend = pinf->endpoints; 130 while (k--) { 131 nextra += N_ALIGN(pend->extra.len); 132 pend++; 133 } 134 135 j = pinf->num_altsetting; 136 nalt += pinf->num_altsetting; 137 pinf = pinf->altsetting; 138 while (j--) { 139 nextra += N_ALIGN(pinf->extra.len); 140 nep += pinf->num_endpoints; 141 k = pinf->num_endpoints; 142 pend = pinf->endpoints; 143 while (k--) { 144 nextra += N_ALIGN(pend->extra.len); 145 pend++; 146 } 147 pinf++; 148 } 149 } 150 151 nextra = nextra + 152 (1 * sizeof(libusb_config_descriptor)) + 153 (nif * sizeof(libusb_interface)) + 154 (nalt * sizeof(libusb_interface_descriptor)) + 155 (nep * sizeof(libusb_endpoint_descriptor)); 156 157 nextra = N_ALIGN(nextra); 158 159 pconfd = malloc(nextra); 160 161 if (pconfd == NULL) { 162 free(pconf); 163 return (LIBUSB_ERROR_NO_MEM); 164 } 165 /* make sure memory is initialised */ 166 memset(pconfd, 0, nextra); 167 168 pconfd->interface = (libusb_interface *) (pconfd + 1); 169 170 ifd = (libusb_interface_descriptor *) (pconfd->interface + nif); 171 endd = (libusb_endpoint_descriptor *) (ifd + nalt); 172 pextra = (uint8_t *)(endd + nep); 173 174 /* fill in config descriptor */ 175 176 pconfd->bLength = pconf->desc.bLength; 177 pconfd->bDescriptorType = pconf->desc.bDescriptorType; 178 pconfd->wTotalLength = pconf->desc.wTotalLength; 179 pconfd->bNumInterfaces = pconf->desc.bNumInterfaces; 180 pconfd->bConfigurationValue = pconf->desc.bConfigurationValue; 181 pconfd->iConfiguration = pconf->desc.iConfiguration; 182 pconfd->bmAttributes = pconf->desc.bmAttributes; 183 pconfd->MaxPower = pconf->desc.bMaxPower; 184 185 if (pconf->extra.len != 0) { 186 pconfd->extra_length = pconf->extra.len; 187 pconfd->extra = pextra; 188 memcpy(pextra, pconf->extra.ptr, pconfd->extra_length); 189 pextra += N_ALIGN(pconfd->extra_length); 190 } 191 /* setup all interface and endpoint pointers */ 192 193 for (i = 0; i < nif; i++) { 194 195 pconfd->interface[i].altsetting = ifd; 196 ifd->endpoint = endd; 197 endd += pconf->interface[i].num_endpoints; 198 ifd++; 199 200 for (j = 0; j < pconf->interface[i].num_altsetting; j++) { 201 ifd->endpoint = endd; 202 endd += pconf->interface[i].altsetting[j].num_endpoints; 203 ifd++; 204 } 205 } 206 207 /* fill in all interface and endpoint data */ 208 209 for (i = 0; i < nif; i++) { 210 pinf = &pconf->interface[i]; 211 pconfd->interface[i].num_altsetting = pinf->num_altsetting + 1; 212 for (j = 0; j < pconfd->interface[i].num_altsetting; j++) { 213 if (j != 0) 214 pinf = &pconf->interface[i].altsetting[j - 1]; 215 ifd = &pconfd->interface[i].altsetting[j]; 216 ifd->bLength = pinf->desc.bLength; 217 ifd->bDescriptorType = pinf->desc.bDescriptorType; 218 ifd->bInterfaceNumber = pinf->desc.bInterfaceNumber; 219 ifd->bAlternateSetting = pinf->desc.bAlternateSetting; 220 ifd->bNumEndpoints = pinf->desc.bNumEndpoints; 221 ifd->bInterfaceClass = pinf->desc.bInterfaceClass; 222 ifd->bInterfaceSubClass = pinf->desc.bInterfaceSubClass; 223 ifd->bInterfaceProtocol = pinf->desc.bInterfaceProtocol; 224 ifd->iInterface = pinf->desc.iInterface; 225 if (pinf->extra.len != 0) { 226 ifd->extra_length = pinf->extra.len; 227 ifd->extra = pextra; 228 memcpy(pextra, pinf->extra.ptr, pinf->extra.len); 229 pextra += N_ALIGN(pinf->extra.len); 230 } 231 for (k = 0; k < pinf->num_endpoints; k++) { 232 pend = &pinf->endpoints[k]; 233 endd = &ifd->endpoint[k]; 234 endd->bLength = pend->desc.bLength; 235 endd->bDescriptorType = pend->desc.bDescriptorType; 236 endd->bEndpointAddress = pend->desc.bEndpointAddress; 237 endd->bmAttributes = pend->desc.bmAttributes; 238 endd->wMaxPacketSize = pend->desc.wMaxPacketSize; 239 endd->bInterval = pend->desc.bInterval; 240 endd->bRefresh = pend->desc.bRefresh; 241 endd->bSynchAddress = pend->desc.bSynchAddress; 242 if (pend->extra.len != 0) { 243 endd->extra_length = pend->extra.len; 244 endd->extra = pextra; 245 memcpy(pextra, pend->extra.ptr, pend->extra.len); 246 pextra += N_ALIGN(pend->extra.len); 247 } 248 } 249 } 250 } 251 252 free(pconf); 253 254 *config = pconfd; 255 256 return (0); /* success */ 257 } 258 259 int 260 libusb_get_config_descriptor_by_value(libusb_device *dev, 261 uint8_t bConfigurationValue, struct libusb_config_descriptor **config) 262 { 263 struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 264 struct libusb20_device *pdev; 265 int i; 266 int err; 267 268 if (dev == NULL || config == NULL) 269 return (LIBUSB_ERROR_INVALID_PARAM); 270 271 pdev = dev->os_priv; 272 pdesc = libusb20_dev_get_device_desc(pdev); 273 274 for (i = 0; i < pdesc->bNumConfigurations; i++) { 275 err = libusb_get_config_descriptor(dev, i, config); 276 if (err) 277 return (err); 278 279 if ((*config)->bConfigurationValue == bConfigurationValue) 280 return (0); /* success */ 281 282 libusb_free_config_descriptor(*config); 283 } 284 285 *config = NULL; 286 287 return (LIBUSB_ERROR_NOT_FOUND); 288 } 289 290 void 291 libusb_free_config_descriptor(struct libusb_config_descriptor *config) 292 { 293 free(config); 294 } 295 296 int 297 libusb_get_string_descriptor_ascii(libusb_device_handle *pdev, 298 uint8_t desc_index, unsigned char *data, int length) 299 { 300 if (pdev == NULL || data == NULL || length < 1) 301 return (LIBUSB20_ERROR_INVALID_PARAM); 302 303 /* put some default data into the destination buffer */ 304 data[0] = 0; 305 306 if (libusb20_dev_req_string_simple_sync(pdev, desc_index, 307 data, length) == 0) 308 return (strlen(data)); 309 310 return (LIBUSB_ERROR_OTHER); 311 } 312 313 int 314 libusb_get_descriptor(libusb_device_handle * devh, uint8_t desc_type, 315 uint8_t desc_index, uint8_t *data, int length) 316 { 317 return (libusb_control_transfer(devh, LIBUSB_ENDPOINT_IN, 318 LIBUSB_REQUEST_GET_DESCRIPTOR, (desc_type << 8) | desc_index, 0, data, 319 length, 1000)); 320 } 321