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 #include <stdlib.h> 29 #include <stdio.h> 30 #include <pthread.h> 31 32 #include "libusb20.h" 33 #include "libusb20_desc.h" 34 #include "libusb20_int.h" 35 #include "libusb.h" 36 #include "libusb10.h" 37 38 /* USB descriptors */ 39 40 int 41 libusb_get_device_descriptor(libusb_device * dev, 42 struct libusb_device_descriptor *desc) 43 { 44 struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 45 struct libusb20_device *pdev; 46 libusb_context *ctx; 47 48 ctx = NULL; 49 GET_CONTEXT(ctx); 50 dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_descriptor enter"); 51 52 if ((dev == NULL) || (desc == NULL)) 53 return (LIBUSB_ERROR_INVALID_PARAM); 54 55 pdev = dev->os_priv; 56 pdesc = libusb20_dev_get_device_desc(pdev); 57 58 desc->bLength = pdesc->bLength; 59 desc->bDescriptorType = pdesc->bDescriptorType; 60 desc->bcdUSB = pdesc->bcdUSB; 61 desc->bDeviceClass = pdesc->bDeviceClass; 62 desc->bDeviceSubClass = pdesc->bDeviceSubClass; 63 desc->bDeviceProtocol = pdesc->bDeviceProtocol; 64 desc->bMaxPacketSize0 = pdesc->bMaxPacketSize0; 65 desc->idVendor = pdesc->idVendor; 66 desc->idProduct = pdesc->idProduct; 67 desc->bcdDevice = pdesc->bcdDevice; 68 desc->iManufacturer = pdesc->iManufacturer; 69 desc->iProduct = pdesc->iProduct; 70 desc->iSerialNumber = pdesc->iSerialNumber; 71 desc->bNumConfigurations = pdesc->bNumConfigurations; 72 73 dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_device_descriptor leave"); 74 return (0); 75 } 76 77 int 78 libusb_get_active_config_descriptor(libusb_device * dev, 79 struct libusb_config_descriptor **config) 80 { 81 struct libusb20_device *pdev; 82 libusb_context *ctx; 83 uint8_t idx; 84 85 ctx = NULL; 86 GET_CONTEXT(ctx); 87 dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_active_config_descriptor enter"); 88 89 pdev = dev->os_priv; 90 idx = libusb20_dev_get_config_index(pdev); 91 92 dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_active_config_descriptor leave"); 93 return (libusb_get_config_descriptor(dev, idx, config)); 94 } 95 96 /* 97 * XXX Need to check if extra need a dup because 98 * XXX free pconf could free this char * 99 */ 100 int 101 libusb_get_config_descriptor(libusb_device * dev, uint8_t config_index, 102 struct libusb_config_descriptor **config) 103 { 104 struct libusb20_device *pdev; 105 struct libusb20_config *pconf; 106 struct libusb20_interface *pinf; 107 struct libusb20_endpoint *pend; 108 libusb_interface_descriptor *ifd; 109 libusb_endpoint_descriptor *endd; 110 libusb_context *ctx; 111 uint8_t nif, nend, nalt, i, j, k; 112 uint32_t if_idx, endp_idx; 113 114 ctx = NULL; 115 GET_CONTEXT(ctx); 116 dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_config_descriptor enter"); 117 118 if (dev == NULL || config == NULL) 119 return (LIBUSB_ERROR_INVALID_PARAM); 120 121 pdev = dev->os_priv; 122 pconf = libusb20_dev_alloc_config(pdev, config_index); 123 124 if (pconf == NULL) 125 return (LIBUSB_ERROR_NOT_FOUND); 126 127 nalt = nif = pconf->num_interface; 128 nend = 0; 129 for (i = 0 ; i < nif ; i++) { 130 if (pconf->interface[i].num_altsetting > 0) 131 { 132 nalt += pconf->interface[i].num_altsetting; 133 for (j = 0 ; j < nalt ; j++) { 134 nend += pconf->interface[i].altsetting[j].num_endpoints; 135 } 136 } 137 nend += pconf->interface[i].num_endpoints; 138 } 139 140 *config = malloc(sizeof(libusb_config_descriptor) + 141 (nif * sizeof(libusb_interface)) + 142 (nalt * sizeof(libusb_interface_descriptor)) + 143 (nend * sizeof(libusb_endpoint_descriptor))); 144 if (*config == NULL) { 145 free(pconf); 146 return (LIBUSB_ERROR_NO_MEM); 147 } 148 149 (*config)->interface = (libusb_interface *)(*config + 150 sizeof(libusb_config_descriptor)); 151 for (i = if_idx = endp_idx = 0 ; i < nif ; if_idx, i++) { 152 (*config)->interface[i].altsetting = (libusb_interface_descriptor *) 153 (*config + sizeof(libusb_config_descriptor) + 154 (nif * sizeof(libusb_interface)) + 155 (if_idx * sizeof(libusb_interface_descriptor))); 156 (*config)->interface[i].altsetting[0].endpoint = 157 (libusb_endpoint_descriptor *) (*config + 158 sizeof(libusb_config_descriptor) + 159 (nif * sizeof(libusb_interface)) + 160 (nalt * sizeof(libusb_interface_descriptor)) + 161 (endp_idx * sizeof(libusb_endpoint_descriptor))); 162 endp_idx += pconf->interface[i].num_endpoints; 163 164 if (pconf->interface[i].num_altsetting > 0) 165 { 166 for (j = 0 ; j < pconf->interface[i].num_altsetting ; j++, if_idx++) { 167 (*config)->interface[i].altsetting[j + 1].endpoint = 168 (libusb_endpoint_descriptor *) (*config + 169 sizeof(libusb_config_descriptor) + 170 (nif * sizeof(libusb_interface)) + 171 (nalt * sizeof(libusb_interface_descriptor)) + 172 (endp_idx * sizeof(libusb_endpoint_descriptor))); 173 endp_idx += pconf->interface[i].altsetting[j].num_endpoints; 174 } 175 } 176 } 177 178 (*config)->bLength = pconf->desc.bLength; 179 (*config)->bDescriptorType = pconf->desc.bDescriptorType; 180 (*config)->wTotalLength = pconf->desc.wTotalLength; 181 (*config)->bNumInterfaces = pconf->desc.bNumInterfaces; 182 (*config)->bConfigurationValue = pconf->desc.bConfigurationValue; 183 (*config)->iConfiguration = pconf->desc.iConfiguration; 184 (*config)->bmAttributes = pconf->desc.bmAttributes; 185 (*config)->MaxPower = pconf->desc.bMaxPower; 186 (*config)->extra_length = pconf->extra.len; 187 if ((*config)->extra_length != 0) 188 (*config)->extra = pconf->extra.ptr; 189 190 for (i = 0 ; i < nif ; i++) { 191 pinf = &pconf->interface[i]; 192 (*config)->interface[i].num_altsetting = pinf->num_altsetting + 1; 193 for (j = 0 ; j < (*config)->interface[i].num_altsetting ; j++) { 194 if (j != 0) 195 pinf = &pconf->interface[i].altsetting[j - 1]; 196 ifd = &(*config)->interface[i].altsetting[j]; 197 ifd->bLength = pinf->desc.bLength; 198 ifd->bDescriptorType = pinf->desc.bDescriptorType; 199 ifd->bInterfaceNumber = pinf->desc.bInterfaceNumber; 200 ifd->bAlternateSetting = pinf->desc.bAlternateSetting; 201 ifd->bNumEndpoints = pinf->desc.bNumEndpoints; 202 ifd->bInterfaceClass = pinf->desc.bInterfaceClass; 203 ifd->bInterfaceSubClass = pinf->desc.bInterfaceSubClass; 204 ifd->bInterfaceProtocol = pinf->desc.bInterfaceProtocol; 205 ifd->iInterface = pinf->desc.iInterface; 206 ifd->extra_length = pinf->extra.len; 207 if (ifd->extra_length != 0) 208 ifd->extra = pinf->extra.ptr; 209 for (k = 0 ; k < pinf->num_endpoints ; k++) { 210 pend = &pinf->endpoints[k]; 211 endd = &ifd->endpoint[k]; 212 endd->bLength = pend->desc.bLength; 213 endd->bDescriptorType = pend->desc.bDescriptorType; 214 endd->bEndpointAddress = pend->desc.bEndpointAddress; 215 endd->bmAttributes = pend->desc.bmAttributes; 216 endd->wMaxPacketSize = pend->desc.wMaxPacketSize; 217 endd->bInterval = pend->desc.bInterval; 218 endd->bRefresh = pend->desc.bRefresh; 219 endd->bSynchAddress = pend->desc.bSynchAddress; 220 endd->extra_length = pend->extra.len; 221 if (endd->extra_length != 0) 222 endd->extra = pend->extra.ptr; 223 } 224 } 225 } 226 227 free(pconf); 228 dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_config_descriptor leave"); 229 return (0); 230 } 231 232 int 233 libusb_get_config_descriptor_by_value(libusb_device * dev, 234 uint8_t bConfigurationValue, struct libusb_config_descriptor **config) 235 { 236 struct LIBUSB20_DEVICE_DESC_DECODED *pdesc; 237 struct libusb20_device *pdev; 238 struct libusb20_config *pconf; 239 libusb_context *ctx; 240 int i; 241 242 ctx = NULL; 243 GET_CONTEXT(ctx); 244 dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_config_descriptor_by_value enter"); 245 246 if (dev == NULL || config == NULL) 247 return (LIBUSB_ERROR_INVALID_PARAM); 248 249 pdev = dev->os_priv; 250 pdesc = libusb20_dev_get_device_desc(pdev); 251 252 for (i = 0 ; i < pdesc->bNumConfigurations ; i++) { 253 pconf = libusb20_dev_alloc_config(pdev, i); 254 if (pconf->desc.bConfigurationValue == bConfigurationValue) { 255 free(pconf); 256 return libusb_get_config_descriptor(dev, i, config); 257 258 } 259 free(pconf); 260 } 261 262 dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_config_descriptor_by_value leave"); 263 return (LIBUSB_ERROR_NOT_FOUND); 264 } 265 266 void 267 libusb_free_config_descriptor(struct libusb_config_descriptor *config) 268 { 269 libusb_context *ctx; 270 271 ctx = NULL; 272 GET_CONTEXT(ctx); 273 dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_config_descriptor enter"); 274 275 free(config); 276 dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_free_config_descriptor leave"); 277 } 278 279 int 280 libusb_get_string_descriptor_ascii(libusb_device_handle * dev, 281 uint8_t desc_index, unsigned char *data, int length) 282 { 283 struct libusb20_device *pdev; 284 libusb_context *ctx; 285 int ret; 286 287 ctx = NULL; 288 GET_CONTEXT(ctx); 289 dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_string_descriptor_ascii enter"); 290 291 if (dev == NULL || data == NULL) 292 return (LIBUSB20_ERROR_INVALID_PARAM); 293 294 pdev = dev->os_priv; 295 dprintf(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_get_string_descriptor_ascii leave"); 296 if (libusb20_dev_req_string_simple_sync(pdev, desc_index, 297 data, length) == 0) 298 return (strlen(data)); 299 300 return (LIBUSB_ERROR_OTHER); 301 } 302