1/* 2 * Parses descriptors 3 * 4 * Copyright (c) 2001 Johannes Erdfelt <johannes@erdfelt.com> 5 * 6 * This library is covered by the LGPL, read LICENSE for details. 7 */ 8 9#include <stdio.h> 10#include <string.h> 11#include <stdint.h> 12#include "usbi.h" 13 14int usb_get_descriptor_by_endpoint(usb_dev_handle *udev, int ep, 15 unsigned char type, unsigned char index, void *buf, int size) 16{ 17 memset(buf, 0, size); 18 19 return usb_control_msg(udev, ep | USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, 20 (type << 8) + index, 0, buf, size, 1000); 21} 22 23int usb_get_descriptor(usb_dev_handle *udev, unsigned char type, 24 unsigned char index, void *buf, int size) 25{ 26 memset(buf, 0, size); 27 28 return usb_control_msg(udev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, 29 (type << 8) + index, 0, buf, size, 1000); 30} 31 32int usb_parse_descriptor(unsigned char *source, char *description, void *dest) 33{ 34 unsigned char *sp = source, *dp = dest; 35 uint16_t w; 36 uint32_t d; 37 char *cp; 38 39 for (cp = description; *cp; cp++) { 40 switch (*cp) { 41 case 'b': /* 8-bit byte */ 42 *dp++ = *sp++; 43 break; 44 case 'w': /* 16-bit word, convert from little endian to CPU */ 45 w = (sp[1] << 8) | sp[0]; sp += 2; 46 dp += ((unsigned long)dp & 1); /* Align to word boundary */ 47 *((uint16_t *)dp) = w; dp += 2; 48 break; 49 case 'd': /* 32-bit dword, convert from little endian to CPU */ 50 d = (sp[3] << 24) | (sp[2] << 16) | (sp[1] << 8) | sp[0]; sp += 4; 51 dp += ((unsigned long)dp & 2); /* Align to dword boundary */ 52 *((uint32_t *)dp) = d; dp += 4; 53 break; 54 /* These two characters are undocumented and just a hack for Linux */ 55 case 'W': /* 16-bit word, keep CPU endianess */ 56 dp += ((unsigned long)dp & 1); /* Align to word boundary */ 57 memcpy(dp, sp, 2); sp += 2; dp += 2; 58 break; 59 case 'D': /* 32-bit dword, keep CPU endianess */ 60 dp += ((unsigned long)dp & 2); /* Align to dword boundary */ 61 memcpy(dp, sp, 4); sp += 4; dp += 4; 62 break; 63 } 64 } 65 66 return sp - source; 67} 68 69/* 70 * This code looks surprisingly similar to the code I wrote for the Linux 71 * kernel. It's not a coincidence :) 72 */ 73 74static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *buffer, int size) 75{ 76 struct usb_descriptor_header header; 77 unsigned char *begin; 78 int parsed = 0, len, numskipped; 79 80 usb_parse_descriptor(buffer, "bb", &header); 81 82 /* Everything should be fine being passed into here, but we sanity */ 83 /* check JIC */ 84 if (header.bLength > size) { 85 if (usb_debug >= 1) 86 fprintf(stderr, "ran out of descriptors parsing\n"); 87 return -1; 88 } 89 90 if (header.bDescriptorType != USB_DT_ENDPOINT) { 91 if (usb_debug >= 2) 92 fprintf(stderr, "unexpected descriptor 0x%X, expecting endpoint descriptor, type 0x%X\n", 93 header.bDescriptorType, USB_DT_ENDPOINT); 94 return parsed; 95 } 96 97 if (header.bLength >= ENDPOINT_AUDIO_DESC_LENGTH) 98 usb_parse_descriptor(buffer, "bbbbwbbb", endpoint); 99 else if (header.bLength >= ENDPOINT_DESC_LENGTH) 100 usb_parse_descriptor(buffer, "bbbbwb", endpoint); 101 102 buffer += header.bLength; 103 size -= header.bLength; 104 parsed += header.bLength; 105 106 /* Skip over the rest of the Class Specific or Vendor Specific */ 107 /* descriptors */ 108 begin = buffer; 109 numskipped = 0; 110 while (size >= DESC_HEADER_LENGTH) { 111 usb_parse_descriptor(buffer, "bb", &header); 112 113 if (header.bLength < 2) { 114 if (usb_debug >= 1) 115 fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); 116 return -1; 117 } 118 119 /* If we find another "proper" descriptor then we're done */ 120 if ((header.bDescriptorType == USB_DT_ENDPOINT) || 121 (header.bDescriptorType == USB_DT_INTERFACE) || 122 (header.bDescriptorType == USB_DT_CONFIG) || 123 (header.bDescriptorType == USB_DT_DEVICE)) 124 break; 125 126 if (usb_debug >= 1) 127 fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType); 128 numskipped++; 129 130 buffer += header.bLength; 131 size -= header.bLength; 132 parsed += header.bLength; 133 } 134 135 if (numskipped && usb_debug >= 2) 136 fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped); 137 138 /* Copy any unknown descriptors into a storage area for drivers */ 139 /* to later parse */ 140 len = (int)(buffer - begin); 141 if (!len) { 142 endpoint->extra = NULL; 143 endpoint->extralen = 0; 144 return parsed; 145 } 146 147 endpoint->extra = malloc(len); 148 if (!endpoint->extra) { 149 if (usb_debug >= 1) 150 fprintf(stderr, "couldn't allocate memory for endpoint extra descriptors\n"); 151 endpoint->extralen = 0; 152 return parsed; 153 } 154 155 memcpy(endpoint->extra, begin, len); 156 endpoint->extralen = len; 157 158 return parsed; 159} 160 161static int usb_parse_interface(struct usb_interface *interface, 162 unsigned char *buffer, int size) 163{ 164 int i, len, numskipped, retval, parsed = 0; 165 struct usb_descriptor_header header; 166 struct usb_interface_descriptor *ifp; 167 unsigned char *begin; 168 169 interface->num_altsetting = 0; 170 171 while (size >= INTERFACE_DESC_LENGTH) { 172 interface->altsetting = realloc(interface->altsetting, sizeof(struct usb_interface_descriptor) * (interface->num_altsetting + 1)); 173 if (!interface->altsetting) { 174 if (usb_debug >= 1) 175 fprintf(stderr, "couldn't malloc interface->altsetting\n"); 176 return -1; 177 } 178 179 ifp = interface->altsetting + interface->num_altsetting; 180 interface->num_altsetting++; 181 182 usb_parse_descriptor(buffer, "bbbbbbbbb", ifp); 183 184 /* Skip over the interface */ 185 buffer += ifp->bLength; 186 parsed += ifp->bLength; 187 size -= ifp->bLength; 188 189 begin = buffer; 190 numskipped = 0; 191 192 /* Skip over any interface, class or vendor descriptors */ 193 while (size >= DESC_HEADER_LENGTH) { 194 usb_parse_descriptor(buffer, "bb", &header); 195 196 if (header.bLength < 2) { 197 if (usb_debug >= 1) 198 fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); 199 return -1; 200 } 201 202 /* If we find another "proper" descriptor then we're done */ 203 if ((header.bDescriptorType == USB_DT_INTERFACE) || 204 (header.bDescriptorType == USB_DT_ENDPOINT) || 205 (header.bDescriptorType == USB_DT_CONFIG) || 206 (header.bDescriptorType == USB_DT_DEVICE)) 207 break; 208 209 numskipped++; 210 211 buffer += header.bLength; 212 parsed += header.bLength; 213 size -= header.bLength; 214 } 215 216 if (numskipped && usb_debug >= 2) 217 fprintf(stderr, "skipped %d class/vendor specific interface descriptors\n", numskipped); 218 219 /* Copy any unknown descriptors into a storage area for */ 220 /* drivers to later parse */ 221 len = (int)(buffer - begin); 222 if (!len) { 223 ifp->extra = NULL; 224 ifp->extralen = 0; 225 } else { 226 ifp->extra = malloc(len); 227 if (!ifp->extra) { 228 if (usb_debug >= 1) 229 fprintf(stderr, "couldn't allocate memory for interface extra descriptors\n"); 230 ifp->extralen = 0; 231 return -1; 232 } 233 memcpy(ifp->extra, begin, len); 234 ifp->extralen = len; 235 } 236 237 /* Did we hit an unexpected descriptor? */ 238 usb_parse_descriptor(buffer, "bb", &header); 239 if ((size >= DESC_HEADER_LENGTH) && 240 ((header.bDescriptorType == USB_DT_CONFIG) || 241 (header.bDescriptorType == USB_DT_DEVICE))) 242 return parsed; 243 244 if (ifp->bNumEndpoints > USB_MAXENDPOINTS) { 245 if (usb_debug >= 1) 246 fprintf(stderr, "too many endpoints\n"); 247 return -1; 248 } 249 250 if (ifp->bNumEndpoints > 0) { 251 ifp->endpoint = (struct usb_endpoint_descriptor *) 252 malloc(ifp->bNumEndpoints * 253 sizeof(struct usb_endpoint_descriptor)); 254 if (!ifp->endpoint) { 255 if (usb_debug >= 1) 256 fprintf(stderr, "couldn't allocate memory for ifp->endpoint\n"); 257 return -1; 258 } 259 260 memset(ifp->endpoint, 0, ifp->bNumEndpoints * 261 sizeof(struct usb_endpoint_descriptor)); 262 263 for (i = 0; i < ifp->bNumEndpoints; i++) { 264 usb_parse_descriptor(buffer, "bb", &header); 265 266 if (header.bLength > size) { 267 if (usb_debug >= 1) 268 fprintf(stderr, "ran out of descriptors parsing\n"); 269 return -1; 270 } 271 272 retval = usb_parse_endpoint(ifp->endpoint + i, buffer, size); 273 if (retval < 0) 274 return retval; 275 276 buffer += retval; 277 parsed += retval; 278 size -= retval; 279 } 280 } else 281 ifp->endpoint = NULL; 282 283 /* We check to see if it's an alternate to this one */ 284 ifp = (struct usb_interface_descriptor *)buffer; 285 if (size < USB_DT_INTERFACE_SIZE || 286 ifp->bDescriptorType != USB_DT_INTERFACE || 287 !ifp->bAlternateSetting) 288 return parsed; 289 } 290 291 return parsed; 292} 293 294int usb_parse_configuration(struct usb_config_descriptor *config, 295 unsigned char *buffer) 296{ 297 int i, retval, size; 298 struct usb_descriptor_header header; 299 300 usb_parse_descriptor(buffer, "bbwbbbbb", config); 301 size = config->wTotalLength; 302 303 if (config->bNumInterfaces > USB_MAXINTERFACES) { 304 if (usb_debug >= 1) 305 fprintf(stderr, "too many interfaces\n"); 306 return -1; 307 } 308 309 config->interface = (struct usb_interface *) 310 malloc(config->bNumInterfaces * 311 sizeof(struct usb_interface)); 312 if (!config->interface) { 313 if (usb_debug >= 1) 314 fprintf(stderr, "out of memory\n"); 315 return -1; 316 } 317 318 memset(config->interface, 0, config->bNumInterfaces * sizeof(struct usb_interface)); 319 320 buffer += config->bLength; 321 size -= config->bLength; 322 323 config->extra = NULL; 324 config->extralen = 0; 325 326 for (i = 0; i < config->bNumInterfaces; i++) { 327 int numskipped, len; 328 unsigned char *begin; 329 330 /* Skip over the rest of the Class Specific or Vendor */ 331 /* Specific descriptors */ 332 begin = buffer; 333 numskipped = 0; 334 while (size >= DESC_HEADER_LENGTH) { 335 usb_parse_descriptor(buffer, "bb", &header); 336 337 if ((header.bLength > size) || (header.bLength < DESC_HEADER_LENGTH)) { 338 if (usb_debug >= 1) 339 fprintf(stderr, "invalid descriptor length of %d\n", header.bLength); 340 return -1; 341 } 342 343 /* If we find another "proper" descriptor then we're done */ 344 if ((header.bDescriptorType == USB_DT_ENDPOINT) || 345 (header.bDescriptorType == USB_DT_INTERFACE) || 346 (header.bDescriptorType == USB_DT_CONFIG) || 347 (header.bDescriptorType == USB_DT_DEVICE)) 348 break; 349 350 if (usb_debug >= 2) 351 fprintf(stderr, "skipping descriptor 0x%X\n", header.bDescriptorType); 352 numskipped++; 353 354 buffer += header.bLength; 355 size -= header.bLength; 356 } 357 358 if (numskipped && usb_debug >= 2) 359 fprintf(stderr, "skipped %d class/vendor specific endpoint descriptors\n", numskipped); 360 361 /* Copy any unknown descriptors into a storage area for */ 362 /* drivers to later parse */ 363 len = (int)(buffer - begin); 364 if (len) { 365 /* FIXME: We should realloc and append here */ 366 if (!config->extralen) { 367 config->extra = malloc(len); 368 if (!config->extra) { 369 if (usb_debug >= 1) 370 fprintf(stderr, "couldn't allocate memory for config extra descriptors\n"); 371 config->extralen = 0; 372 return -1; 373 } 374 375 memcpy(config->extra, begin, len); 376 config->extralen = len; 377 } 378 } 379 380 retval = usb_parse_interface(config->interface + i, buffer, size); 381 if (retval < 0) 382 return retval; 383 384 buffer += retval; 385 size -= retval; 386 } 387 388 return size; 389} 390 391void usb_destroy_configuration(struct usb_device *dev) 392{ 393 int c, i, j, k; 394 395 if (!dev->config) 396 return; 397 398 for (c = 0; c < dev->descriptor.bNumConfigurations; c++) { 399 struct usb_config_descriptor *cf = &dev->config[c]; 400 401 if (!cf->interface) 402 continue; 403 404 for (i = 0; i < cf->bNumInterfaces; i++) { 405 struct usb_interface *ifp = &cf->interface[i]; 406 407 if (!ifp->altsetting) 408 continue; 409 410 for (j = 0; j < ifp->num_altsetting; j++) { 411 struct usb_interface_descriptor *as = &ifp->altsetting[j]; 412 413 if (as->extra) 414 free(as->extra); 415 416 if (!as->endpoint) 417 continue; 418 419 for (k = 0; k < as->bNumEndpoints; k++) { 420 if (as->endpoint[k].extra) 421 free(as->endpoint[k].extra); 422 } 423 free(as->endpoint); 424 } 425 426 free(ifp->altsetting); 427 } 428 429 free(cf->interface); 430 } 431 432 free(dev->config); 433} 434 435void usb_fetch_and_parse_descriptors(usb_dev_handle *udev) 436{ 437 struct usb_device *dev = udev->device; 438 int i; 439 440 if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) { 441 if (usb_debug >= 1) 442 fprintf(stderr, "Too many configurations (%d > %d)\n", dev->descriptor.bNumConfigurations, USB_MAXCONFIG); 443 return; 444 } 445 446 if (dev->descriptor.bNumConfigurations < 1) { 447 if (usb_debug >= 1) 448 fprintf(stderr, "Not enough configurations (%d < %d)\n", dev->descriptor.bNumConfigurations, 1); 449 return; 450 } 451 452 dev->config = (struct usb_config_descriptor *)malloc(dev->descriptor.bNumConfigurations * sizeof(struct usb_config_descriptor)); 453 if (!dev->config) { 454 if (usb_debug >= 1) 455 fprintf(stderr, "Unable to allocate memory for config descriptor\n"); 456 return; 457 } 458 459 memset(dev->config, 0, dev->descriptor.bNumConfigurations * 460 sizeof(struct usb_config_descriptor)); 461 462 for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { 463 unsigned char buffer[8], *bigbuffer; 464 struct usb_config_descriptor config; 465 int res; 466 467 /* Get the first 8 bytes so we can figure out what the total length is */ 468 res = usb_get_descriptor(udev, USB_DT_CONFIG, i, buffer, 8); 469 if (res < 8) { 470 if (usb_debug >= 1) { 471 if (res < 0) 472 fprintf(stderr, "Unable to get descriptor (%d)\n", res); 473 else 474 fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", 8, res); 475 } 476 477 goto err; 478 } 479 480 usb_parse_descriptor(buffer, "bbw", &config); 481 482 bigbuffer = malloc(config.wTotalLength); 483 if (!bigbuffer) { 484 if (usb_debug >= 1) 485 fprintf(stderr, "Unable to allocate memory for descriptors\n"); 486 goto err; 487 } 488 489 res = usb_get_descriptor(udev, USB_DT_CONFIG, i, bigbuffer, config.wTotalLength); 490 if (res < config.wTotalLength) { 491 if (usb_debug >= 1) { 492 if (res < 0) 493 fprintf(stderr, "Unable to get descriptor (%d)\n", res); 494 else 495 fprintf(stderr, "Config descriptor too short (expected %d, got %d)\n", config.wTotalLength, res); 496 } 497 498 free(bigbuffer); 499 goto err; 500 } 501 502 res = usb_parse_configuration(&dev->config[i], bigbuffer); 503 if (usb_debug >= 2) { 504 if (res > 0) 505 fprintf(stderr, "Descriptor data still left\n"); 506 else if (res < 0) 507 fprintf(stderr, "Unable to parse descriptors\n"); 508 } 509 510 free(bigbuffer); 511 } 512 513 return; 514 515err: 516 free(dev->config); 517 518 dev->config = NULL; 519} 520 521