1 /* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */
3 * USB descriptor handling functions for libusbx
4 * Copyright © 2007 Daniel Drake <dsd@gentoo.org>
5 * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com>
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 #define DESC_HEADER_LENGTH 2
30 #define DEVICE_DESC_LENGTH 18
31 #define CONFIG_DESC_LENGTH 9
32 #define INTERFACE_DESC_LENGTH 9
33 #define ENDPOINT_DESC_LENGTH 7
34 #define ENDPOINT_AUDIO_DESC_LENGTH 9
36 /** @defgroup desc USB descriptors
37 * This page details how to examine the various standard USB descriptors
38 * for detected devices
41 /* set host_endian if the w values are already in host endian format,
42 * as opposed to bus endian. */
43 int usbi_parse_descriptor(unsigned char *source
, const char *descriptor
,
44 void *dest
, int host_endian
)
46 unsigned char *sp
= source
, *dp
= dest
;
50 for (cp
= descriptor
; *cp
; cp
++) {
52 case 'b': /* 8-bit byte */
55 case 'w': /* 16-bit word, convert from little endian to CPU */
56 dp
+= ((uintptr_t)dp
& 1); /* Align to word boundary */
61 w
= (sp
[1] << 8) | sp
[0];
62 *((uint16_t *)dp
) = w
;
70 return (int) (sp
- source
);
73 static void clear_endpoint(struct libusb_endpoint_descriptor
*endpoint
)
76 free((unsigned char *) endpoint
->extra
);
79 static int parse_endpoint(struct libusb_context
*ctx
,
80 struct libusb_endpoint_descriptor
*endpoint
, unsigned char *buffer
,
81 int size
, int host_endian
)
83 struct usb_descriptor_header header
;
89 usbi_parse_descriptor(buffer
, "bb", &header
, 0);
91 /* Everything should be fine being passed into here, but we sanity */
93 if (header
.bLength
> size
) {
94 usbi_err(ctx
, "ran out of descriptors parsing");
98 if (header
.bDescriptorType
!= LIBUSB_DT_ENDPOINT
) {
99 usbi_err(ctx
, "unexpected descriptor %x (expected %x)",
100 header
.bDescriptorType
, LIBUSB_DT_ENDPOINT
);
104 if (header
.bLength
>= ENDPOINT_AUDIO_DESC_LENGTH
)
105 usbi_parse_descriptor(buffer
, "bbbbwbbb", endpoint
, host_endian
);
106 else if (header
.bLength
>= ENDPOINT_DESC_LENGTH
)
107 usbi_parse_descriptor(buffer
, "bbbbwb", endpoint
, host_endian
);
109 buffer
+= header
.bLength
;
110 size
-= header
.bLength
;
111 parsed
+= header
.bLength
;
113 /* Skip over the rest of the Class Specific or Vendor Specific */
116 while (size
>= DESC_HEADER_LENGTH
) {
117 usbi_parse_descriptor(buffer
, "bb", &header
, 0);
119 if (header
.bLength
< 2) {
120 usbi_err(ctx
, "invalid descriptor length %d", header
.bLength
);
124 /* If we find another "proper" descriptor then we're done */
125 if ((header
.bDescriptorType
== LIBUSB_DT_ENDPOINT
) ||
126 (header
.bDescriptorType
== LIBUSB_DT_INTERFACE
) ||
127 (header
.bDescriptorType
== LIBUSB_DT_CONFIG
) ||
128 (header
.bDescriptorType
== LIBUSB_DT_DEVICE
))
131 usbi_dbg("skipping descriptor %x", header
.bDescriptorType
);
132 buffer
+= header
.bLength
;
133 size
-= header
.bLength
;
134 parsed
+= header
.bLength
;
137 /* Copy any unknown descriptors into a storage area for drivers */
139 len
= (int)(buffer
- begin
);
141 endpoint
->extra
= NULL
;
142 endpoint
->extra_length
= 0;
147 endpoint
->extra
= extra
;
149 endpoint
->extra_length
= 0;
150 return LIBUSB_ERROR_NO_MEM
;
153 memcpy(extra
, begin
, len
);
154 endpoint
->extra_length
= len
;
159 static void clear_interface(struct libusb_interface
*usb_interface
)
164 if (usb_interface
->altsetting
) {
165 for (i
= 0; i
< usb_interface
->num_altsetting
; i
++) {
166 struct libusb_interface_descriptor
*ifp
=
167 (struct libusb_interface_descriptor
*)
168 usb_interface
->altsetting
+ i
;
170 free((void *) ifp
->extra
);
172 for (j
= 0; j
< ifp
->bNumEndpoints
; j
++)
173 clear_endpoint((struct libusb_endpoint_descriptor
*)
175 free((void *) ifp
->endpoint
);
178 free((void *) usb_interface
->altsetting
);
179 usb_interface
->altsetting
= NULL
;
184 static int parse_interface(libusb_context
*ctx
,
185 struct libusb_interface
*usb_interface
, unsigned char *buffer
, int size
,
193 struct usb_descriptor_header header
;
194 struct libusb_interface_descriptor
*ifp
;
195 unsigned char *begin
;
197 usb_interface
->num_altsetting
= 0;
199 while (size
>= INTERFACE_DESC_LENGTH
) {
200 struct libusb_interface_descriptor
*altsetting
=
201 (struct libusb_interface_descriptor
*) usb_interface
->altsetting
;
202 altsetting
= usbi_reallocf(altsetting
,
203 sizeof(struct libusb_interface_descriptor
) *
204 (usb_interface
->num_altsetting
+ 1));
206 r
= LIBUSB_ERROR_NO_MEM
;
209 usb_interface
->altsetting
= altsetting
;
211 ifp
= altsetting
+ usb_interface
->num_altsetting
;
212 usb_interface
->num_altsetting
++;
213 usbi_parse_descriptor(buffer
, "bbbbbbbbb", ifp
, 0);
215 ifp
->extra_length
= 0;
216 ifp
->endpoint
= NULL
;
218 /* Skip over the interface */
219 buffer
+= ifp
->bLength
;
220 parsed
+= ifp
->bLength
;
221 size
-= ifp
->bLength
;
225 /* Skip over any interface, class or vendor descriptors */
226 while (size
>= DESC_HEADER_LENGTH
) {
227 usbi_parse_descriptor(buffer
, "bb", &header
, 0);
228 if (header
.bLength
< 2) {
229 usbi_err(ctx
, "invalid descriptor of length %d",
233 } else if (header
.bLength
> size
) {
234 usbi_warn(ctx
, "invalid descriptor of length %d",
236 /* The remaining bytes are bogus, but at least
237 * one interface is OK, so let's continue. */
241 /* If we find another "proper" descriptor then we're done */
242 if ((header
.bDescriptorType
== LIBUSB_DT_INTERFACE
) ||
243 (header
.bDescriptorType
== LIBUSB_DT_ENDPOINT
) ||
244 (header
.bDescriptorType
== LIBUSB_DT_CONFIG
) ||
245 (header
.bDescriptorType
== LIBUSB_DT_DEVICE
))
248 buffer
+= header
.bLength
;
249 parsed
+= header
.bLength
;
250 size
-= header
.bLength
;
253 /* Copy any unknown descriptors into a storage area for */
254 /* drivers to later parse */
255 len
= (int)(buffer
- begin
);
257 ifp
->extra
= malloc(len
);
259 r
= LIBUSB_ERROR_NO_MEM
;
262 memcpy((unsigned char *) ifp
->extra
, begin
, len
);
263 ifp
->extra_length
= len
;
266 /* Did we hit an unexpected descriptor? */
267 if (size
>= DESC_HEADER_LENGTH
) {
268 usbi_parse_descriptor(buffer
, "bb", &header
, 0);
269 if ((header
.bDescriptorType
== LIBUSB_DT_CONFIG
) ||
270 (header
.bDescriptorType
== LIBUSB_DT_DEVICE
)) {
275 if (ifp
->bNumEndpoints
> USB_MAXENDPOINTS
) {
276 usbi_err(ctx
, "too many endpoints (%d)", ifp
->bNumEndpoints
);
281 if (ifp
->bNumEndpoints
> 0) {
282 struct libusb_endpoint_descriptor
*endpoint
;
283 tmp
= ifp
->bNumEndpoints
* sizeof(struct libusb_endpoint_descriptor
);
284 endpoint
= malloc(tmp
);
285 ifp
->endpoint
= endpoint
;
287 r
= LIBUSB_ERROR_NO_MEM
;
291 memset(endpoint
, 0, tmp
);
292 for (i
= 0; i
< ifp
->bNumEndpoints
; i
++) {
293 usbi_parse_descriptor(buffer
, "bb", &header
, 0);
295 if (header
.bLength
> size
) {
296 usbi_err(ctx
, "ran out of descriptors parsing");
301 r
= parse_endpoint(ctx
, endpoint
+ i
, buffer
, size
,
312 /* We check to see if it's an alternate to this one */
313 ifp
= (struct libusb_interface_descriptor
*) buffer
;
314 if (size
< LIBUSB_DT_INTERFACE_SIZE
||
315 ifp
->bDescriptorType
!= LIBUSB_DT_INTERFACE
||
316 !ifp
->bAlternateSetting
)
322 clear_interface(usb_interface
);
326 static void clear_configuration(struct libusb_config_descriptor
*config
)
328 if (config
->interface
) {
330 for (i
= 0; i
< config
->bNumInterfaces
; i
++)
331 clear_interface((struct libusb_interface
*)
332 config
->interface
+ i
);
333 free((void *) config
->interface
);
336 free((void *) config
->extra
);
339 static int parse_configuration(struct libusb_context
*ctx
,
340 struct libusb_config_descriptor
*config
, unsigned char *buffer
,
347 struct usb_descriptor_header header
;
348 struct libusb_interface
*usb_interface
;
350 usbi_parse_descriptor(buffer
, "bbwbbbbb", config
, host_endian
);
351 size
= config
->wTotalLength
;
353 if (config
->bNumInterfaces
> USB_MAXINTERFACES
) {
354 usbi_err(ctx
, "too many interfaces (%d)", config
->bNumInterfaces
);
355 return LIBUSB_ERROR_IO
;
358 tmp
= config
->bNumInterfaces
* sizeof(struct libusb_interface
);
359 usb_interface
= malloc(tmp
);
360 config
->interface
= usb_interface
;
361 if (!config
->interface
)
362 return LIBUSB_ERROR_NO_MEM
;
364 memset(usb_interface
, 0, tmp
);
365 buffer
+= config
->bLength
;
366 size
-= config
->bLength
;
368 config
->extra
= NULL
;
369 config
->extra_length
= 0;
371 for (i
= 0; i
< config
->bNumInterfaces
; i
++) {
373 unsigned char *begin
;
375 /* Skip over the rest of the Class Specific or Vendor */
376 /* Specific descriptors */
378 while (size
>= DESC_HEADER_LENGTH
) {
379 usbi_parse_descriptor(buffer
, "bb", &header
, 0);
381 /* If we've parsed at least one config descriptor then
382 * let's return that. */
383 if (header
.bLength
> size
&& i
) {
384 usbi_warn(ctx
, "invalid descriptor length of %d",
389 if ((header
.bLength
> size
) ||
390 (header
.bLength
< DESC_HEADER_LENGTH
)) {
391 usbi_err(ctx
, "invalid descriptor length of %d",
397 /* If we find another "proper" descriptor then we're done */
398 if ((header
.bDescriptorType
== LIBUSB_DT_ENDPOINT
) ||
399 (header
.bDescriptorType
== LIBUSB_DT_INTERFACE
) ||
400 (header
.bDescriptorType
== LIBUSB_DT_CONFIG
) ||
401 (header
.bDescriptorType
== LIBUSB_DT_DEVICE
))
404 usbi_dbg("skipping descriptor 0x%x\n", header
.bDescriptorType
);
405 buffer
+= header
.bLength
;
406 size
-= header
.bLength
;
409 /* Copy any unknown descriptors into a storage area for */
410 /* drivers to later parse */
411 len
= (int)(buffer
- begin
);
413 /* FIXME: We should realloc and append here */
414 if (!config
->extra_length
) {
415 config
->extra
= malloc(len
);
416 if (!config
->extra
) {
417 r
= LIBUSB_ERROR_NO_MEM
;
421 memcpy((unsigned char *) config
->extra
, begin
, len
);
422 config
->extra_length
= len
;
426 r
= parse_interface(ctx
, usb_interface
+ i
, buffer
, size
, host_endian
);
437 clear_configuration(config
);
441 int usbi_device_cache_descriptor(libusb_device
*dev
)
445 r
= usbi_backend
->get_device_descriptor(dev
, (unsigned char *) &dev
->device_descriptor
,
451 dev
->device_descriptor
.bcdUSB
= libusb_le16_to_cpu(dev
->device_descriptor
.bcdUSB
);
452 dev
->device_descriptor
.idVendor
= libusb_le16_to_cpu(dev
->device_descriptor
.idVendor
);
453 dev
->device_descriptor
.idProduct
= libusb_le16_to_cpu(dev
->device_descriptor
.idProduct
);
454 dev
->device_descriptor
.bcdDevice
= libusb_le16_to_cpu(dev
->device_descriptor
.bcdDevice
);
457 return LIBUSB_SUCCESS
;
461 * Get the USB device descriptor for a given device.
463 * This is a non-blocking function; the device descriptor is cached in memory.
465 * \param dev the device
466 * \param desc output location for the descriptor data
467 * \returns 0 on success or a LIBUSB_ERROR code on failure
469 int API_EXPORTED
libusb_get_device_descriptor(libusb_device
*dev
,
470 struct libusb_device_descriptor
*desc
)
473 memcpy((unsigned char *) desc
, (unsigned char *) &dev
->device_descriptor
,
474 sizeof (dev
->device_descriptor
));
479 * Get the USB configuration descriptor for the currently active configuration.
480 * This is a non-blocking function which does not involve any requests being
481 * sent to the device.
483 * \param dev a device
484 * \param config output location for the USB configuration descriptor. Only
485 * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
487 * \returns 0 on success
488 * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state
489 * \returns another LIBUSB_ERROR code on error
490 * \see libusb_get_config_descriptor
492 int API_EXPORTED
libusb_get_active_config_descriptor(libusb_device
*dev
,
493 struct libusb_config_descriptor
**config
)
495 struct libusb_config_descriptor
*_config
= malloc(sizeof(*_config
));
496 unsigned char tmp
[8];
497 unsigned char *buf
= NULL
;
503 return LIBUSB_ERROR_NO_MEM
;
505 r
= usbi_backend
->get_active_config_descriptor(dev
, tmp
, sizeof(tmp
),
510 _config
->wTotalLength
= 0;
511 usbi_parse_descriptor(tmp
, "bbw", _config
, host_endian
);
512 if (_config
->wTotalLength
!= 0)
513 buf
= malloc(_config
->wTotalLength
);
515 r
= LIBUSB_ERROR_NO_MEM
;
519 r
= usbi_backend
->get_active_config_descriptor(dev
, buf
,
520 _config
->wTotalLength
, &host_endian
);
524 r
= parse_configuration(dev
->ctx
, _config
, buf
, host_endian
);
526 usbi_err(dev
->ctx
, "parse_configuration failed with error %d", r
);
529 usbi_warn(dev
->ctx
, "descriptor data still left");
544 * Get a USB configuration descriptor based on its index.
545 * This is a non-blocking function which does not involve any requests being
546 * sent to the device.
548 * \param dev a device
549 * \param config_index the index of the configuration you wish to retrieve
550 * \param config output location for the USB configuration descriptor. Only
551 * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
553 * \returns 0 on success
554 * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
555 * \returns another LIBUSB_ERROR code on error
556 * \see libusb_get_active_config_descriptor()
557 * \see libusb_get_config_descriptor_by_value()
559 int API_EXPORTED
libusb_get_config_descriptor(libusb_device
*dev
,
560 uint8_t config_index
, struct libusb_config_descriptor
**config
)
562 struct libusb_config_descriptor
*_config
;
563 unsigned char tmp
[8];
564 unsigned char *buf
= NULL
;
568 usbi_dbg("index %d", config_index
);
569 if (config_index
>= dev
->num_configurations
)
570 return LIBUSB_ERROR_NOT_FOUND
;
572 _config
= malloc(sizeof(*_config
));
574 return LIBUSB_ERROR_NO_MEM
;
576 r
= usbi_backend
->get_config_descriptor(dev
, config_index
, tmp
,
577 sizeof(tmp
), &host_endian
);
581 usbi_parse_descriptor(tmp
, "bbw", _config
, host_endian
);
582 buf
= malloc(_config
->wTotalLength
);
584 r
= LIBUSB_ERROR_NO_MEM
;
589 r
= usbi_backend
->get_config_descriptor(dev
, config_index
, buf
,
590 _config
->wTotalLength
, &host_endian
);
594 r
= parse_configuration(dev
->ctx
, _config
, buf
, host_endian
);
596 usbi_err(dev
->ctx
, "parse_configuration failed with error %d", r
);
599 usbi_warn(dev
->ctx
, "descriptor data still left");
613 /* iterate through all configurations, returning the index of the configuration
614 * matching a specific bConfigurationValue in the idx output parameter, or -1
615 * if the config was not found.
616 * returns 0 or a LIBUSB_ERROR code
618 int usbi_get_config_index_by_value(struct libusb_device
*dev
,
619 uint8_t bConfigurationValue
, int *idx
)
623 usbi_dbg("value %d", bConfigurationValue
);
624 for (i
= 0; i
< dev
->num_configurations
; i
++) {
625 unsigned char tmp
[6];
627 int r
= usbi_backend
->get_config_descriptor(dev
, i
, tmp
, sizeof(tmp
),
631 if (tmp
[5] == bConfigurationValue
) {
642 * Get a USB configuration descriptor with a specific bConfigurationValue.
643 * This is a non-blocking function which does not involve any requests being
644 * sent to the device.
646 * \param dev a device
647 * \param bConfigurationValue the bConfigurationValue of the configuration you
649 * \param config output location for the USB configuration descriptor. Only
650 * valid if 0 was returned. Must be freed with libusb_free_config_descriptor()
652 * \returns 0 on success
653 * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist
654 * \returns another LIBUSB_ERROR code on error
655 * \see libusb_get_active_config_descriptor()
656 * \see libusb_get_config_descriptor()
658 int API_EXPORTED
libusb_get_config_descriptor_by_value(libusb_device
*dev
,
659 uint8_t bConfigurationValue
, struct libusb_config_descriptor
**config
)
662 int r
= usbi_get_config_index_by_value(dev
, bConfigurationValue
, &idx
);
666 return LIBUSB_ERROR_NOT_FOUND
;
668 return libusb_get_config_descriptor(dev
, (uint8_t) idx
, config
);
672 * Free a configuration descriptor obtained from
673 * libusb_get_active_config_descriptor() or libusb_get_config_descriptor().
674 * It is safe to call this function with a NULL config parameter, in which
675 * case the function simply returns.
677 * \param config the configuration descriptor to free
679 void API_EXPORTED
libusb_free_config_descriptor(
680 struct libusb_config_descriptor
*config
)
685 clear_configuration(config
);
690 * Retrieve a string descriptor in C style ASCII.
692 * Wrapper around libusb_get_string_descriptor(). Uses the first language
693 * supported by the device.
695 * \param dev a device handle
696 * \param desc_index the index of the descriptor to retrieve
697 * \param data output buffer for ASCII string descriptor
698 * \param length size of data buffer
699 * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure
701 int API_EXPORTED
libusb_get_string_descriptor_ascii(libusb_device_handle
*dev
,
702 uint8_t desc_index
, unsigned char *data
, int length
)
704 unsigned char tbuf
[255]; /* Some devices choke on size > 255 */
708 /* Asking for the zero'th index is special - it returns a string
709 * descriptor that contains all the language IDs supported by the
710 * device. Typically there aren't many - often only one. Language
711 * IDs are 16 bit numbers, and they start at the third byte in the
712 * descriptor. There's also no point in trying to read descriptor 0
713 * with this function. See USB 2.0 specification section 9.6.7 for
718 return LIBUSB_ERROR_INVALID_PARAM
;
720 r
= libusb_get_string_descriptor(dev
, 0, 0, tbuf
, sizeof(tbuf
));
725 return LIBUSB_ERROR_IO
;
727 langid
= tbuf
[2] | (tbuf
[3] << 8);
729 r
= libusb_get_string_descriptor(dev
, desc_index
, langid
, tbuf
,
734 if (tbuf
[1] != LIBUSB_DT_STRING
)
735 return LIBUSB_ERROR_IO
;
738 return LIBUSB_ERROR_IO
;
740 for (di
= 0, si
= 2; si
< tbuf
[0]; si
+= 2) {
741 if (di
>= (length
- 1))
744 if ((tbuf
[si
] & 0x80) || (tbuf
[si
+ 1])) /* non-ASCII */
747 data
[di
++] = tbuf
[si
];