/src/libusb/libusb/descriptor.c
Line | Count | Source |
1 | | /* -*- Mode: C; indent-tabs-mode:t ; c-basic-offset:8 -*- */ |
2 | | /* |
3 | | * USB descriptor handling functions for libusb |
4 | | * Copyright © 2007 Daniel Drake <dsd@gentoo.org> |
5 | | * Copyright © 2001 Johannes Erdfelt <johannes@erdfelt.com> |
6 | | * |
7 | | * SPDX-License-Identifier: LGPL-2.1-or-later |
8 | | * |
9 | | * This library is free software; you can redistribute it and/or |
10 | | * modify it under the terms of the GNU Lesser General Public |
11 | | * License as published by the Free Software Foundation; either |
12 | | * version 2.1 of the License, or (at your option) any later version. |
13 | | * |
14 | | * This library is distributed in the hope that it will be useful, |
15 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | | * Lesser General Public License for more details. |
18 | | * |
19 | | * You should have received a copy of the GNU Lesser General Public |
20 | | * License along with this library; if not, write to the Free Software |
21 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
22 | | */ |
23 | | |
24 | | #include "libusbi.h" |
25 | | |
26 | | #include <string.h> |
27 | | |
28 | 0 | #define DESC_HEADER_LENGTH 2 |
29 | | |
30 | | /** @defgroup libusb_desc USB descriptors |
31 | | * This page details how to examine the various standard USB descriptors |
32 | | * for detected devices |
33 | | */ |
34 | | |
35 | | static inline uint16_t ReadLittleEndian16(const uint8_t p[2]) |
36 | 0 | { |
37 | 0 | return (uint16_t)((uint16_t)p[1] << 8 | |
38 | 0 | (uint16_t)p[0]); |
39 | 0 | } |
40 | | |
41 | | static inline uint32_t ReadLittleEndian32(const uint8_t p[4]) |
42 | 0 | { |
43 | 0 | return ((uint32_t)p[3] << 24 | |
44 | 0 | (uint32_t)p[2] << 16 | |
45 | 0 | (uint32_t)p[1] << 8 | |
46 | 0 | (uint32_t)p[0]); |
47 | 0 | } |
48 | | |
49 | | static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint) |
50 | 0 | { |
51 | 0 | free((void *)endpoint->extra); |
52 | 0 | } |
53 | | |
54 | | static int parse_endpoint(struct libusb_context *ctx, |
55 | | struct libusb_endpoint_descriptor *endpoint, const uint8_t *buffer, int size) |
56 | 0 | { |
57 | 0 | const struct usbi_descriptor_header *header; |
58 | 0 | const uint8_t *begin; |
59 | 0 | void *extra; |
60 | 0 | int parsed = 0; |
61 | |
|
62 | 0 | if (size < DESC_HEADER_LENGTH) { |
63 | 0 | usbi_err(ctx, "short endpoint descriptor read %d/%d", |
64 | 0 | size, DESC_HEADER_LENGTH); |
65 | 0 | return LIBUSB_ERROR_IO; |
66 | 0 | } |
67 | | |
68 | 0 | header = (const struct usbi_descriptor_header *)buffer; |
69 | 0 | if (header->bDescriptorType != LIBUSB_DT_ENDPOINT) { |
70 | 0 | usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)", |
71 | 0 | header->bDescriptorType, LIBUSB_DT_ENDPOINT); |
72 | 0 | return parsed; |
73 | 0 | } else if (header->bLength < LIBUSB_DT_ENDPOINT_SIZE) { |
74 | 0 | usbi_err(ctx, "invalid endpoint bLength (%u)", header->bLength); |
75 | 0 | return LIBUSB_ERROR_IO; |
76 | 0 | } else if (header->bLength > size) { |
77 | 0 | usbi_warn(ctx, "short endpoint descriptor read %d/%u", |
78 | 0 | size, header->bLength); |
79 | 0 | return parsed; |
80 | 0 | } |
81 | | |
82 | 0 | endpoint->bLength = buffer[0]; |
83 | 0 | endpoint->bDescriptorType = buffer[1]; |
84 | 0 | endpoint->bEndpointAddress = buffer[2]; |
85 | 0 | endpoint->bmAttributes = buffer[3]; |
86 | 0 | endpoint->wMaxPacketSize = ReadLittleEndian16(&buffer[4]); |
87 | 0 | endpoint->bInterval = buffer[6]; |
88 | 0 | if (header->bLength >= LIBUSB_DT_ENDPOINT_AUDIO_SIZE) { |
89 | 0 | endpoint->bRefresh = buffer[7]; |
90 | 0 | endpoint->bSynchAddress = buffer[8]; |
91 | 0 | } |
92 | |
|
93 | 0 | buffer += header->bLength; |
94 | 0 | size -= header->bLength; |
95 | 0 | parsed += header->bLength; |
96 | | |
97 | | /* Skip over the rest of the Class Specific or Vendor Specific */ |
98 | | /* descriptors */ |
99 | 0 | begin = buffer; |
100 | 0 | while (size >= DESC_HEADER_LENGTH) { |
101 | 0 | header = (const struct usbi_descriptor_header *)buffer; |
102 | 0 | if (header->bLength < DESC_HEADER_LENGTH) { |
103 | 0 | usbi_err(ctx, "invalid extra ep desc len (%u)", |
104 | 0 | header->bLength); |
105 | 0 | return LIBUSB_ERROR_IO; |
106 | 0 | } else if (header->bLength > size) { |
107 | 0 | usbi_warn(ctx, "short extra ep desc read %d/%u", |
108 | 0 | size, header->bLength); |
109 | 0 | return parsed; |
110 | 0 | } |
111 | | |
112 | | /* If we find another "proper" descriptor then we're done */ |
113 | 0 | if (header->bDescriptorType == LIBUSB_DT_ENDPOINT || |
114 | 0 | header->bDescriptorType == LIBUSB_DT_INTERFACE || |
115 | 0 | header->bDescriptorType == LIBUSB_DT_CONFIG || |
116 | 0 | header->bDescriptorType == LIBUSB_DT_DEVICE) |
117 | 0 | break; |
118 | | |
119 | 0 | usbi_dbg(ctx, "skipping descriptor 0x%x", header->bDescriptorType); |
120 | 0 | buffer += header->bLength; |
121 | 0 | size -= header->bLength; |
122 | 0 | parsed += header->bLength; |
123 | 0 | } |
124 | | |
125 | | /* Copy any unknown descriptors into a storage area for drivers */ |
126 | | /* to later parse */ |
127 | 0 | ptrdiff_t len = buffer - begin; |
128 | 0 | if (len <= 0) |
129 | 0 | return parsed; |
130 | | |
131 | 0 | extra = malloc((size_t)len); |
132 | 0 | if (!extra) |
133 | 0 | return LIBUSB_ERROR_NO_MEM; |
134 | | |
135 | 0 | memcpy(extra, begin, (size_t)len); |
136 | 0 | endpoint->extra = (const unsigned char *)extra; |
137 | 0 | endpoint->extra_length = (int)len; |
138 | |
|
139 | 0 | return parsed; |
140 | 0 | } |
141 | | |
142 | | static void clear_interface(struct libusb_interface *usb_interface) |
143 | 0 | { |
144 | 0 | int i; |
145 | |
|
146 | 0 | if (usb_interface->altsetting) { |
147 | 0 | for (i = 0; i < usb_interface->num_altsetting; i++) { |
148 | 0 | struct libusb_interface_descriptor *ifp = |
149 | 0 | (struct libusb_interface_descriptor *) |
150 | 0 | usb_interface->altsetting + i; |
151 | |
|
152 | 0 | free((void *)ifp->extra); |
153 | 0 | ifp->extra = NULL; |
154 | 0 | ifp->extra_length = 0; |
155 | 0 | if (ifp->endpoint) { |
156 | 0 | uint8_t j; |
157 | |
|
158 | 0 | for (j = 0; j < ifp->bNumEndpoints; j++) |
159 | 0 | clear_endpoint((struct libusb_endpoint_descriptor *) |
160 | 0 | ifp->endpoint + j); |
161 | 0 | } |
162 | 0 | free((void *)ifp->endpoint); |
163 | 0 | ifp->endpoint = NULL; |
164 | 0 | ifp->bNumEndpoints = 0; |
165 | 0 | } |
166 | 0 | } |
167 | 0 | free((void *)usb_interface->altsetting); |
168 | 0 | usb_interface->altsetting = NULL; |
169 | 0 | usb_interface->num_altsetting = 0; |
170 | 0 | } |
171 | | |
172 | | static int parse_interface(libusb_context *ctx, |
173 | | struct libusb_interface *usb_interface, const uint8_t *buffer, int size) |
174 | 0 | { |
175 | 0 | int r; |
176 | 0 | int parsed = 0; |
177 | 0 | int interface_number = -1; |
178 | 0 | const struct usbi_descriptor_header *header; |
179 | 0 | const struct usbi_interface_descriptor *if_desc; |
180 | 0 | struct libusb_interface_descriptor *ifp; |
181 | 0 | const uint8_t *begin; |
182 | |
|
183 | 0 | while (size >= LIBUSB_DT_INTERFACE_SIZE) { |
184 | 0 | uint8_t bLength = buffer[0]; |
185 | 0 | uint8_t bDescriptorType = buffer[1]; |
186 | 0 | uint8_t bInterfaceNumber = buffer[2]; |
187 | 0 | uint8_t bAlternateSetting = buffer[3]; |
188 | 0 | uint8_t bNumEndpoints = buffer[4]; |
189 | 0 | uint8_t bInterfaceClass = buffer[5]; |
190 | 0 | uint8_t bInterfaceSubClass = buffer[6]; |
191 | 0 | uint8_t bInterfaceProtocol = buffer[7]; |
192 | 0 | uint8_t iInterface = buffer[8]; |
193 | |
|
194 | 0 | if (bDescriptorType != LIBUSB_DT_INTERFACE) { |
195 | 0 | usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)", |
196 | 0 | bDescriptorType, LIBUSB_DT_INTERFACE); |
197 | 0 | return parsed; |
198 | 0 | } else if (bLength < LIBUSB_DT_INTERFACE_SIZE) { |
199 | 0 | usbi_err(ctx, "invalid interface bLength (%u)", |
200 | 0 | bLength); |
201 | 0 | r = LIBUSB_ERROR_IO; |
202 | 0 | goto err; |
203 | 0 | } else if (bLength > size) { |
204 | 0 | usbi_warn(ctx, "short intf descriptor read %d/%u", |
205 | 0 | size, bLength); |
206 | 0 | return parsed; |
207 | 0 | } else if (bNumEndpoints > USB_MAXENDPOINTS) { |
208 | 0 | usbi_err(ctx, "too many endpoints (%u)", bNumEndpoints); |
209 | 0 | r = LIBUSB_ERROR_IO; |
210 | 0 | goto err; |
211 | 0 | } |
212 | | |
213 | 0 | struct libusb_interface_descriptor *altsetting; |
214 | 0 | altsetting = (struct libusb_interface_descriptor *)realloc((void *)usb_interface->altsetting, |
215 | 0 | sizeof(*altsetting) * (size_t)(usb_interface->num_altsetting + 1)); |
216 | 0 | if (!altsetting) { |
217 | 0 | r = LIBUSB_ERROR_NO_MEM; |
218 | 0 | goto err; |
219 | 0 | } |
220 | | |
221 | 0 | ifp = altsetting + usb_interface->num_altsetting; |
222 | 0 | ifp->bLength = bLength; |
223 | 0 | ifp->bDescriptorType = bDescriptorType; |
224 | 0 | ifp->bInterfaceNumber = bInterfaceNumber; |
225 | 0 | ifp->bAlternateSetting = bAlternateSetting; |
226 | 0 | ifp->bNumEndpoints = bNumEndpoints; |
227 | 0 | ifp->bInterfaceClass = bInterfaceClass; |
228 | 0 | ifp->bInterfaceSubClass = bInterfaceSubClass; |
229 | 0 | ifp->bInterfaceProtocol = bInterfaceProtocol; |
230 | 0 | ifp->iInterface = iInterface; |
231 | 0 | ifp->extra = NULL; |
232 | 0 | ifp->extra_length = 0; |
233 | 0 | ifp->endpoint = NULL; |
234 | |
|
235 | 0 | usb_interface->altsetting = altsetting; |
236 | 0 | usb_interface->num_altsetting++; |
237 | |
|
238 | 0 | if (interface_number == -1) |
239 | 0 | interface_number = ifp->bInterfaceNumber; |
240 | | |
241 | | /* Skip over the interface */ |
242 | 0 | buffer += ifp->bLength; |
243 | 0 | parsed += ifp->bLength; |
244 | 0 | size -= ifp->bLength; |
245 | |
|
246 | 0 | begin = buffer; |
247 | | |
248 | | /* Skip over any interface, class or vendor descriptors */ |
249 | 0 | while (size >= DESC_HEADER_LENGTH) { |
250 | 0 | header = (const struct usbi_descriptor_header *)buffer; |
251 | 0 | if (header->bLength < DESC_HEADER_LENGTH) { |
252 | 0 | usbi_err(ctx, |
253 | 0 | "invalid extra intf desc len (%u)", |
254 | 0 | header->bLength); |
255 | 0 | r = LIBUSB_ERROR_IO; |
256 | 0 | goto err; |
257 | 0 | } else if (header->bLength > size) { |
258 | 0 | usbi_warn(ctx, |
259 | 0 | "short extra intf desc read %d/%u", |
260 | 0 | size, header->bLength); |
261 | | /* Keep the invariant: bNumEndpoints > 0 implies |
262 | | * endpoint != NULL. The endpoint array isn't |
263 | | * allocated yet on this early return. */ |
264 | 0 | ifp->bNumEndpoints = 0; |
265 | 0 | return parsed; |
266 | 0 | } |
267 | | |
268 | | /* If we find another "proper" descriptor then we're done */ |
269 | 0 | if (header->bDescriptorType == LIBUSB_DT_INTERFACE || |
270 | 0 | header->bDescriptorType == LIBUSB_DT_ENDPOINT || |
271 | 0 | header->bDescriptorType == LIBUSB_DT_CONFIG || |
272 | 0 | header->bDescriptorType == LIBUSB_DT_DEVICE) |
273 | 0 | break; |
274 | | |
275 | 0 | buffer += header->bLength; |
276 | 0 | parsed += header->bLength; |
277 | 0 | size -= header->bLength; |
278 | 0 | } |
279 | | |
280 | | /* Copy any unknown descriptors into a storage area for */ |
281 | | /* drivers to later parse */ |
282 | 0 | ptrdiff_t len = buffer - begin; |
283 | 0 | if (len > 0) { |
284 | 0 | void *extra = malloc((size_t)len); |
285 | |
|
286 | 0 | if (!extra) { |
287 | 0 | r = LIBUSB_ERROR_NO_MEM; |
288 | 0 | goto err; |
289 | 0 | } |
290 | | |
291 | 0 | memcpy(extra, begin, (size_t)len); |
292 | 0 | ifp->extra = (const unsigned char *)extra; |
293 | 0 | ifp->extra_length = (int)len; |
294 | 0 | } |
295 | | |
296 | 0 | if (ifp->bNumEndpoints > 0) { |
297 | 0 | struct libusb_endpoint_descriptor *endpoint; |
298 | 0 | uint8_t i; |
299 | |
|
300 | 0 | endpoint = (struct libusb_endpoint_descriptor *)calloc(ifp->bNumEndpoints, sizeof(*endpoint)); |
301 | 0 | if (!endpoint) { |
302 | 0 | r = LIBUSB_ERROR_NO_MEM; |
303 | 0 | goto err; |
304 | 0 | } |
305 | | |
306 | 0 | ifp->endpoint = endpoint; |
307 | 0 | for (i = 0; i < ifp->bNumEndpoints; i++) { |
308 | 0 | r = parse_endpoint(ctx, endpoint + i, buffer, size); |
309 | 0 | if (r < 0) |
310 | 0 | goto err; |
311 | 0 | if (r == 0) { |
312 | 0 | ifp->bNumEndpoints = i; |
313 | 0 | break; |
314 | 0 | } |
315 | | |
316 | 0 | buffer += r; |
317 | 0 | parsed += r; |
318 | 0 | size -= r; |
319 | 0 | } |
320 | 0 | } |
321 | | |
322 | | /* We check to see if it's an alternate to this one */ |
323 | 0 | if_desc = (const struct usbi_interface_descriptor *)buffer; |
324 | 0 | if (size < LIBUSB_DT_INTERFACE_SIZE || |
325 | 0 | if_desc->bDescriptorType != LIBUSB_DT_INTERFACE || |
326 | 0 | if_desc->bInterfaceNumber != interface_number) |
327 | 0 | return parsed; |
328 | 0 | } |
329 | | |
330 | 0 | return parsed; |
331 | 0 | err: |
332 | 0 | clear_interface(usb_interface); |
333 | 0 | return r; |
334 | 0 | } |
335 | | |
336 | | static void clear_configuration(struct libusb_config_descriptor *config) |
337 | 0 | { |
338 | 0 | uint8_t i; |
339 | |
|
340 | 0 | if (config->interface) { |
341 | 0 | for (i = 0; i < config->bNumInterfaces; i++) |
342 | 0 | clear_interface((struct libusb_interface *) |
343 | 0 | config->interface + i); |
344 | 0 | } |
345 | 0 | free((void *)config->interface); |
346 | 0 | config->interface = NULL; |
347 | 0 | config->bNumInterfaces = 0; |
348 | 0 | free((void *)config->extra); |
349 | 0 | config->extra = NULL; |
350 | 0 | config->extra_length = 0; |
351 | 0 | } |
352 | | |
353 | | static int parse_configuration(struct libusb_context *ctx, |
354 | | struct libusb_config_descriptor *config, const uint8_t *buffer, int size) |
355 | 0 | { |
356 | 0 | uint8_t i; |
357 | 0 | int r; |
358 | 0 | const struct usbi_descriptor_header *header; |
359 | 0 | struct libusb_interface *usb_interface; |
360 | |
|
361 | 0 | if (size < LIBUSB_DT_CONFIG_SIZE) { |
362 | 0 | usbi_err(ctx, "short config descriptor read %d/%d", |
363 | 0 | size, LIBUSB_DT_CONFIG_SIZE); |
364 | 0 | return LIBUSB_ERROR_IO; |
365 | 0 | } |
366 | | |
367 | 0 | uint8_t bLength = buffer[0]; |
368 | 0 | uint8_t bDescriptorType = buffer[1]; |
369 | 0 | uint16_t wTotalLength = ReadLittleEndian16(&buffer[2]); |
370 | 0 | uint8_t bNumInterfaces = buffer[4]; |
371 | 0 | uint8_t bConfigurationValue = buffer[5]; |
372 | 0 | uint8_t iConfiguration = buffer[6]; |
373 | 0 | uint8_t bmAttributes = buffer[7]; |
374 | 0 | uint8_t MaxPower = buffer[8]; |
375 | |
|
376 | 0 | if (bDescriptorType != LIBUSB_DT_CONFIG) { |
377 | 0 | usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)", |
378 | 0 | bDescriptorType, LIBUSB_DT_CONFIG); |
379 | 0 | return LIBUSB_ERROR_IO; |
380 | 0 | } else if (bLength < LIBUSB_DT_CONFIG_SIZE) { |
381 | 0 | usbi_err(ctx, "invalid config bLength (%u)", bLength); |
382 | 0 | return LIBUSB_ERROR_IO; |
383 | 0 | } else if (bLength > size) { |
384 | 0 | usbi_err(ctx, "short config descriptor read %d/%u", |
385 | 0 | size, bLength); |
386 | 0 | return LIBUSB_ERROR_IO; |
387 | 0 | } else if (bNumInterfaces > USB_MAXINTERFACES) { |
388 | 0 | usbi_err(ctx, "too many interfaces (%u)", bNumInterfaces); |
389 | 0 | return LIBUSB_ERROR_IO; |
390 | 0 | } |
391 | | |
392 | 0 | usb_interface = (struct libusb_interface *)calloc(bNumInterfaces, sizeof(*usb_interface)); |
393 | 0 | if (!usb_interface) |
394 | 0 | return LIBUSB_ERROR_NO_MEM; |
395 | | |
396 | 0 | buffer += bLength; |
397 | 0 | size -= bLength; |
398 | |
|
399 | 0 | for (i = 0; i < bNumInterfaces; i++) { |
400 | 0 | const uint8_t *begin; |
401 | | |
402 | | /* Skip over the rest of the Class Specific or Vendor */ |
403 | | /* Specific descriptors */ |
404 | 0 | begin = buffer; |
405 | 0 | while (size >= DESC_HEADER_LENGTH) { |
406 | 0 | header = (const struct usbi_descriptor_header *)buffer; |
407 | 0 | if (header->bLength < DESC_HEADER_LENGTH) { |
408 | 0 | usbi_err(ctx, |
409 | 0 | "invalid extra config desc len (%u)", |
410 | 0 | header->bLength); |
411 | 0 | r = LIBUSB_ERROR_IO; |
412 | 0 | goto err; |
413 | 0 | } else if (header->bLength > size) { |
414 | 0 | usbi_warn(ctx, |
415 | 0 | "short extra config desc read %d/%u", |
416 | 0 | size, header->bLength); |
417 | 0 | bNumInterfaces = i; |
418 | 0 | goto finish; |
419 | 0 | } |
420 | | |
421 | | /* If we find another "proper" descriptor then we're done */ |
422 | 0 | if (header->bDescriptorType == LIBUSB_DT_ENDPOINT || |
423 | 0 | header->bDescriptorType == LIBUSB_DT_INTERFACE || |
424 | 0 | header->bDescriptorType == LIBUSB_DT_CONFIG || |
425 | 0 | header->bDescriptorType == LIBUSB_DT_DEVICE) |
426 | 0 | break; |
427 | | |
428 | 0 | usbi_dbg(ctx, "skipping descriptor 0x%x", header->bDescriptorType); |
429 | 0 | buffer += header->bLength; |
430 | 0 | size -= header->bLength; |
431 | 0 | } |
432 | | |
433 | | /* Copy any unknown descriptors into a storage area for */ |
434 | | /* drivers to later parse */ |
435 | 0 | ptrdiff_t len = buffer - begin; |
436 | 0 | if (len > 0) { |
437 | 0 | size_t new_extra_len = (size_t)(config->extra_length) + (size_t)len; |
438 | 0 | uint8_t *new_extra = (uint8_t *)realloc((void *)config->extra, new_extra_len); |
439 | |
|
440 | 0 | if (!new_extra) { |
441 | 0 | r = LIBUSB_ERROR_NO_MEM; |
442 | 0 | goto err; |
443 | 0 | } |
444 | | |
445 | 0 | memcpy(new_extra + config->extra_length, begin, (size_t)len); |
446 | 0 | config->extra = new_extra; |
447 | 0 | config->extra_length = (int)new_extra_len; |
448 | 0 | } |
449 | | |
450 | 0 | r = parse_interface(ctx, usb_interface + i, buffer, size); |
451 | 0 | if (r < 0) |
452 | 0 | goto err; |
453 | 0 | if (r == 0) { |
454 | 0 | bNumInterfaces = i; |
455 | 0 | break; |
456 | 0 | } |
457 | | |
458 | 0 | buffer += r; |
459 | 0 | size -= r; |
460 | 0 | } |
461 | | |
462 | 0 | finish: |
463 | 0 | config->interface = usb_interface; |
464 | 0 | config->bNumInterfaces = bNumInterfaces; |
465 | 0 | config->bLength = bLength; |
466 | 0 | config->bDescriptorType = bDescriptorType; |
467 | 0 | config->wTotalLength = wTotalLength; |
468 | 0 | config->bConfigurationValue = bConfigurationValue; |
469 | 0 | config->iConfiguration = iConfiguration; |
470 | 0 | config->bmAttributes = bmAttributes; |
471 | 0 | config->MaxPower = MaxPower; |
472 | |
|
473 | 0 | return size; |
474 | | |
475 | 0 | err: |
476 | | /* Even though we've failed, set these 2 fields so clear_configuration() can dealloc memory. */ |
477 | 0 | config->interface = usb_interface; |
478 | 0 | config->bNumInterfaces = bNumInterfaces; |
479 | |
|
480 | 0 | clear_configuration(config); |
481 | 0 | return r; |
482 | 0 | } |
483 | | |
484 | | static int raw_desc_to_config(struct libusb_context *ctx, |
485 | | const uint8_t *buf, int size, struct libusb_config_descriptor **config) |
486 | 0 | { |
487 | 0 | struct libusb_config_descriptor *_config = (struct libusb_config_descriptor *)calloc(1, sizeof(*_config)); |
488 | 0 | int r; |
489 | |
|
490 | 0 | if (!_config) |
491 | 0 | return LIBUSB_ERROR_NO_MEM; |
492 | | |
493 | 0 | r = parse_configuration(ctx, _config, buf, size); |
494 | 0 | if (r < 0) { |
495 | 0 | usbi_err(ctx, "parse_configuration failed with error %d", r); |
496 | 0 | free(_config); |
497 | 0 | return r; |
498 | 0 | } else if (r > 0) { |
499 | 0 | usbi_warn(ctx, "still %d bytes of descriptor data left", r); |
500 | 0 | } |
501 | | |
502 | 0 | *config = _config; |
503 | 0 | return LIBUSB_SUCCESS; |
504 | 0 | } |
505 | | |
506 | | static int get_active_config_descriptor(struct libusb_device *dev, |
507 | | uint8_t *buffer, size_t size) |
508 | 0 | { |
509 | 0 | int r = usbi_backend.get_active_config_descriptor(dev, buffer, size); |
510 | |
|
511 | 0 | if (r < 0) |
512 | 0 | return r; |
513 | | |
514 | 0 | if (r < LIBUSB_DT_CONFIG_SIZE) { |
515 | 0 | usbi_err(usbi_device_ctx(dev), "short config descriptor read %d/%d", |
516 | 0 | r, LIBUSB_DT_CONFIG_SIZE); |
517 | 0 | return LIBUSB_ERROR_IO; |
518 | 0 | } else if (r != (int)size) { |
519 | 0 | usbi_warn(usbi_device_ctx(dev), "short config descriptor read %d/%d", |
520 | 0 | r, (int)size); |
521 | 0 | } |
522 | | |
523 | 0 | return r; |
524 | 0 | } |
525 | | |
526 | | static int get_config_descriptor(struct libusb_device *dev, uint8_t config_idx, |
527 | | uint8_t *buffer, size_t size) |
528 | 0 | { |
529 | 0 | int r = usbi_backend.get_config_descriptor(dev, config_idx, buffer, size); |
530 | |
|
531 | 0 | if (r < 0) |
532 | 0 | return r; |
533 | 0 | if (r < LIBUSB_DT_CONFIG_SIZE) { |
534 | 0 | usbi_err(usbi_device_ctx(dev), "short config descriptor read %d/%d", |
535 | 0 | r, LIBUSB_DT_CONFIG_SIZE); |
536 | 0 | return LIBUSB_ERROR_IO; |
537 | 0 | } else if (r != (int)size) { |
538 | 0 | usbi_warn(usbi_device_ctx(dev), "short config descriptor read %d/%d", |
539 | 0 | r, (int)size); |
540 | 0 | } |
541 | | |
542 | 0 | return r; |
543 | 0 | } |
544 | | |
545 | | /** \ingroup libusb_desc |
546 | | * Get the USB device descriptor for a given device. |
547 | | * |
548 | | * This is a non-blocking function; the device descriptor is cached in memory. |
549 | | * |
550 | | * Note since libusb-1.0.16, \ref LIBUSBX_API_VERSION >= 0x01000102, this |
551 | | * function always succeeds. |
552 | | * |
553 | | * \param dev the device |
554 | | * \param desc output location for the descriptor data |
555 | | * \returns 0 on success or a LIBUSB_ERROR code on failure |
556 | | */ |
557 | | int API_EXPORTED libusb_get_device_descriptor(libusb_device *dev, |
558 | | struct libusb_device_descriptor *desc) |
559 | 0 | { |
560 | 0 | usbi_dbg(usbi_device_ctx(dev), " "); |
561 | 0 | static_assert(sizeof(dev->device_descriptor) == LIBUSB_DT_DEVICE_SIZE, |
562 | 0 | "struct libusb_device_descriptor is not expected size"); |
563 | 0 | *desc = dev->device_descriptor; |
564 | 0 | return 0; |
565 | 0 | } |
566 | | |
567 | | /** \ingroup libusb_desc |
568 | | * Get the USB configuration descriptor for the currently active configuration. |
569 | | * This is a non-blocking function which does not involve any requests being |
570 | | * sent to the device. |
571 | | * |
572 | | * \param dev a device |
573 | | * \param config output location for the USB configuration descriptor. Only |
574 | | * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() |
575 | | * after use. |
576 | | * \returns 0 on success |
577 | | * \returns \ref LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state |
578 | | * \returns another LIBUSB_ERROR code on error |
579 | | * \see libusb_get_config_descriptor |
580 | | */ |
581 | | int API_EXPORTED libusb_get_active_config_descriptor(libusb_device *dev, |
582 | | struct libusb_config_descriptor **config) |
583 | 0 | { |
584 | 0 | union usbi_config_desc_buf _config; |
585 | 0 | uint16_t config_len; |
586 | 0 | uint8_t *buf; |
587 | 0 | int r; |
588 | |
|
589 | 0 | r = get_active_config_descriptor(dev, _config.buf, sizeof(_config.buf)); |
590 | 0 | if (r < 0) |
591 | 0 | return r; |
592 | | |
593 | 0 | config_len = libusb_le16_to_cpu(_config.desc.wTotalLength); |
594 | 0 | buf = (uint8_t *)malloc(config_len); |
595 | 0 | if (!buf) |
596 | 0 | return LIBUSB_ERROR_NO_MEM; |
597 | | |
598 | 0 | r = get_active_config_descriptor(dev, buf, config_len); |
599 | 0 | if (r >= 0) |
600 | 0 | r = raw_desc_to_config(usbi_device_ctx(dev), buf, r, config); |
601 | |
|
602 | 0 | free(buf); |
603 | 0 | return r; |
604 | 0 | } |
605 | | |
606 | | /** \ingroup libusb_desc |
607 | | * Get a USB configuration descriptor based on its index. |
608 | | * This is a non-blocking function which does not involve any requests being |
609 | | * sent to the device. |
610 | | * |
611 | | * \param dev a device |
612 | | * \param config_index the index of the configuration you wish to retrieve |
613 | | * \param config output location for the USB configuration descriptor. Only |
614 | | * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() |
615 | | * after use. |
616 | | * \returns 0 on success |
617 | | * \returns \ref LIBUSB_ERROR_NOT_FOUND if the configuration does not exist |
618 | | * \returns another LIBUSB_ERROR code on error |
619 | | * \see libusb_get_active_config_descriptor() |
620 | | * \see libusb_get_config_descriptor_by_value() |
621 | | */ |
622 | | int API_EXPORTED libusb_get_config_descriptor(libusb_device *dev, |
623 | | uint8_t config_index, struct libusb_config_descriptor **config) |
624 | 0 | { |
625 | 0 | union usbi_config_desc_buf _config; |
626 | 0 | uint16_t config_len; |
627 | 0 | uint8_t *buf; |
628 | 0 | int r; |
629 | |
|
630 | 0 | usbi_dbg(usbi_device_ctx(dev), "index %u", config_index); |
631 | 0 | if (config_index >= dev->device_descriptor.bNumConfigurations) |
632 | 0 | return LIBUSB_ERROR_NOT_FOUND; |
633 | | |
634 | 0 | r = get_config_descriptor(dev, config_index, _config.buf, sizeof(_config.buf)); |
635 | 0 | if (r < 0) |
636 | 0 | return r; |
637 | | |
638 | 0 | config_len = libusb_le16_to_cpu(_config.desc.wTotalLength); |
639 | 0 | buf = (uint8_t *)malloc(config_len); |
640 | 0 | if (!buf) |
641 | 0 | return LIBUSB_ERROR_NO_MEM; |
642 | | |
643 | 0 | r = get_config_descriptor(dev, config_index, buf, config_len); |
644 | 0 | if (r >= 0) |
645 | 0 | r = raw_desc_to_config(usbi_device_ctx(dev), buf, r, config); |
646 | |
|
647 | 0 | free(buf); |
648 | 0 | return r; |
649 | 0 | } |
650 | | |
651 | | /** \ingroup libusb_desc |
652 | | * Get a USB configuration descriptor with a specific bConfigurationValue. |
653 | | * This is a non-blocking function which does not involve any requests being |
654 | | * sent to the device. |
655 | | * |
656 | | * \param dev a device |
657 | | * \param bConfigurationValue the bConfigurationValue of the configuration you |
658 | | * wish to retrieve |
659 | | * \param config output location for the USB configuration descriptor. Only |
660 | | * valid if 0 was returned. Must be freed with libusb_free_config_descriptor() |
661 | | * after use. |
662 | | * \returns 0 on success |
663 | | * \returns \ref LIBUSB_ERROR_NOT_FOUND if the configuration does not exist |
664 | | * \returns another LIBUSB_ERROR code on error |
665 | | * \see libusb_get_active_config_descriptor() |
666 | | * \see libusb_get_config_descriptor() |
667 | | */ |
668 | | int API_EXPORTED libusb_get_config_descriptor_by_value(libusb_device *dev, |
669 | | uint8_t bConfigurationValue, struct libusb_config_descriptor **config) |
670 | 0 | { |
671 | 0 | uint8_t idx; |
672 | 0 | int r; |
673 | |
|
674 | 0 | if (usbi_backend.get_config_descriptor_by_value) { |
675 | 0 | void *buf; |
676 | |
|
677 | 0 | r = usbi_backend.get_config_descriptor_by_value(dev, |
678 | 0 | bConfigurationValue, &buf); |
679 | 0 | if (r < 0) |
680 | 0 | return r; |
681 | | |
682 | 0 | return raw_desc_to_config(usbi_device_ctx(dev), (uint8_t *)buf, r, config); |
683 | 0 | } |
684 | | |
685 | 0 | usbi_dbg(usbi_device_ctx(dev), "value %u", bConfigurationValue); |
686 | 0 | for (idx = 0; idx < dev->device_descriptor.bNumConfigurations; idx++) { |
687 | 0 | union usbi_config_desc_buf _config; |
688 | |
|
689 | 0 | r = get_config_descriptor(dev, idx, _config.buf, sizeof(_config.buf)); |
690 | 0 | if (r < 0) |
691 | 0 | return r; |
692 | | |
693 | 0 | if (_config.desc.bConfigurationValue == bConfigurationValue) |
694 | 0 | return libusb_get_config_descriptor(dev, idx, config); |
695 | 0 | } |
696 | | |
697 | 0 | return LIBUSB_ERROR_NOT_FOUND; |
698 | 0 | } |
699 | | |
700 | | /** \ingroup libusb_desc |
701 | | * Free a configuration descriptor obtained from |
702 | | * libusb_get_active_config_descriptor() or libusb_get_config_descriptor(). |
703 | | * It is safe to call this function with a NULL config parameter, in which |
704 | | * case the function simply returns. |
705 | | * |
706 | | * \param config the configuration descriptor to free |
707 | | */ |
708 | | void API_EXPORTED libusb_free_config_descriptor( |
709 | | struct libusb_config_descriptor *config) |
710 | 0 | { |
711 | 0 | if (!config) |
712 | 0 | return; |
713 | | |
714 | 0 | clear_configuration(config); |
715 | 0 | free(config); |
716 | 0 | } |
717 | | |
718 | | /** \ingroup libusb_desc |
719 | | * Get an endpoints superspeed endpoint companion descriptor (if any) |
720 | | * |
721 | | * \param ctx the context to operate on, or NULL for the default context |
722 | | * \param endpoint endpoint descriptor from which to get the superspeed |
723 | | * endpoint companion descriptor |
724 | | * \param ep_comp output location for the superspeed endpoint companion |
725 | | * descriptor. Only valid if 0 was returned. Must be freed with |
726 | | * libusb_free_ss_endpoint_companion_descriptor() after use. |
727 | | * \returns 0 on success |
728 | | * \returns \ref LIBUSB_ERROR_NOT_FOUND if the configuration does not exist |
729 | | * \returns another LIBUSB_ERROR code on error |
730 | | */ |
731 | | int API_EXPORTED libusb_get_ss_endpoint_companion_descriptor( |
732 | | libusb_context *ctx, |
733 | | const struct libusb_endpoint_descriptor *endpoint, |
734 | | struct libusb_ss_endpoint_companion_descriptor **ep_comp) |
735 | 0 | { |
736 | 0 | const struct usbi_descriptor_header *header; |
737 | 0 | const uint8_t *buffer = endpoint->extra; |
738 | 0 | int size = endpoint->extra_length; |
739 | |
|
740 | 0 | *ep_comp = NULL; |
741 | |
|
742 | 0 | while (size >= DESC_HEADER_LENGTH) { |
743 | 0 | header = (const struct usbi_descriptor_header *)buffer; |
744 | 0 | if (header->bDescriptorType != LIBUSB_DT_SS_ENDPOINT_COMPANION) { |
745 | 0 | if (header->bLength < DESC_HEADER_LENGTH) { |
746 | 0 | usbi_err(ctx, "invalid descriptor length %u", |
747 | 0 | header->bLength); |
748 | 0 | return LIBUSB_ERROR_IO; |
749 | 0 | } |
750 | 0 | buffer += header->bLength; |
751 | 0 | size -= header->bLength; |
752 | 0 | continue; |
753 | 0 | } else if (header->bLength < LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE) { |
754 | 0 | usbi_err(ctx, "invalid ss-ep-comp-desc length %u", |
755 | 0 | header->bLength); |
756 | 0 | return LIBUSB_ERROR_IO; |
757 | 0 | } else if (header->bLength > size) { |
758 | 0 | usbi_err(ctx, "short ss-ep-comp-desc read %d/%u", |
759 | 0 | size, header->bLength); |
760 | 0 | return LIBUSB_ERROR_IO; |
761 | 0 | } |
762 | | |
763 | 0 | *ep_comp = (struct libusb_ss_endpoint_companion_descriptor *)malloc(sizeof(**ep_comp)); |
764 | 0 | if (!*ep_comp) |
765 | 0 | return LIBUSB_ERROR_NO_MEM; |
766 | 0 | (*ep_comp)->bLength = buffer[0]; |
767 | 0 | (*ep_comp)->bDescriptorType = buffer[1]; |
768 | 0 | (*ep_comp)->bMaxBurst = buffer[2]; |
769 | 0 | (*ep_comp)->bmAttributes = buffer[3]; |
770 | 0 | (*ep_comp)->wBytesPerInterval = ReadLittleEndian16(&buffer[4]); |
771 | 0 | return LIBUSB_SUCCESS; |
772 | 0 | } |
773 | 0 | return LIBUSB_ERROR_NOT_FOUND; |
774 | 0 | } |
775 | | |
776 | | /** \ingroup libusb_desc |
777 | | * Free a superspeed endpoint companion descriptor obtained from |
778 | | * libusb_get_ss_endpoint_companion_descriptor(). |
779 | | * It is safe to call this function with a NULL ep_comp parameter, in which |
780 | | * case the function simply returns. |
781 | | * |
782 | | * \param ep_comp the superspeed endpoint companion descriptor to free |
783 | | */ |
784 | | void API_EXPORTED libusb_free_ss_endpoint_companion_descriptor( |
785 | | struct libusb_ss_endpoint_companion_descriptor *ep_comp) |
786 | 0 | { |
787 | 0 | free(ep_comp); |
788 | 0 | } |
789 | | |
790 | | static int parse_bos(struct libusb_context *ctx, |
791 | | struct libusb_bos_descriptor **bos, |
792 | | const uint8_t *buffer, int size) |
793 | 0 | { |
794 | 0 | struct libusb_bos_descriptor *_bos; |
795 | 0 | const struct usbi_bos_descriptor *bos_desc; |
796 | 0 | const struct usbi_descriptor_header *header; |
797 | 0 | uint8_t i; |
798 | |
|
799 | 0 | if (size < LIBUSB_DT_BOS_SIZE) { |
800 | 0 | usbi_err(ctx, "short bos descriptor read %d/%d", |
801 | 0 | size, LIBUSB_DT_BOS_SIZE); |
802 | 0 | return LIBUSB_ERROR_IO; |
803 | 0 | } |
804 | | |
805 | 0 | bos_desc = (const struct usbi_bos_descriptor *)buffer; |
806 | 0 | if (bos_desc->bDescriptorType != LIBUSB_DT_BOS) { |
807 | 0 | usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)", |
808 | 0 | bos_desc->bDescriptorType, LIBUSB_DT_BOS); |
809 | 0 | return LIBUSB_ERROR_IO; |
810 | 0 | } else if (bos_desc->bLength < LIBUSB_DT_BOS_SIZE) { |
811 | 0 | usbi_err(ctx, "invalid bos bLength (%u)", bos_desc->bLength); |
812 | 0 | return LIBUSB_ERROR_IO; |
813 | 0 | } else if (bos_desc->bLength > size) { |
814 | 0 | usbi_err(ctx, "short bos descriptor read %d/%u", |
815 | 0 | size, bos_desc->bLength); |
816 | 0 | return LIBUSB_ERROR_IO; |
817 | 0 | } |
818 | | |
819 | 0 | _bos = (struct libusb_bos_descriptor *)calloc(1, sizeof(*_bos) + (bos_desc->bNumDeviceCaps * sizeof(void *))); |
820 | 0 | if (!_bos) |
821 | 0 | return LIBUSB_ERROR_NO_MEM; |
822 | | |
823 | 0 | _bos->bLength = buffer[0]; |
824 | 0 | _bos->bDescriptorType = buffer[1]; |
825 | 0 | _bos->wTotalLength = ReadLittleEndian16(&buffer[2]); |
826 | 0 | _bos->bNumDeviceCaps = buffer[4]; |
827 | 0 | buffer += _bos->bLength; |
828 | 0 | size -= _bos->bLength; |
829 | | |
830 | | /* Get the device capability descriptors */ |
831 | 0 | for (i = 0; i < _bos->bNumDeviceCaps; i++) { |
832 | 0 | if (size < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) { |
833 | 0 | usbi_warn(ctx, "short dev-cap descriptor read %d/%d", |
834 | 0 | size, LIBUSB_DT_DEVICE_CAPABILITY_SIZE); |
835 | 0 | break; |
836 | 0 | } |
837 | 0 | header = (const struct usbi_descriptor_header *)buffer; |
838 | 0 | if (header->bDescriptorType != LIBUSB_DT_DEVICE_CAPABILITY) { |
839 | 0 | usbi_warn(ctx, "unexpected descriptor 0x%x (expected 0x%x)", |
840 | 0 | header->bDescriptorType, LIBUSB_DT_DEVICE_CAPABILITY); |
841 | 0 | break; |
842 | 0 | } else if (header->bLength < LIBUSB_DT_DEVICE_CAPABILITY_SIZE) { |
843 | 0 | usbi_err(ctx, "invalid dev-cap bLength (%u)", |
844 | 0 | header->bLength); |
845 | 0 | libusb_free_bos_descriptor(_bos); |
846 | 0 | return LIBUSB_ERROR_IO; |
847 | 0 | } else if (header->bLength > size) { |
848 | 0 | usbi_warn(ctx, "short dev-cap descriptor read %d/%u", |
849 | 0 | size, header->bLength); |
850 | 0 | break; |
851 | 0 | } |
852 | | |
853 | 0 | _bos->dev_capability[i] = (struct libusb_bos_dev_capability_descriptor *)malloc(header->bLength); |
854 | 0 | if (!_bos->dev_capability[i]) { |
855 | 0 | libusb_free_bos_descriptor(_bos); |
856 | 0 | return LIBUSB_ERROR_NO_MEM; |
857 | 0 | } |
858 | 0 | memcpy(_bos->dev_capability[i], buffer, header->bLength); |
859 | 0 | buffer += header->bLength; |
860 | 0 | size -= header->bLength; |
861 | 0 | } |
862 | 0 | _bos->bNumDeviceCaps = i; |
863 | 0 | *bos = _bos; |
864 | |
|
865 | 0 | return LIBUSB_SUCCESS; |
866 | 0 | } |
867 | | |
868 | | /** \ingroup libusb_desc |
869 | | * Get a Binary Object Store (BOS) descriptor |
870 | | * This is a BLOCKING function, which will send requests to the device. |
871 | | * |
872 | | * \param dev_handle the handle of an open libusb device |
873 | | * \param bos output location for the BOS descriptor. Only valid if 0 was returned. |
874 | | * Must be freed with \ref libusb_free_bos_descriptor() after use. |
875 | | * \returns 0 on success |
876 | | * \returns \ref LIBUSB_ERROR_NOT_FOUND if the device doesn't have a BOS descriptor |
877 | | * \returns another LIBUSB_ERROR code on error |
878 | | */ |
879 | | int API_EXPORTED libusb_get_bos_descriptor(libusb_device_handle *dev_handle, |
880 | | struct libusb_bos_descriptor **bos) |
881 | 0 | { |
882 | 0 | union usbi_bos_desc_buf _bos; |
883 | 0 | uint16_t bos_len; |
884 | 0 | uint8_t *bos_data; |
885 | 0 | int r; |
886 | 0 | struct libusb_context *ctx = usbi_handle_ctx(dev_handle); |
887 | | |
888 | | /* Read the BOS. This generates 2 requests on the bus, |
889 | | * one for the header, and one for the full BOS */ |
890 | 0 | r = libusb_get_descriptor(dev_handle, LIBUSB_DT_BOS, 0, _bos.buf, sizeof(_bos.buf)); |
891 | 0 | if (r < 0) { |
892 | 0 | if (r != LIBUSB_ERROR_PIPE) |
893 | 0 | usbi_err(ctx, "failed to read BOS (%d)", r); |
894 | 0 | return r; |
895 | 0 | } |
896 | 0 | if (r < LIBUSB_DT_BOS_SIZE) { |
897 | 0 | usbi_err(ctx, "short BOS read %d/%d", |
898 | 0 | r, LIBUSB_DT_BOS_SIZE); |
899 | 0 | return LIBUSB_ERROR_IO; |
900 | 0 | } |
901 | | |
902 | 0 | bos_len = libusb_le16_to_cpu(_bos.desc.wTotalLength); |
903 | 0 | usbi_dbg(ctx, "found BOS descriptor: size %u bytes, %u capabilities", |
904 | 0 | bos_len, _bos.desc.bNumDeviceCaps); |
905 | 0 | bos_data = (uint8_t *)calloc(1, bos_len); |
906 | 0 | if (!bos_data) |
907 | 0 | return LIBUSB_ERROR_NO_MEM; |
908 | | |
909 | 0 | r = libusb_get_descriptor(dev_handle, LIBUSB_DT_BOS, 0, bos_data, bos_len); |
910 | 0 | if (r >= 0) { |
911 | 0 | if (r != (int)bos_len) |
912 | 0 | usbi_warn(ctx, "short BOS read %d/%u", r, bos_len); |
913 | 0 | r = parse_bos(usbi_handle_ctx(dev_handle), bos, bos_data, r); |
914 | 0 | } else { |
915 | 0 | usbi_err(ctx, "failed to read BOS (%d)", r); |
916 | 0 | } |
917 | |
|
918 | 0 | free(bos_data); |
919 | 0 | return r; |
920 | 0 | } |
921 | | |
922 | | /** \ingroup libusb_desc |
923 | | * Free a BOS descriptor obtained from libusb_get_bos_descriptor(). |
924 | | * It is safe to call this function with a NULL bos parameter, in which |
925 | | * case the function simply returns. |
926 | | * |
927 | | * \param bos the BOS descriptor to free |
928 | | */ |
929 | | void API_EXPORTED libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos) |
930 | 0 | { |
931 | 0 | uint8_t i; |
932 | |
|
933 | 0 | if (!bos) |
934 | 0 | return; |
935 | | |
936 | 0 | for (i = 0; i < bos->bNumDeviceCaps; i++) |
937 | 0 | free(bos->dev_capability[i]); |
938 | 0 | free(bos); |
939 | 0 | } |
940 | | |
941 | | /** \ingroup libusb_desc |
942 | | * Get an USB 2.0 Extension descriptor |
943 | | * |
944 | | * \param ctx the context to operate on, or NULL for the default context |
945 | | * \param dev_cap Device Capability descriptor with a bDevCapabilityType of |
946 | | * \ref libusb_bos_type::LIBUSB_BT_USB_2_0_EXTENSION |
947 | | * LIBUSB_BT_USB_2_0_EXTENSION |
948 | | * \param usb_2_0_extension output location for the USB 2.0 Extension |
949 | | * descriptor. Only valid if 0 was returned. Must be freed with |
950 | | * libusb_free_usb_2_0_extension_descriptor() after use. |
951 | | * \returns 0 on success |
952 | | * \returns a LIBUSB_ERROR code on error |
953 | | */ |
954 | | int API_EXPORTED libusb_get_usb_2_0_extension_descriptor( |
955 | | libusb_context *ctx, |
956 | | struct libusb_bos_dev_capability_descriptor *dev_cap, |
957 | | struct libusb_usb_2_0_extension_descriptor **usb_2_0_extension) |
958 | 0 | { |
959 | 0 | struct libusb_usb_2_0_extension_descriptor *_usb_2_0_extension; |
960 | |
|
961 | 0 | if (dev_cap->bDevCapabilityType != LIBUSB_BT_USB_2_0_EXTENSION) { |
962 | 0 | usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)", |
963 | 0 | dev_cap->bDevCapabilityType, |
964 | 0 | LIBUSB_BT_USB_2_0_EXTENSION); |
965 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
966 | 0 | } else if (dev_cap->bLength < LIBUSB_BT_USB_2_0_EXTENSION_SIZE) { |
967 | 0 | usbi_err(ctx, "short dev-cap descriptor read %u/%d", |
968 | 0 | dev_cap->bLength, LIBUSB_BT_USB_2_0_EXTENSION_SIZE); |
969 | 0 | return LIBUSB_ERROR_IO; |
970 | 0 | } |
971 | | |
972 | 0 | _usb_2_0_extension = (struct libusb_usb_2_0_extension_descriptor *)malloc(sizeof(*_usb_2_0_extension)); |
973 | 0 | if (!_usb_2_0_extension) |
974 | 0 | return LIBUSB_ERROR_NO_MEM; |
975 | | |
976 | 0 | _usb_2_0_extension->bLength = dev_cap->bLength; |
977 | 0 | _usb_2_0_extension->bDescriptorType = dev_cap->bDescriptorType; |
978 | 0 | _usb_2_0_extension->bDevCapabilityType = dev_cap->bDevCapabilityType; |
979 | 0 | _usb_2_0_extension->bmAttributes = ReadLittleEndian32(dev_cap->dev_capability_data); |
980 | |
|
981 | 0 | *usb_2_0_extension = _usb_2_0_extension; |
982 | 0 | return LIBUSB_SUCCESS; |
983 | 0 | } |
984 | | |
985 | | /** \ingroup libusb_desc |
986 | | * Free a USB 2.0 Extension descriptor obtained from |
987 | | * libusb_get_usb_2_0_extension_descriptor(). |
988 | | * It is safe to call this function with a NULL usb_2_0_extension parameter, |
989 | | * in which case the function simply returns. |
990 | | * |
991 | | * \param usb_2_0_extension the USB 2.0 Extension descriptor to free |
992 | | */ |
993 | | void API_EXPORTED libusb_free_usb_2_0_extension_descriptor( |
994 | | struct libusb_usb_2_0_extension_descriptor *usb_2_0_extension) |
995 | 0 | { |
996 | 0 | free(usb_2_0_extension); |
997 | 0 | } |
998 | | |
999 | | /** \ingroup libusb_desc |
1000 | | * Get a SuperSpeed USB Device Capability descriptor |
1001 | | * |
1002 | | * \param ctx the context to operate on, or NULL for the default context |
1003 | | * \param dev_cap Device Capability descriptor with a bDevCapabilityType of |
1004 | | * \ref libusb_bos_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY |
1005 | | * LIBUSB_BT_SS_USB_DEVICE_CAPABILITY |
1006 | | * \param ss_usb_device_cap output location for the SuperSpeed USB Device |
1007 | | * Capability descriptor. Only valid if 0 was returned. Must be freed with |
1008 | | * libusb_free_ss_usb_device_capability_descriptor() after use. |
1009 | | * \returns 0 on success |
1010 | | * \returns a LIBUSB_ERROR code on error |
1011 | | */ |
1012 | | int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor( |
1013 | | libusb_context *ctx, |
1014 | | struct libusb_bos_dev_capability_descriptor *dev_cap, |
1015 | | struct libusb_ss_usb_device_capability_descriptor **ss_usb_device_cap) |
1016 | 0 | { |
1017 | 0 | struct libusb_ss_usb_device_capability_descriptor *_ss_usb_device_cap; |
1018 | |
|
1019 | 0 | if (dev_cap->bDevCapabilityType != LIBUSB_BT_SS_USB_DEVICE_CAPABILITY) { |
1020 | 0 | usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)", |
1021 | 0 | dev_cap->bDevCapabilityType, |
1022 | 0 | LIBUSB_BT_SS_USB_DEVICE_CAPABILITY); |
1023 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1024 | 0 | } else if (dev_cap->bLength < LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE) { |
1025 | 0 | usbi_err(ctx, "short dev-cap descriptor read %u/%d", |
1026 | 0 | dev_cap->bLength, LIBUSB_BT_SS_USB_DEVICE_CAPABILITY_SIZE); |
1027 | 0 | return LIBUSB_ERROR_IO; |
1028 | 0 | } |
1029 | | |
1030 | 0 | _ss_usb_device_cap = (struct libusb_ss_usb_device_capability_descriptor *)malloc(sizeof(*_ss_usb_device_cap)); |
1031 | 0 | if (!_ss_usb_device_cap) |
1032 | 0 | return LIBUSB_ERROR_NO_MEM; |
1033 | | |
1034 | 0 | _ss_usb_device_cap->bLength = dev_cap->bLength; |
1035 | 0 | _ss_usb_device_cap->bDescriptorType = dev_cap->bDescriptorType; |
1036 | 0 | _ss_usb_device_cap->bDevCapabilityType = dev_cap->bDevCapabilityType; |
1037 | 0 | _ss_usb_device_cap->bmAttributes = dev_cap->dev_capability_data[0]; |
1038 | 0 | _ss_usb_device_cap->wSpeedSupported = ReadLittleEndian16(&dev_cap->dev_capability_data[1]); |
1039 | 0 | _ss_usb_device_cap->bFunctionalitySupport = dev_cap->dev_capability_data[3]; |
1040 | 0 | _ss_usb_device_cap->bU1DevExitLat = dev_cap->dev_capability_data[4]; |
1041 | 0 | _ss_usb_device_cap->bU2DevExitLat = ReadLittleEndian16(&dev_cap->dev_capability_data[5]); |
1042 | |
|
1043 | 0 | *ss_usb_device_cap = _ss_usb_device_cap; |
1044 | 0 | return LIBUSB_SUCCESS; |
1045 | 0 | } |
1046 | | |
1047 | | /// @cond DEV |
1048 | | /** \internal \ingroup libusb_desc |
1049 | | * We use this private struct only to parse a SuperSpeedPlus device capability |
1050 | | * descriptor according to section 9.6.2.5 of the USB 3.1 specification. |
1051 | | * We don't expose it. |
1052 | | */ |
1053 | | struct internal_ssplus_capability_descriptor { |
1054 | | /** The length of the descriptor. Must be equal to LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE */ |
1055 | | uint8_t bLength; |
1056 | | |
1057 | | /** The type of the descriptor */ |
1058 | | uint8_t bDescriptorType; |
1059 | | |
1060 | | /** Must be equal to LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY */ |
1061 | | uint8_t bDevCapabilityType; |
1062 | | |
1063 | | /** Unused */ |
1064 | | uint8_t bReserved; |
1065 | | |
1066 | | /** Contains the number of SublinkSpeedIDs */ |
1067 | | uint32_t bmAttributes; |
1068 | | |
1069 | | /** Contains the ssid, minRxLaneCount, and minTxLaneCount */ |
1070 | | uint16_t wFunctionalitySupport; |
1071 | | |
1072 | | /** Unused */ |
1073 | | uint16_t wReserved; |
1074 | | }; |
1075 | | /// @endcond |
1076 | | |
1077 | | /** \ingroup libusb_desc |
1078 | | * Get a SuperSpeedPlus USB Device Capability descriptor |
1079 | | * |
1080 | | * Since version 1.0.28, \ref LIBUSB_API_VERSION >= 0x0100010B |
1081 | | * |
1082 | | * \param ctx the context to operate on, or NULL for the default context |
1083 | | * \param dev_cap Device Capability descriptor with a bDevCapabilityType of |
1084 | | * \ref libusb_bos_type::LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY |
1085 | | * LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY |
1086 | | * \param ssplus_usb_device_cap output location for the SuperSpeedPlus USB Device |
1087 | | * Capability descriptor. Only valid if 0 was returned. Must be freed with |
1088 | | * libusb_free_ssplus_usb_device_capability_descriptor() after use. |
1089 | | * \returns 0 on success |
1090 | | * \returns a LIBUSB_ERROR code on error |
1091 | | */ |
1092 | | int API_EXPORTED libusb_get_ssplus_usb_device_capability_descriptor( |
1093 | | libusb_context *ctx, |
1094 | | struct libusb_bos_dev_capability_descriptor *dev_cap, |
1095 | | struct libusb_ssplus_usb_device_capability_descriptor **ssplus_usb_device_cap) |
1096 | 0 | { |
1097 | 0 | struct libusb_ssplus_usb_device_capability_descriptor *_ssplus_cap; |
1098 | | |
1099 | | /* Use a private struct to reuse our descriptor parsing system. */ |
1100 | 0 | struct internal_ssplus_capability_descriptor parsedDescriptor; |
1101 | | |
1102 | | /* Some size/type checks to make sure everything is in order */ |
1103 | 0 | if (dev_cap->bDevCapabilityType != LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY) { |
1104 | 0 | usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)", |
1105 | 0 | dev_cap->bDevCapabilityType, |
1106 | 0 | LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY); |
1107 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1108 | 0 | } else if (dev_cap->bLength < LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE) { |
1109 | 0 | usbi_err(ctx, "short dev-cap descriptor read %u/%d", |
1110 | 0 | dev_cap->bLength, LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE); |
1111 | 0 | return LIBUSB_ERROR_IO; |
1112 | 0 | } |
1113 | | |
1114 | 0 | const uint8_t* dev_capability_data = dev_cap->dev_capability_data; |
1115 | 0 | parsedDescriptor.bLength = dev_cap->bLength; |
1116 | 0 | parsedDescriptor.bDescriptorType = dev_cap->bDescriptorType; |
1117 | 0 | parsedDescriptor.bDevCapabilityType = dev_cap->bDevCapabilityType; |
1118 | 0 | parsedDescriptor.bReserved = dev_capability_data[0]; |
1119 | 0 | parsedDescriptor.bmAttributes = ReadLittleEndian32(&dev_capability_data[1]); |
1120 | 0 | parsedDescriptor.wFunctionalitySupport = ReadLittleEndian16(&dev_capability_data[5]); |
1121 | 0 | parsedDescriptor.wReserved = ReadLittleEndian16(&dev_capability_data[7]); |
1122 | |
|
1123 | 0 | uint8_t numSublikSpeedAttributes = (parsedDescriptor.bmAttributes & 0xF) + 1; |
1124 | 0 | _ssplus_cap = (struct libusb_ssplus_usb_device_capability_descriptor *)malloc(sizeof(struct libusb_ssplus_usb_device_capability_descriptor) + (numSublikSpeedAttributes * sizeof(struct libusb_ssplus_sublink_attribute))); |
1125 | 0 | if (!_ssplus_cap) |
1126 | 0 | return LIBUSB_ERROR_NO_MEM; |
1127 | | |
1128 | | /* Parse bmAttributes */ |
1129 | 0 | _ssplus_cap->numSublinkSpeedAttributes = numSublikSpeedAttributes; |
1130 | 0 | _ssplus_cap->numSublinkSpeedIDs = ((parsedDescriptor.bmAttributes & 0xF0) >> 4) + 1; |
1131 | | |
1132 | | /* Parse wFunctionalitySupport */ |
1133 | 0 | _ssplus_cap->ssid = parsedDescriptor.wFunctionalitySupport & 0xF; |
1134 | 0 | _ssplus_cap->minRxLaneCount = (parsedDescriptor.wFunctionalitySupport & 0x0F00) >> 8; |
1135 | 0 | _ssplus_cap->minTxLaneCount = (parsedDescriptor.wFunctionalitySupport & 0xF000) >> 12; |
1136 | | |
1137 | | /* Check that we have enough to read all the sublink attributes */ |
1138 | 0 | if (dev_cap->bLength < LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE + (_ssplus_cap->numSublinkSpeedAttributes * sizeof(uint32_t))) { |
1139 | 0 | free(_ssplus_cap); |
1140 | 0 | usbi_err(ctx, "short ssplus capability descriptor, unable to read sublinks: Not enough data"); |
1141 | 0 | return LIBUSB_ERROR_IO; |
1142 | 0 | } |
1143 | | |
1144 | | /* Read the attributes */ |
1145 | 0 | uint8_t* base = ((uint8_t*)dev_cap) + LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE; |
1146 | 0 | for(uint8_t i = 0 ; i < _ssplus_cap->numSublinkSpeedAttributes ; i++) { |
1147 | 0 | uint32_t attr = ReadLittleEndian32(base + (i * sizeof(uint32_t))); |
1148 | 0 | _ssplus_cap->sublinkSpeedAttributes[i].ssid = attr & 0x0f; |
1149 | 0 | _ssplus_cap->sublinkSpeedAttributes[i].mantissa = attr >> 16; |
1150 | 0 | _ssplus_cap->sublinkSpeedAttributes[i].exponent = (enum libusb_superspeedplus_sublink_attribute_exponent)((attr >> 4) & 0x3); |
1151 | 0 | _ssplus_cap->sublinkSpeedAttributes[i].type = attr & 0x40 ? LIBUSB_SSPLUS_ATTR_TYPE_ASYM : LIBUSB_SSPLUS_ATTR_TYPE_SYM; |
1152 | 0 | _ssplus_cap->sublinkSpeedAttributes[i].direction = attr & 0x80 ? LIBUSB_SSPLUS_ATTR_DIR_TX : LIBUSB_SSPLUS_ATTR_DIR_RX; |
1153 | 0 | _ssplus_cap->sublinkSpeedAttributes[i].protocol = attr & 0x4000 ? LIBUSB_SSPLUS_ATTR_PROT_SSPLUS: LIBUSB_SSPLUS_ATTR_PROT_SS; |
1154 | 0 | } |
1155 | |
|
1156 | 0 | *ssplus_usb_device_cap = _ssplus_cap; |
1157 | 0 | return LIBUSB_SUCCESS; |
1158 | 0 | } |
1159 | | |
1160 | | /** \ingroup libusb_desc |
1161 | | * Free a SuperSpeedPlus USB Device Capability descriptor obtained from |
1162 | | * libusb_get_ssplus_usb_device_capability_descriptor(). |
1163 | | * It is safe to call this function with a NULL ssplus_usb_device_cap |
1164 | | * parameter, in which case the function simply returns. |
1165 | | * |
1166 | | * Since version 1.0.28, \ref LIBUSB_API_VERSION >= 0x0100010B |
1167 | | * |
1168 | | * \param ssplus_usb_device_cap the SuperSpeedPlus USB Device Capability descriptor |
1169 | | * to free |
1170 | | */ |
1171 | | void API_EXPORTED libusb_free_ssplus_usb_device_capability_descriptor( |
1172 | | struct libusb_ssplus_usb_device_capability_descriptor *ssplus_usb_device_cap) |
1173 | 0 | { |
1174 | 0 | free(ssplus_usb_device_cap); |
1175 | 0 | } |
1176 | | |
1177 | | |
1178 | | |
1179 | | /** \ingroup libusb_desc |
1180 | | * Free a SuperSpeed USB Device Capability descriptor obtained from |
1181 | | * libusb_get_ss_usb_device_capability_descriptor(). |
1182 | | * It is safe to call this function with a NULL ss_usb_device_cap |
1183 | | * parameter, in which case the function simply returns. |
1184 | | * |
1185 | | * \param ss_usb_device_cap the SuperSpeed USB Device Capability descriptor |
1186 | | * to free |
1187 | | */ |
1188 | | void API_EXPORTED libusb_free_ss_usb_device_capability_descriptor( |
1189 | | struct libusb_ss_usb_device_capability_descriptor *ss_usb_device_cap) |
1190 | 0 | { |
1191 | 0 | free(ss_usb_device_cap); |
1192 | 0 | } |
1193 | | |
1194 | | /** \ingroup libusb_desc |
1195 | | * Get a Container ID descriptor |
1196 | | * |
1197 | | * \param ctx the context to operate on, or NULL for the default context |
1198 | | * \param dev_cap Device Capability descriptor with a bDevCapabilityType of |
1199 | | * \ref libusb_bos_type::LIBUSB_BT_CONTAINER_ID |
1200 | | * LIBUSB_BT_CONTAINER_ID |
1201 | | * \param container_id output location for the Container ID descriptor. |
1202 | | * Only valid if 0 was returned. Must be freed with |
1203 | | * libusb_free_container_id_descriptor() after use. |
1204 | | * \returns 0 on success |
1205 | | * \returns a LIBUSB_ERROR code on error |
1206 | | */ |
1207 | | int API_EXPORTED libusb_get_container_id_descriptor(libusb_context *ctx, |
1208 | | struct libusb_bos_dev_capability_descriptor *dev_cap, |
1209 | | struct libusb_container_id_descriptor **container_id) |
1210 | 0 | { |
1211 | 0 | struct libusb_container_id_descriptor *_container_id; |
1212 | |
|
1213 | 0 | if (dev_cap->bDevCapabilityType != LIBUSB_BT_CONTAINER_ID) { |
1214 | 0 | usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)", |
1215 | 0 | dev_cap->bDevCapabilityType, |
1216 | 0 | LIBUSB_BT_CONTAINER_ID); |
1217 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1218 | 0 | } else if (dev_cap->bLength < LIBUSB_BT_CONTAINER_ID_SIZE) { |
1219 | 0 | usbi_err(ctx, "short dev-cap descriptor read %u/%d", |
1220 | 0 | dev_cap->bLength, LIBUSB_BT_CONTAINER_ID_SIZE); |
1221 | 0 | return LIBUSB_ERROR_IO; |
1222 | 0 | } |
1223 | | |
1224 | 0 | _container_id = (struct libusb_container_id_descriptor *)malloc(sizeof(*_container_id)); |
1225 | 0 | if (!_container_id) |
1226 | 0 | return LIBUSB_ERROR_NO_MEM; |
1227 | | |
1228 | 0 | _container_id->bLength = dev_cap->bLength; |
1229 | 0 | _container_id->bDescriptorType = dev_cap->bDescriptorType; |
1230 | 0 | _container_id->bDevCapabilityType = dev_cap->bDevCapabilityType; |
1231 | 0 | _container_id->bReserved = dev_cap->dev_capability_data[0]; |
1232 | 0 | memcpy(_container_id->ContainerID, &dev_cap->dev_capability_data[1], 16); |
1233 | |
|
1234 | 0 | *container_id = _container_id; |
1235 | 0 | return LIBUSB_SUCCESS; |
1236 | 0 | } |
1237 | | |
1238 | | /** \ingroup libusb_desc |
1239 | | * Free a Container ID descriptor obtained from |
1240 | | * libusb_get_container_id_descriptor(). |
1241 | | * It is safe to call this function with a NULL container_id parameter, |
1242 | | * in which case the function simply returns. |
1243 | | * |
1244 | | * \param container_id the Container ID descriptor to free |
1245 | | */ |
1246 | | void API_EXPORTED libusb_free_container_id_descriptor( |
1247 | | struct libusb_container_id_descriptor *container_id) |
1248 | 0 | { |
1249 | 0 | free(container_id); |
1250 | 0 | } |
1251 | | |
1252 | | /** \ingroup libusb_desc |
1253 | | * Get a platform descriptor |
1254 | | * |
1255 | | * Since version 1.0.27, \ref LIBUSB_API_VERSION >= 0x0100010A |
1256 | | * |
1257 | | * \param ctx the context to operate on, or NULL for the default context |
1258 | | * \param dev_cap Device Capability descriptor with a bDevCapabilityType of |
1259 | | * \ref libusb_bos_type::LIBUSB_BT_PLATFORM_DESCRIPTOR |
1260 | | * LIBUSB_BT_PLATFORM_DESCRIPTOR |
1261 | | * \param platform_descriptor output location for the Platform descriptor. |
1262 | | * Only valid if 0 was returned. Must be freed with |
1263 | | * libusb_free_platform_descriptor() after use. |
1264 | | * \returns 0 on success |
1265 | | * \returns a LIBUSB_ERROR code on error |
1266 | | */ |
1267 | | int API_EXPORTED libusb_get_platform_descriptor(libusb_context *ctx, |
1268 | | struct libusb_bos_dev_capability_descriptor *dev_cap, |
1269 | | struct libusb_platform_descriptor **platform_descriptor) |
1270 | 0 | { |
1271 | 0 | struct libusb_platform_descriptor *_platform_descriptor; |
1272 | |
|
1273 | 0 | if (dev_cap->bDevCapabilityType != LIBUSB_BT_PLATFORM_DESCRIPTOR) { |
1274 | 0 | usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)", |
1275 | 0 | dev_cap->bDevCapabilityType, |
1276 | 0 | LIBUSB_BT_PLATFORM_DESCRIPTOR); |
1277 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1278 | 0 | } else if (dev_cap->bLength < LIBUSB_BT_PLATFORM_DESCRIPTOR_MIN_SIZE) { |
1279 | 0 | usbi_err(ctx, "short dev-cap descriptor read %u/%d", |
1280 | 0 | dev_cap->bLength, LIBUSB_BT_PLATFORM_DESCRIPTOR_MIN_SIZE); |
1281 | 0 | return LIBUSB_ERROR_IO; |
1282 | 0 | } |
1283 | | |
1284 | 0 | _platform_descriptor = (struct libusb_platform_descriptor *)malloc(dev_cap->bLength); |
1285 | 0 | if (!_platform_descriptor) |
1286 | 0 | return LIBUSB_ERROR_NO_MEM; |
1287 | | |
1288 | 0 | _platform_descriptor->bLength = dev_cap->bLength; |
1289 | 0 | _platform_descriptor->bDescriptorType = dev_cap->bDescriptorType; |
1290 | 0 | _platform_descriptor->bDevCapabilityType = dev_cap->bDevCapabilityType; |
1291 | 0 | _platform_descriptor->bReserved = dev_cap->dev_capability_data[0]; |
1292 | 0 | memcpy(_platform_descriptor->PlatformCapabilityUUID, &(dev_cap->dev_capability_data[1]), 16); |
1293 | | |
1294 | | /* Capability data is located after reserved byte and 16 byte UUID */ |
1295 | 0 | uint8_t* capability_data = dev_cap->dev_capability_data + 1 + 16; |
1296 | | |
1297 | | /* Capability data length is total descriptor length minus initial fields */ |
1298 | 0 | size_t capability_data_length = dev_cap->bLength - (3 + 1 + 16); |
1299 | |
|
1300 | 0 | memcpy(_platform_descriptor->CapabilityData, capability_data, capability_data_length); |
1301 | |
|
1302 | 0 | *platform_descriptor = _platform_descriptor; |
1303 | 0 | return LIBUSB_SUCCESS; |
1304 | 0 | } |
1305 | | |
1306 | | /** \ingroup libusb_desc |
1307 | | * Free a platform descriptor obtained from |
1308 | | * libusb_get_platform_descriptor(). |
1309 | | * It is safe to call this function with a NULL platform_descriptor parameter, |
1310 | | * in which case the function simply returns. |
1311 | | * |
1312 | | * \param platform_descriptor the Platform descriptor to free |
1313 | | */ |
1314 | | void API_EXPORTED libusb_free_platform_descriptor( |
1315 | | struct libusb_platform_descriptor *platform_descriptor) |
1316 | 0 | { |
1317 | 0 | free(platform_descriptor); |
1318 | 0 | } |
1319 | | |
1320 | | /** \ingroup libusb_desc |
1321 | | * Retrieve a string descriptor in C style ASCII. |
1322 | | * |
1323 | | * Wrapper around libusb_get_string_descriptor(). Uses the first language |
1324 | | * supported by the device. |
1325 | | * |
1326 | | * \param dev_handle a device handle |
1327 | | * \param desc_index the index of the descriptor to retrieve |
1328 | | * \param data output buffer for ASCII string descriptor |
1329 | | * \param length size of data buffer |
1330 | | * \returns number of bytes returned in data, or LIBUSB_ERROR code on failure |
1331 | | */ |
1332 | | int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_handle, |
1333 | | uint8_t desc_index, unsigned char *data, int length) |
1334 | 0 | { |
1335 | 0 | union usbi_string_desc_buf str; |
1336 | 0 | int r; |
1337 | 0 | uint16_t langid, wdata; |
1338 | | |
1339 | | /* Asking for the zero'th index is special - it returns a string |
1340 | | * descriptor that contains all the language IDs supported by the |
1341 | | * device. Typically there aren't many - often only one. Language |
1342 | | * IDs are 16 bit numbers, and they start at the third byte in the |
1343 | | * descriptor. There's also no point in trying to read descriptor 0 |
1344 | | * with this function. See USB 2.0 specification section 9.6.7 for |
1345 | | * more information. |
1346 | | */ |
1347 | |
|
1348 | 0 | if (desc_index == 0) |
1349 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1350 | | |
1351 | 0 | r = libusb_get_string_descriptor(dev_handle, 0, 0, str.buf, 4); |
1352 | 0 | if (r < 0) |
1353 | 0 | return r; |
1354 | 0 | else if (r != 4 || str.desc.bLength < 4 || str.desc.bDescriptorType != LIBUSB_DT_STRING) { |
1355 | 0 | usbi_warn(usbi_handle_ctx(dev_handle), "invalid language ID string descriptor"); |
1356 | 0 | return LIBUSB_ERROR_IO; |
1357 | 0 | } else if (str.desc.bLength & 1) |
1358 | 0 | usbi_warn(usbi_handle_ctx(dev_handle), "suspicious bLength %u for language ID string descriptor", str.desc.bLength); |
1359 | | |
1360 | 0 | langid = libusb_le16_to_cpu(str.desc.wData[0]); |
1361 | 0 | r = libusb_get_string_descriptor(dev_handle, desc_index, langid, str.buf, sizeof(str.buf)); |
1362 | 0 | if (r < 0) |
1363 | 0 | return r; |
1364 | 0 | else if (r < DESC_HEADER_LENGTH || str.desc.bLength > r || str.desc.bDescriptorType != LIBUSB_DT_STRING) |
1365 | 0 | return LIBUSB_ERROR_IO; |
1366 | 0 | else if ((str.desc.bLength & 1) || str.desc.bLength != r) |
1367 | 0 | usbi_warn(usbi_handle_ctx(dev_handle), "suspicious bLength %u for string descriptor (read %d)", str.desc.bLength, r); |
1368 | | |
1369 | | /* Stop one byte before the end to leave room for null termination. */ |
1370 | 0 | int dest_max = length - 1; |
1371 | | |
1372 | | /* The descriptor has this number of wide characters */ |
1373 | 0 | int src_max = (str.desc.bLength - 1 - 1) / 2; |
1374 | | |
1375 | | /* Neither read nor write more than the smallest buffer */ |
1376 | 0 | int idx_max = MIN(dest_max, src_max); |
1377 | |
|
1378 | 0 | int idx; |
1379 | 0 | for (idx = 0; idx < idx_max; ++idx) { |
1380 | 0 | wdata = libusb_le16_to_cpu(str.desc.wData[idx]); |
1381 | 0 | if (wdata < 0x80) |
1382 | 0 | data[idx] = (unsigned char)wdata; |
1383 | 0 | else |
1384 | 0 | data[idx] = '?'; /* non-ASCII */ |
1385 | 0 | } |
1386 | |
|
1387 | 0 | data[idx] = 0; /* null-terminate string */ |
1388 | 0 | return idx; |
1389 | 0 | } |
1390 | | |
1391 | | static int parse_iad_array(struct libusb_context *ctx, |
1392 | | struct libusb_interface_association_descriptor_array *iad_array, |
1393 | | const uint8_t *buffer, int size) |
1394 | 0 | { |
1395 | 0 | uint8_t i; |
1396 | 0 | struct usbi_descriptor_header header; |
1397 | 0 | int consumed = 0; |
1398 | 0 | const uint8_t *buf = buffer; |
1399 | 0 | struct libusb_interface_association_descriptor *iad; |
1400 | 0 | int iad_length = 0; |
1401 | |
|
1402 | 0 | iad_array->iad = NULL; |
1403 | 0 | iad_array->length = 0; |
1404 | |
|
1405 | 0 | if (size < LIBUSB_DT_CONFIG_SIZE) { |
1406 | 0 | usbi_err(ctx, "short config descriptor read %d/%d", |
1407 | 0 | size, LIBUSB_DT_CONFIG_SIZE); |
1408 | 0 | return LIBUSB_ERROR_IO; |
1409 | 0 | } |
1410 | | |
1411 | | /* First pass: Iterate through desc list, count number of IADs */ |
1412 | 0 | while (size - consumed >= DESC_HEADER_LENGTH) { |
1413 | 0 | header.bLength = buf[0]; |
1414 | 0 | header.bDescriptorType = buf[1]; |
1415 | 0 | if (header.bLength < DESC_HEADER_LENGTH) { |
1416 | 0 | usbi_err(ctx, "invalid descriptor bLength %d", |
1417 | 0 | header.bLength); |
1418 | 0 | return LIBUSB_ERROR_IO; |
1419 | 0 | } |
1420 | 0 | else if (header.bLength > size - consumed) { |
1421 | 0 | usbi_warn(ctx, "short config descriptor read %d/%u", |
1422 | 0 | size - consumed, header.bLength); |
1423 | 0 | return LIBUSB_ERROR_IO; |
1424 | 0 | } |
1425 | 0 | if (header.bDescriptorType == LIBUSB_DT_INTERFACE_ASSOCIATION) |
1426 | 0 | iad_length++; |
1427 | 0 | buf += header.bLength; |
1428 | 0 | consumed += header.bLength; |
1429 | 0 | } |
1430 | | |
1431 | 0 | if (iad_length > 0) { |
1432 | 0 | iad = (struct libusb_interface_association_descriptor *)calloc((size_t)iad_length, sizeof(*iad)); |
1433 | 0 | if (!iad) |
1434 | 0 | return LIBUSB_ERROR_NO_MEM; |
1435 | | |
1436 | 0 | iad_array->iad = iad; |
1437 | 0 | iad_array->length = iad_length; |
1438 | | |
1439 | | /* Second pass: Iterate through desc list, fill IAD structures */ |
1440 | 0 | i = 0; |
1441 | 0 | do { |
1442 | 0 | header.bLength = buffer[0]; |
1443 | 0 | header.bDescriptorType = buffer[1]; |
1444 | 0 | if (header.bDescriptorType == LIBUSB_DT_INTERFACE_ASSOCIATION && (size >= LIBUSB_DT_INTERFACE_ASSOCIATION_SIZE)) { |
1445 | 0 | iad[i].bLength = buffer[0]; |
1446 | 0 | iad[i].bDescriptorType = buffer[1]; |
1447 | 0 | iad[i].bFirstInterface = buffer[2]; |
1448 | 0 | iad[i].bInterfaceCount = buffer[3]; |
1449 | 0 | iad[i].bFunctionClass = buffer[4]; |
1450 | 0 | iad[i].bFunctionSubClass = buffer[5]; |
1451 | 0 | iad[i].bFunctionProtocol = buffer[6]; |
1452 | 0 | iad[i].iFunction = buffer[7]; |
1453 | 0 | i++; |
1454 | 0 | } |
1455 | |
|
1456 | 0 | if (size - header.bLength < DESC_HEADER_LENGTH) { |
1457 | 0 | break; |
1458 | 0 | } |
1459 | | |
1460 | 0 | size -= header.bLength; |
1461 | 0 | buffer += header.bLength; |
1462 | 0 | } while (1); |
1463 | 0 | } |
1464 | | |
1465 | 0 | return LIBUSB_SUCCESS; |
1466 | 0 | } |
1467 | | |
1468 | | static int raw_desc_to_iad_array(struct libusb_context *ctx, const uint8_t *buf, |
1469 | | int size, struct libusb_interface_association_descriptor_array **iad_array) |
1470 | 0 | { |
1471 | 0 | struct libusb_interface_association_descriptor_array *_iad_array |
1472 | 0 | = (struct libusb_interface_association_descriptor_array *)calloc(1, sizeof(*_iad_array)); |
1473 | 0 | int r; |
1474 | |
|
1475 | 0 | if (!_iad_array) |
1476 | 0 | return LIBUSB_ERROR_NO_MEM; |
1477 | | |
1478 | 0 | r = parse_iad_array(ctx, _iad_array, buf, size); |
1479 | 0 | if (r < 0) { |
1480 | 0 | usbi_err(ctx, "parse_iad_array failed with error %d", r); |
1481 | 0 | free(_iad_array); |
1482 | 0 | return r; |
1483 | 0 | } |
1484 | | |
1485 | 0 | *iad_array = _iad_array; |
1486 | 0 | return LIBUSB_SUCCESS; |
1487 | 0 | } |
1488 | | |
1489 | | /** \ingroup libusb_desc |
1490 | | * Get an array of interface association descriptors (IAD) for a given |
1491 | | * configuration. |
1492 | | * This is a non-blocking function which does not involve any requests being |
1493 | | * sent to the device. |
1494 | | * |
1495 | | * \param dev a device |
1496 | | * \param config_index the index of the configuration you wish to retrieve the |
1497 | | * IADs for. |
1498 | | * \param iad_array output location for the array of IADs. Only valid if 0 was |
1499 | | * returned. Must be freed with libusb_free_interface_association_descriptors() |
1500 | | * after use. It's possible that a given configuration contains no IADs. In this |
1501 | | * case the iad_array is still output, but will have 'length' field set to 0, and |
1502 | | * iad field set to NULL. |
1503 | | * \returns 0 on success |
1504 | | * \returns LIBUSB_ERROR_NOT_FOUND if the configuration does not exist |
1505 | | * \returns another LIBUSB_ERROR code on error |
1506 | | * \see libusb_get_active_interface_association_descriptors() |
1507 | | */ |
1508 | | int API_EXPORTED libusb_get_interface_association_descriptors(libusb_device *dev, |
1509 | | uint8_t config_index, struct libusb_interface_association_descriptor_array **iad_array) |
1510 | 0 | { |
1511 | 0 | union usbi_config_desc_buf _config; |
1512 | 0 | uint16_t config_len; |
1513 | 0 | uint8_t *buf; |
1514 | 0 | int r; |
1515 | |
|
1516 | 0 | if (!iad_array) |
1517 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1518 | | |
1519 | 0 | usbi_dbg(usbi_device_ctx(dev), "IADs for config index %u", config_index); |
1520 | 0 | if (config_index >= dev->device_descriptor.bNumConfigurations) |
1521 | 0 | return LIBUSB_ERROR_NOT_FOUND; |
1522 | | |
1523 | 0 | r = get_config_descriptor(dev, config_index, _config.buf, sizeof(_config.buf)); |
1524 | 0 | if (r < 0) |
1525 | 0 | return r; |
1526 | | |
1527 | 0 | config_len = libusb_le16_to_cpu(_config.desc.wTotalLength); |
1528 | 0 | buf = (uint8_t *)malloc(config_len); |
1529 | 0 | if (!buf) |
1530 | 0 | return LIBUSB_ERROR_NO_MEM; |
1531 | | |
1532 | 0 | r = get_config_descriptor(dev, config_index, buf, config_len); |
1533 | 0 | if (r >= 0) |
1534 | 0 | r = raw_desc_to_iad_array(usbi_device_ctx(dev), buf, r, iad_array); |
1535 | |
|
1536 | 0 | free(buf); |
1537 | 0 | return r; |
1538 | 0 | } |
1539 | | |
1540 | | /** \ingroup libusb_desc |
1541 | | * Get an array of interface association descriptors (IAD) for the currently |
1542 | | * active configuration. |
1543 | | * This is a non-blocking function which does not involve any requests being |
1544 | | * sent to the device. |
1545 | | * |
1546 | | * \param dev a device |
1547 | | * \param iad_array output location for the array of IADs. Only valid if 0 was |
1548 | | * returned. Must be freed with libusb_free_interface_association_descriptors() |
1549 | | * after use. It's possible that a given configuration contains no IADs. In this |
1550 | | * case the iad_array is still output, but will have 'length' field set to 0, and |
1551 | | * iad field set to NULL. |
1552 | | * \returns 0 on success |
1553 | | * \returns LIBUSB_ERROR_NOT_FOUND if the device is in unconfigured state |
1554 | | * \returns another LIBUSB_ERROR code on error |
1555 | | * \see libusb_get_interface_association_descriptors |
1556 | | */ |
1557 | | int API_EXPORTED libusb_get_active_interface_association_descriptors(libusb_device *dev, |
1558 | | struct libusb_interface_association_descriptor_array **iad_array) |
1559 | 0 | { |
1560 | 0 | union usbi_config_desc_buf _config; |
1561 | 0 | uint16_t config_len; |
1562 | 0 | uint8_t *buf; |
1563 | 0 | int r; |
1564 | |
|
1565 | 0 | if (!iad_array) |
1566 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1567 | | |
1568 | 0 | r = get_active_config_descriptor(dev, _config.buf, sizeof(_config.buf)); |
1569 | 0 | if (r < 0) |
1570 | 0 | return r; |
1571 | | |
1572 | 0 | config_len = libusb_le16_to_cpu(_config.desc.wTotalLength); |
1573 | 0 | buf = (uint8_t *)malloc(config_len); |
1574 | 0 | if (!buf) |
1575 | 0 | return LIBUSB_ERROR_NO_MEM; |
1576 | | |
1577 | 0 | r = get_active_config_descriptor(dev, buf, config_len); |
1578 | 0 | if (r >= 0) |
1579 | 0 | r = raw_desc_to_iad_array(usbi_device_ctx(dev), buf, r, iad_array); |
1580 | 0 | free(buf); |
1581 | 0 | return r; |
1582 | 0 | } |
1583 | | |
1584 | | /** \ingroup libusb_desc |
1585 | | * Free an array of interface association descriptors (IADs) obtained from |
1586 | | * libusb_get_interface_association_descriptors() or |
1587 | | * libusb_get_active_interface_association_descriptors(). |
1588 | | * It is safe to call this function with a NULL iad_array parameter, in which |
1589 | | * case the function simply returns. |
1590 | | * |
1591 | | * \param iad_array the IAD array to free |
1592 | | */ |
1593 | | void API_EXPORTED libusb_free_interface_association_descriptors( |
1594 | | struct libusb_interface_association_descriptor_array *iad_array) |
1595 | 0 | { |
1596 | 0 | if (!iad_array) |
1597 | 0 | return; |
1598 | | |
1599 | 0 | if (iad_array->iad) |
1600 | 0 | free((void*)iad_array->iad); |
1601 | 0 | free(iad_array); |
1602 | 0 | } |
1603 | | |
1604 | | /* |
1605 | | * \brief Copy a UTF-8 string with proper truncation if needed. |
1606 | | * |
1607 | | * \param tgt The target utf-8 string. If NULL, then tgt is ignored, |
1608 | | * tgt_size is forced to 0, and this function returns the |
1609 | | * required tgt_size for a subsequent call to this function. |
1610 | | * \param src The source utf-8 string. If NULL, then |
1611 | | * the source string is empty, the return length is 1, |
1612 | | * and, if tgt is not NULL, this function |
1613 | | * sets tgt[0] to the null terminator. |
1614 | | * \param tgt_size The size of target in bytes. |
1615 | | * \return the length of src in bytes, including the null terminator. |
1616 | | * |
1617 | | * utf8_copy(NULL, src, 0) is equivalent to strlen(src) + 1. |
1618 | | */ |
1619 | 0 | static int usbi_utf8_copy(char *tgt, char const *src, int tgt_size) { |
1620 | 0 | uint8_t* t = (uint8_t*)tgt; |
1621 | 0 | uint8_t const* s = (uint8_t const*)src; |
1622 | |
|
1623 | 0 | if (NULL == src) { |
1624 | 0 | if ((NULL != tgt) && (tgt_size > 0)) { |
1625 | 0 | tgt[0] = 0; |
1626 | 0 | } |
1627 | 0 | return 1; |
1628 | 0 | } |
1629 | | |
1630 | 0 | if ((NULL == tgt) || (tgt_size <= 0)) { |
1631 | 0 | return (int)(strlen(src) + 1); |
1632 | 0 | } |
1633 | | |
1634 | | // copy UTF-8 string and compute length |
1635 | 0 | int k = 0; |
1636 | 0 | for (k = 0; s[k]; ++k) { |
1637 | 0 | if (k < tgt_size) { |
1638 | 0 | t[k] = s[k]; |
1639 | 0 | } else { |
1640 | 0 | break; |
1641 | 0 | } |
1642 | 0 | } |
1643 | |
|
1644 | 0 | if (k >= tgt_size) { |
1645 | | // truncate respecting UTF-8 character boundaries |
1646 | 0 | int idx = tgt_size - 1; |
1647 | 0 | while (idx && (0x80 == (t[idx] & 0xC0))) { // utf-8 continuation byte |
1648 | 0 | --idx; |
1649 | 0 | } |
1650 | 0 | t[idx] = 0; |
1651 | 0 | return (int)(strlen(src) + 1); |
1652 | 0 | } else { |
1653 | 0 | t[k++] = 0; |
1654 | 0 | return k; |
1655 | 0 | } |
1656 | 0 | } |
1657 | | |
1658 | | /** \ingroup libusb_desc |
1659 | | * Retrieve a device string without needing to open the device. |
1660 | | * |
1661 | | * Since version v1.0.30 \ref LIBUSB_API_VERSION >= 0x0100010C |
1662 | | * |
1663 | | * \param dev the target device |
1664 | | * \param string_type the string type to retrieve |
1665 | | * \param data the data buffer for the UTF-8 encoded string. |
1666 | | * \param length the size of the data buffer in bytes. |
1667 | | * USB string descriptors cannot be longer than |
1668 | | * LIBUSB_DEVICE_STRING_BYTES_MAX. |
1669 | | * \returns a negative error code or |
1670 | | * the actual string length in bytes including the null terminator. |
1671 | | * \see libusb_get_string_descriptor() |
1672 | | * \see libusb_get_string_descriptor_ascii() |
1673 | | * |
1674 | | * This function works when the device is still closed since it relies |
1675 | | * on the operating system to provide the string. The operating system |
1676 | | * normally reads and caches the common string descriptors during |
1677 | | * USB enumeration. |
1678 | | * |
1679 | | * Since the USB string descriptor could be processed by the OS, |
1680 | | * this function returns a UTF-8 encoded string. |
1681 | | * |
1682 | | * The string will be returned untranslated or in the default OS language |
1683 | | * when supported by the OS and USB device. |
1684 | | * |
1685 | | * One way to call this function is using a buffer on the stack: |
1686 | | * |
1687 | | * char buffer[LIBUSB_DEVICE_STRING_BYTES_MAX]; |
1688 | | * int ret = libusb_get_device_string(dev, LIBUSB_DEVICE_STRING_SERIAL_NUMBER, buffer, sizeof(buffer)); |
1689 | | * if (ret < 0) { |
1690 | | * // handle error |
1691 | | * } |
1692 | | * |
1693 | | * This function is commonly used to get the serial number to allow |
1694 | | * for device selection before opening the selected device. |
1695 | | */ |
1696 | | int API_EXPORTED libusb_get_device_string(libusb_device *dev, |
1697 | 0 | enum libusb_device_string_type string_type, char *data, int length) { |
1698 | 0 | char * s; |
1699 | 0 | if (NULL == dev) { |
1700 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1701 | 0 | } |
1702 | 0 | if ((string_type < 0) || (string_type >= LIBUSB_DEVICE_STRING_COUNT)) { |
1703 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1704 | 0 | } |
1705 | 0 | if (length <= 0) { |
1706 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1707 | 0 | } |
1708 | 0 | if (NULL == data) { |
1709 | 0 | length = 0; |
1710 | 0 | data = NULL; |
1711 | 0 | } else if (length > 0) { |
1712 | 0 | *data = 0; // return an empty string on errors when possible |
1713 | 0 | } |
1714 | |
|
1715 | 0 | if (NULL == dev->device_strings_utf8[string_type]) { |
1716 | 0 | if (usbi_backend.get_device_string) { |
1717 | 0 | s = (char *)malloc(LIBUSB_DEVICE_STRING_BYTES_MAX); |
1718 | 0 | int rv = usbi_backend.get_device_string(dev, string_type, s, LIBUSB_DEVICE_STRING_BYTES_MAX); |
1719 | 0 | if (rv < 0) { |
1720 | 0 | free(s); |
1721 | 0 | return rv; |
1722 | 0 | } else { |
1723 | 0 | dev->device_strings_utf8[string_type] = s; |
1724 | 0 | } |
1725 | 0 | } else { |
1726 | 0 | return LIBUSB_ERROR_NOT_SUPPORTED; |
1727 | 0 | } |
1728 | 0 | } |
1729 | | |
1730 | 0 | s = dev->device_strings_utf8[string_type]; |
1731 | 0 | if (NULL == s) { |
1732 | 0 | return LIBUSB_ERROR_NOT_SUPPORTED; |
1733 | 0 | } |
1734 | | |
1735 | 0 | return usbi_utf8_copy(data, s, length); |
1736 | 0 | } |
1737 | | |
1738 | | /* Get the configuration descriptor for config_value, or the active |
1739 | | * configuration when config_value is 0. */ |
1740 | | static int get_config_descriptor_for_value(libusb_device *dev, |
1741 | | uint8_t config_value, struct libusb_config_descriptor **config) |
1742 | 0 | { |
1743 | 0 | if (config_value == 0) |
1744 | 0 | return libusb_get_active_config_descriptor(dev, config); |
1745 | 0 | return libusb_get_config_descriptor_by_value(dev, config_value, config); |
1746 | 0 | } |
1747 | | |
1748 | | /* Resolve iConfiguration for config_value (0 = active config); *index_out is |
1749 | | * set to 0 when the configuration has no string descriptor. */ |
1750 | | int usbi_get_config_string_index(libusb_device *dev, |
1751 | | uint8_t config_value, uint8_t *index_out) |
1752 | 0 | { |
1753 | 0 | struct libusb_config_descriptor *config = NULL; |
1754 | 0 | int r; |
1755 | |
|
1756 | 0 | r = get_config_descriptor_for_value(dev, config_value, &config); |
1757 | 0 | if (r < 0) |
1758 | 0 | return r; |
1759 | | |
1760 | 0 | *index_out = config->iConfiguration; |
1761 | 0 | libusb_free_config_descriptor(config); |
1762 | 0 | return LIBUSB_SUCCESS; |
1763 | 0 | } |
1764 | | |
1765 | | /* Resolve iInterface for the given interface/alt setting (config_value 0 = |
1766 | | * active config); *index_out is 0 when it has no string descriptor. Returns |
1767 | | * LIBUSB_ERROR_NOT_FOUND if the interface/alt setting does not exist. */ |
1768 | | int usbi_get_interface_string_index(libusb_device *dev, |
1769 | | uint8_t config_value, uint8_t interface_number, uint8_t alt_setting, |
1770 | | uint8_t *index_out) |
1771 | 0 | { |
1772 | 0 | struct libusb_config_descriptor *config = NULL; |
1773 | 0 | int r, i, j; |
1774 | |
|
1775 | 0 | r = get_config_descriptor_for_value(dev, config_value, &config); |
1776 | 0 | if (r < 0) |
1777 | 0 | return r; |
1778 | | |
1779 | 0 | r = LIBUSB_ERROR_NOT_FOUND; |
1780 | 0 | for (i = 0; i < config->bNumInterfaces; i++) { |
1781 | 0 | const struct libusb_interface *intf = &config->interface[i]; |
1782 | 0 | for (j = 0; j < intf->num_altsetting; j++) { |
1783 | 0 | const struct libusb_interface_descriptor *as = &intf->altsetting[j]; |
1784 | 0 | if (as->bInterfaceNumber == interface_number && |
1785 | 0 | as->bAlternateSetting == alt_setting) { |
1786 | 0 | *index_out = as->iInterface; |
1787 | 0 | r = LIBUSB_SUCCESS; |
1788 | 0 | break; |
1789 | 0 | } |
1790 | 0 | } |
1791 | 0 | if (r == LIBUSB_SUCCESS) |
1792 | 0 | break; |
1793 | 0 | } |
1794 | |
|
1795 | 0 | libusb_free_config_descriptor(config); |
1796 | 0 | return r; |
1797 | 0 | } |
1798 | | |
1799 | | /** \ingroup libusb_desc |
1800 | | * Retrieve the string descriptor describing a configuration (iConfiguration) |
1801 | | * without needing to open the device. |
1802 | | * |
1803 | | * Since version 1.0.31, \ref LIBUSB_API_VERSION >= 0x0100010D |
1804 | | * |
1805 | | * \param dev the target device |
1806 | | * \param config_value the bConfigurationValue of the configuration, or 0 to |
1807 | | * select the device's currently active configuration. |
1808 | | * \param data the data buffer for the UTF-8 encoded string, or NULL to only |
1809 | | * determine the required buffer size (length must still be non-zero). |
1810 | | * \param length the size of the data buffer in bytes. |
1811 | | * USB string descriptors cannot be longer than |
1812 | | * LIBUSB_DEVICE_STRING_BYTES_MAX. |
1813 | | * \returns a negative error code or |
1814 | | * the actual string length in bytes including the null terminator. |
1815 | | * \see libusb_get_device_string() |
1816 | | * \see libusb_get_interface_string() |
1817 | | * |
1818 | | * Like \ref libusb_get_device_string() this function works while the device is |
1819 | | * still closed, relying on the operating system's cached descriptors. Unlike |
1820 | | * \ref libusb_get_device_string() the result is not cached by libusb, so each |
1821 | | * call may perform I/O; cache the string if it is needed repeatedly. |
1822 | | * |
1823 | | * Platform notes: |
1824 | | * - Windows and macOS fetch the string by its descriptor index and can serve |
1825 | | * any configuration, active or not. |
1826 | | * - Linux reads the string from sysfs, which only exposes the string of the |
1827 | | * active configuration. A non-active configuration can only be served |
1828 | | * when it shares its string descriptor (iConfiguration index) with the |
1829 | | * active one; otherwise \ref LIBUSB_ERROR_NOT_SUPPORTED is returned even |
1830 | | * though the requested configuration is valid. In that case the string |
1831 | | * can still be read by opening the device and calling |
1832 | | * \ref libusb_get_string_descriptor with the iConfiguration index. |
1833 | | * - Backends that do not implement this function always return |
1834 | | * \ref LIBUSB_ERROR_NOT_SUPPORTED. |
1835 | | */ |
1836 | | int API_EXPORTED libusb_get_config_string(libusb_device *dev, |
1837 | | uint8_t config_value, char *data, int length) |
1838 | 0 | { |
1839 | 0 | char buf[LIBUSB_DEVICE_STRING_BYTES_MAX]; |
1840 | 0 | int r; |
1841 | |
|
1842 | 0 | if (NULL == dev) |
1843 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1844 | 0 | if (length <= 0) |
1845 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1846 | | |
1847 | | /* as in libusb_get_device_string(), data may be NULL to query the |
1848 | | * required buffer size */ |
1849 | 0 | if (NULL != data) |
1850 | 0 | *data = 0; /* return an empty string on errors when possible */ |
1851 | |
|
1852 | 0 | if (NULL == usbi_backend.get_config_string) |
1853 | 0 | return LIBUSB_ERROR_NOT_SUPPORTED; |
1854 | | |
1855 | | /* Fetch into a full-size buffer, then copy out via usbi_utf8_copy() for |
1856 | | * UTF-8-safe truncation, as libusb_get_device_string() does. */ |
1857 | 0 | r = usbi_backend.get_config_string(dev, config_value, buf, sizeof(buf)); |
1858 | 0 | if (r < 0) |
1859 | 0 | return r; |
1860 | | |
1861 | 0 | return usbi_utf8_copy(data, buf, length); |
1862 | 0 | } |
1863 | | |
1864 | | /** \ingroup libusb_desc |
1865 | | * Retrieve the string descriptor describing an interface (iInterface) |
1866 | | * without needing to open the device. |
1867 | | * |
1868 | | * Since version 1.0.31, \ref LIBUSB_API_VERSION >= 0x0100010D |
1869 | | * |
1870 | | * \param dev the target device |
1871 | | * \param config_value the bConfigurationValue of the configuration the |
1872 | | * interface belongs to, or 0 to select the device's currently active |
1873 | | * configuration. |
1874 | | * \param interface_number the bInterfaceNumber of the interface |
1875 | | * \param alt_setting the bAlternateSetting of the interface |
1876 | | * \param data the data buffer for the UTF-8 encoded string, or NULL to only |
1877 | | * determine the required buffer size (length must still be non-zero). |
1878 | | * \param length the size of the data buffer in bytes. |
1879 | | * USB string descriptors cannot be longer than |
1880 | | * LIBUSB_DEVICE_STRING_BYTES_MAX. |
1881 | | * \returns a negative error code or |
1882 | | * the actual string length in bytes including the null terminator. |
1883 | | * \see libusb_get_device_string() |
1884 | | * \see libusb_get_config_string() |
1885 | | * |
1886 | | * Like \ref libusb_get_device_string() this function works while the device is |
1887 | | * still closed, relying on the operating system's cached descriptors. Unlike |
1888 | | * \ref libusb_get_device_string() the result is not cached by libusb, so each |
1889 | | * call may perform I/O; cache the string if it is needed repeatedly. |
1890 | | * |
1891 | | * A return of \ref LIBUSB_ERROR_NOT_FOUND means the interface has no string |
1892 | | * descriptor (its iInterface is 0) or the requested interface/alternate |
1893 | | * setting does not exist. |
1894 | | * |
1895 | | * Platform notes: |
1896 | | * - Windows and macOS fetch the string by its descriptor index and can serve |
1897 | | * any configuration and alternate setting, current or not. |
1898 | | * - Linux reads the string from sysfs, which only exposes the string of the |
1899 | | * currently selected alternate setting in the active configuration. A |
1900 | | * valid but non-current alternate setting (or non-active configuration) |
1901 | | * can only be served when it shares its string descriptor (iInterface |
1902 | | * index) with the current one; otherwise \ref LIBUSB_ERROR_NOT_SUPPORTED |
1903 | | * is returned even though the requested combination is valid. In that |
1904 | | * case the string can still be read by opening the device and calling |
1905 | | * \ref libusb_get_string_descriptor with the iInterface index. |
1906 | | * - Backends that do not implement this function always return |
1907 | | * \ref LIBUSB_ERROR_NOT_SUPPORTED. |
1908 | | */ |
1909 | | int API_EXPORTED libusb_get_interface_string(libusb_device *dev, |
1910 | | uint8_t config_value, uint8_t interface_number, uint8_t alt_setting, |
1911 | | char *data, int length) |
1912 | 0 | { |
1913 | 0 | char buf[LIBUSB_DEVICE_STRING_BYTES_MAX]; |
1914 | 0 | int r; |
1915 | |
|
1916 | 0 | if (NULL == dev) |
1917 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1918 | 0 | if (length <= 0) |
1919 | 0 | return LIBUSB_ERROR_INVALID_PARAM; |
1920 | | |
1921 | | /* as in libusb_get_device_string(), data may be NULL to query the |
1922 | | * required buffer size */ |
1923 | 0 | if (NULL != data) |
1924 | 0 | *data = 0; /* return an empty string on errors when possible */ |
1925 | |
|
1926 | 0 | if (NULL == usbi_backend.get_interface_string) |
1927 | 0 | return LIBUSB_ERROR_NOT_SUPPORTED; |
1928 | | |
1929 | | /* Fetch into a full-size buffer, then copy out via usbi_utf8_copy() for |
1930 | | * UTF-8-safe truncation, as libusb_get_device_string() does. */ |
1931 | 0 | r = usbi_backend.get_interface_string(dev, config_value, |
1932 | 0 | interface_number, alt_setting, buf, sizeof(buf)); |
1933 | 0 | if (r < 0) |
1934 | 0 | return r; |
1935 | | |
1936 | 0 | return usbi_utf8_copy(data, buf, length); |
1937 | 0 | } |