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