source: trunk/kitgen/8.x/libusb-win32/descriptors.c

Last change on this file was 175, checked in by demin, 12 years ago

initial commit

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