1 /* $FreeBSD: head/lib/libusb/libusb10_desc.c 248236 2013-03-13 12:23:14Z hselasky $ */
3 * Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #ifdef LIBUSB_GLOBAL_INCLUDE_FILE
28 #include LIBUSB_GLOBAL_INCLUDE_FILE
34 #include <sys/queue.h>
37 #define libusb_device_handle libusb20_device
40 #include "libusb20_desc.h"
41 #include "libusb20_int.h"
45 #define N_ALIGN(n) (-((-(n)) & (-8UL)))
50 libusb_get_device_descriptor(libusb_device
*dev
,
51 struct libusb_device_descriptor
*desc
)
53 struct LIBUSB20_DEVICE_DESC_DECODED
*pdesc
;
54 struct libusb20_device
*pdev
;
56 if ((dev
== NULL
) || (desc
== NULL
))
57 return (LIBUSB_ERROR_INVALID_PARAM
);
60 pdesc
= libusb20_dev_get_device_desc(pdev
);
62 desc
->bLength
= pdesc
->bLength
;
63 desc
->bDescriptorType
= pdesc
->bDescriptorType
;
64 desc
->bcdUSB
= pdesc
->bcdUSB
;
65 desc
->bDeviceClass
= pdesc
->bDeviceClass
;
66 desc
->bDeviceSubClass
= pdesc
->bDeviceSubClass
;
67 desc
->bDeviceProtocol
= pdesc
->bDeviceProtocol
;
68 desc
->bMaxPacketSize0
= pdesc
->bMaxPacketSize0
;
69 desc
->idVendor
= pdesc
->idVendor
;
70 desc
->idProduct
= pdesc
->idProduct
;
71 desc
->bcdDevice
= pdesc
->bcdDevice
;
72 desc
->iManufacturer
= pdesc
->iManufacturer
;
73 desc
->iProduct
= pdesc
->iProduct
;
74 desc
->iSerialNumber
= pdesc
->iSerialNumber
;
75 desc
->bNumConfigurations
= pdesc
->bNumConfigurations
;
81 libusb_get_active_config_descriptor(libusb_device
*dev
,
82 struct libusb_config_descriptor
**config
)
84 struct libusb20_device
*pdev
;
88 config_index
= libusb20_dev_get_config_index(pdev
);
90 return (libusb_get_config_descriptor(dev
, config_index
, config
));
94 libusb_get_config_descriptor(libusb_device
*dev
, uint8_t config_index
,
95 struct libusb_config_descriptor
**config
)
97 struct libusb20_device
*pdev
;
98 struct libusb20_config
*pconf
;
99 struct libusb20_interface
*pinf
;
100 struct libusb20_endpoint
*pend
;
101 struct libusb_config_descriptor
*pconfd
;
102 struct libusb_interface_descriptor
*ifd
;
103 struct libusb_endpoint_descriptor
*endd
;
113 if (dev
== NULL
|| config
== NULL
)
114 return (LIBUSB_ERROR_INVALID_PARAM
);
119 pconf
= libusb20_dev_alloc_config(pdev
, config_index
);
122 return (LIBUSB_ERROR_NOT_FOUND
);
124 nalt
= nif
= pconf
->num_interface
;
126 nextra
= N_ALIGN(pconf
->extra
.len
);
128 for (i
= 0; i
< nif
; i
++) {
130 pinf
= pconf
->interface
+ i
;
131 nextra
+= N_ALIGN(pinf
->extra
.len
);
132 nep
+= pinf
->num_endpoints
;
133 k
= pinf
->num_endpoints
;
134 pend
= pinf
->endpoints
;
136 nextra
+= N_ALIGN(pend
->extra
.len
);
140 j
= pinf
->num_altsetting
;
141 nalt
+= pinf
->num_altsetting
;
142 pinf
= pinf
->altsetting
;
144 nextra
+= N_ALIGN(pinf
->extra
.len
);
145 nep
+= pinf
->num_endpoints
;
146 k
= pinf
->num_endpoints
;
147 pend
= pinf
->endpoints
;
149 nextra
+= N_ALIGN(pend
->extra
.len
);
157 (1 * sizeof(libusb_config_descriptor
)) +
158 (nif
* sizeof(libusb_interface
)) +
159 (nalt
* sizeof(libusb_interface_descriptor
)) +
160 (nep
* sizeof(libusb_endpoint_descriptor
));
162 nextra
= N_ALIGN(nextra
);
164 pconfd
= malloc(nextra
);
166 if (pconfd
== NULL
) {
168 return (LIBUSB_ERROR_NO_MEM
);
170 /* make sure memory is initialised */
171 memset(pconfd
, 0, nextra
);
173 pconfd
->interface
= (libusb_interface
*) (pconfd
+ 1);
175 ifd
= (libusb_interface_descriptor
*) (pconfd
->interface
+ nif
);
176 endd
= (libusb_endpoint_descriptor
*) (ifd
+ nalt
);
177 pextra
= (uint8_t *)(endd
+ nep
);
179 /* fill in config descriptor */
181 pconfd
->bLength
= pconf
->desc
.bLength
;
182 pconfd
->bDescriptorType
= pconf
->desc
.bDescriptorType
;
183 pconfd
->wTotalLength
= pconf
->desc
.wTotalLength
;
184 pconfd
->bNumInterfaces
= pconf
->desc
.bNumInterfaces
;
185 pconfd
->bConfigurationValue
= pconf
->desc
.bConfigurationValue
;
186 pconfd
->iConfiguration
= pconf
->desc
.iConfiguration
;
187 pconfd
->bmAttributes
= pconf
->desc
.bmAttributes
;
188 pconfd
->MaxPower
= pconf
->desc
.bMaxPower
;
190 if (pconf
->extra
.len
!= 0) {
191 pconfd
->extra_length
= pconf
->extra
.len
;
192 pconfd
->extra
= pextra
;
193 memcpy(pextra
, pconf
->extra
.ptr
, pconfd
->extra_length
);
194 pextra
+= N_ALIGN(pconfd
->extra_length
);
196 /* setup all interface and endpoint pointers */
198 for (i
= 0; i
< nif
; i
++) {
200 pconfd
->interface
[i
].altsetting
= ifd
;
201 ifd
->endpoint
= endd
;
202 endd
+= pconf
->interface
[i
].num_endpoints
;
205 for (j
= 0; j
< pconf
->interface
[i
].num_altsetting
; j
++) {
206 ifd
->endpoint
= endd
;
207 endd
+= pconf
->interface
[i
].altsetting
[j
].num_endpoints
;
212 /* fill in all interface and endpoint data */
214 for (i
= 0; i
< nif
; i
++) {
215 pinf
= &pconf
->interface
[i
];
216 pconfd
->interface
[i
].num_altsetting
= pinf
->num_altsetting
+ 1;
217 for (j
= 0; j
< pconfd
->interface
[i
].num_altsetting
; j
++) {
219 pinf
= &pconf
->interface
[i
].altsetting
[j
- 1];
220 ifd
= &pconfd
->interface
[i
].altsetting
[j
];
221 ifd
->bLength
= pinf
->desc
.bLength
;
222 ifd
->bDescriptorType
= pinf
->desc
.bDescriptorType
;
223 ifd
->bInterfaceNumber
= pinf
->desc
.bInterfaceNumber
;
224 ifd
->bAlternateSetting
= pinf
->desc
.bAlternateSetting
;
225 ifd
->bNumEndpoints
= pinf
->desc
.bNumEndpoints
;
226 ifd
->bInterfaceClass
= pinf
->desc
.bInterfaceClass
;
227 ifd
->bInterfaceSubClass
= pinf
->desc
.bInterfaceSubClass
;
228 ifd
->bInterfaceProtocol
= pinf
->desc
.bInterfaceProtocol
;
229 ifd
->iInterface
= pinf
->desc
.iInterface
;
230 if (pinf
->extra
.len
!= 0) {
231 ifd
->extra_length
= pinf
->extra
.len
;
233 memcpy(pextra
, pinf
->extra
.ptr
, pinf
->extra
.len
);
234 pextra
+= N_ALIGN(pinf
->extra
.len
);
236 for (k
= 0; k
< pinf
->num_endpoints
; k
++) {
237 pend
= &pinf
->endpoints
[k
];
238 endd
= &ifd
->endpoint
[k
];
239 endd
->bLength
= pend
->desc
.bLength
;
240 endd
->bDescriptorType
= pend
->desc
.bDescriptorType
;
241 endd
->bEndpointAddress
= pend
->desc
.bEndpointAddress
;
242 endd
->bmAttributes
= pend
->desc
.bmAttributes
;
243 endd
->wMaxPacketSize
= pend
->desc
.wMaxPacketSize
;
244 endd
->bInterval
= pend
->desc
.bInterval
;
245 endd
->bRefresh
= pend
->desc
.bRefresh
;
246 endd
->bSynchAddress
= pend
->desc
.bSynchAddress
;
247 if (pend
->extra
.len
!= 0) {
248 endd
->extra_length
= pend
->extra
.len
;
249 endd
->extra
= pextra
;
250 memcpy(pextra
, pend
->extra
.ptr
, pend
->extra
.len
);
251 pextra
+= N_ALIGN(pend
->extra
.len
);
261 return (0); /* success */
265 libusb_get_config_descriptor_by_value(libusb_device
*dev
,
266 uint8_t bConfigurationValue
, struct libusb_config_descriptor
**config
)
268 struct LIBUSB20_DEVICE_DESC_DECODED
*pdesc
;
269 struct libusb20_device
*pdev
;
273 if (dev
== NULL
|| config
== NULL
)
274 return (LIBUSB_ERROR_INVALID_PARAM
);
277 pdesc
= libusb20_dev_get_device_desc(pdev
);
279 for (i
= 0; i
< pdesc
->bNumConfigurations
; i
++) {
280 err
= libusb_get_config_descriptor(dev
, i
, config
);
284 if ((*config
)->bConfigurationValue
== bConfigurationValue
)
285 return (0); /* success */
287 libusb_free_config_descriptor(*config
);
292 return (LIBUSB_ERROR_NOT_FOUND
);
296 libusb_free_config_descriptor(struct libusb_config_descriptor
*config
)
302 libusb_get_string_descriptor(libusb_device_handle
*pdev
,
303 uint8_t desc_index
, uint16_t langid
, unsigned char *data
,
306 if (pdev
== NULL
|| data
== NULL
|| length
< 1)
307 return (LIBUSB_ERROR_INVALID_PARAM
);
312 /* put some default data into the destination buffer */
315 return (libusb_control_transfer(pdev
, LIBUSB_ENDPOINT_IN
,
316 LIBUSB_REQUEST_GET_DESCRIPTOR
, (LIBUSB_DT_STRING
<< 8) | desc_index
,
317 langid
, data
, length
, 1000));
321 libusb_get_string_descriptor_ascii(libusb_device_handle
*pdev
,
322 uint8_t desc_index
, unsigned char *data
, int length
)
324 if (pdev
== NULL
|| data
== NULL
|| length
< 1)
325 return (LIBUSB_ERROR_INVALID_PARAM
);
330 /* put some default data into the destination buffer */
333 if (libusb20_dev_req_string_simple_sync(pdev
, desc_index
,
335 return (strlen(data
));
337 return (LIBUSB_ERROR_OTHER
);
341 libusb_get_descriptor(libusb_device_handle
* devh
, uint8_t desc_type
,
342 uint8_t desc_index
, uint8_t *data
, int length
)
344 if (devh
== NULL
|| data
== NULL
|| length
< 1)
345 return (LIBUSB_ERROR_INVALID_PARAM
);
350 return (libusb_control_transfer(devh
, LIBUSB_ENDPOINT_IN
,
351 LIBUSB_REQUEST_GET_DESCRIPTOR
, (desc_type
<< 8) | desc_index
, 0, data
,
356 libusb_parse_ss_endpoint_comp(const void *buf
, int len
,
357 struct libusb_ss_endpoint_companion_descriptor
**ep_comp
)
359 if (buf
== NULL
|| ep_comp
== NULL
|| len
< 1)
360 return (LIBUSB_ERROR_INVALID_PARAM
);
371 dlen
= ((const uint8_t *)buf
)[0];
372 dtype
= ((const uint8_t *)buf
)[1];
374 if (dlen
< 2 || dlen
> len
)
377 if (dlen
>= LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE
&&
378 dtype
== LIBUSB_DT_SS_ENDPOINT_COMPANION
) {
379 struct libusb_ss_endpoint_companion_descriptor
*ptr
;
381 ptr
= malloc(sizeof(*ptr
));
383 return (LIBUSB_ERROR_NO_MEM
);
385 ptr
->bLength
= LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE
;
386 ptr
->bDescriptorType
= dtype
;
387 ptr
->bMaxBurst
= ((const uint8_t *)buf
)[2];
388 ptr
->bmAttributes
= ((const uint8_t *)buf
)[3];
389 ptr
->wBytesPerInterval
= ((const uint8_t *)buf
)[4] |
390 (((const uint8_t *)buf
)[5] << 8);
394 return (0); /* success */
397 buf
= ((const uint8_t *)buf
) + dlen
;
400 return (LIBUSB_ERROR_IO
);
404 libusb_free_ss_endpoint_comp(struct libusb_ss_endpoint_companion_descriptor
*ep_comp
)
413 libusb_parse_bos_descriptor(const void *buf
, int len
,
414 struct libusb_bos_descriptor
**bos
)
416 struct libusb_bos_descriptor
*ptr
;
417 struct libusb_usb_2_0_device_capability_descriptor
*dcap_20
= NULL
;
418 struct libusb_ss_usb_device_capability_descriptor
*ss_cap
= NULL
;
420 if (buf
== NULL
|| bos
== NULL
|| len
< 1)
421 return (LIBUSB_ERROR_INVALID_PARAM
);
432 dlen
= ((const uint8_t *)buf
)[0];
433 dtype
= ((const uint8_t *)buf
)[1];
435 if (dlen
< 2 || dlen
> len
)
438 if (dlen
>= LIBUSB_DT_BOS_SIZE
&&
439 dtype
== LIBUSB_DT_BOS
) {
441 ptr
= malloc(sizeof(*ptr
) + sizeof(*dcap_20
) +
445 return (LIBUSB_ERROR_NO_MEM
);
449 ptr
->bLength
= LIBUSB_DT_BOS_SIZE
;
450 ptr
->bDescriptorType
= dtype
;
451 ptr
->wTotalLength
= ((const uint8_t *)buf
)[2] |
452 (((const uint8_t *)buf
)[3] << 8);
453 ptr
->bNumDeviceCapabilities
= ((const uint8_t *)buf
)[4];
454 ptr
->usb_2_0_ext_cap
= NULL
;
455 ptr
->ss_usb_cap
= NULL
;
457 dcap_20
= (void *)(ptr
+ 1);
458 ss_cap
= (void *)(dcap_20
+ 1);
462 dtype
== LIBUSB_DT_DEVICE_CAPABILITY
) {
463 switch (((const uint8_t *)buf
)[2]) {
464 case LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY
:
465 if (ptr
->usb_2_0_ext_cap
!= NULL
|| dcap_20
== NULL
)
467 if (dlen
< LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE
)
470 ptr
->usb_2_0_ext_cap
= dcap_20
;
472 dcap_20
->bLength
= LIBUSB_USB_2_0_EXTENSION_DEVICE_CAPABILITY_SIZE
;
473 dcap_20
->bDescriptorType
= dtype
;
474 dcap_20
->bDevCapabilityType
= ((const uint8_t *)buf
)[2];
475 dcap_20
->bmAttributes
= ((const uint8_t *)buf
)[3] |
476 (((const uint8_t *)buf
)[4] << 8) |
477 (((const uint8_t *)buf
)[5] << 16) |
478 (((const uint8_t *)buf
)[6] << 24);
481 case LIBUSB_SS_USB_DEVICE_CAPABILITY
:
482 if (ptr
->ss_usb_cap
!= NULL
|| ss_cap
== NULL
)
484 if (dlen
< LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE
)
487 ptr
->ss_usb_cap
= ss_cap
;
489 ss_cap
->bLength
= LIBUSB_SS_USB_DEVICE_CAPABILITY_SIZE
;
490 ss_cap
->bDescriptorType
= dtype
;
491 ss_cap
->bDevCapabilityType
= ((const uint8_t *)buf
)[2];
492 ss_cap
->bmAttributes
= ((const uint8_t *)buf
)[3];
493 ss_cap
->wSpeedSupported
= ((const uint8_t *)buf
)[4] |
494 (((const uint8_t *)buf
)[5] << 8);
495 ss_cap
->bFunctionalitySupport
= ((const uint8_t *)buf
)[6];
496 ss_cap
->bU1DevExitLat
= ((const uint8_t *)buf
)[7];
497 ss_cap
->wU2DevExitLat
= ((const uint8_t *)buf
)[8] |
498 (((const uint8_t *)buf
)[9] << 8);
506 buf
= ((const uint8_t *)buf
) + dlen
;
510 return (0); /* success */
512 return (LIBUSB_ERROR_IO
);
516 libusb_free_bos_descriptor(struct libusb_bos_descriptor
*bos
)