usb 2.16.0 → 2.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/README.md +14 -0
- package/binding.gyp +2 -9
- package/dist/usb/bindings.d.ts +27 -2
- package/dist/usb/bindings.js.map +1 -1
- package/dist/usb/endpoint.js +1 -1
- package/dist/usb/endpoint.js.map +1 -1
- package/dist/usb/index.d.ts +0 -29
- package/dist/usb/index.js +4 -18
- package/dist/usb/index.js.map +1 -1
- package/dist/webusb/index.d.ts +1 -1
- package/dist/webusb/index.js +1 -1
- package/dist/webusb/index.js.map +1 -1
- package/dist/webusb/webusb-device.d.ts +4 -4
- package/dist/webusb/webusb-device.js +5 -2
- package/dist/webusb/webusb-device.js.map +1 -1
- package/libusb/.clang-tidy +36 -0
- package/libusb/.private/ci-build.sh +5 -1
- package/libusb/AUTHORS +21 -0
- package/libusb/ChangeLog +29 -2
- package/libusb/KEYS +123 -0
- package/libusb/README +8 -9
- package/libusb/Xcode/common.xcconfig +20 -0
- package/libusb/Xcode/libusb.xcodeproj/project.pbxproj +16 -12
- package/libusb/android/examples/unrooted_android.c +1 -0
- package/libusb/configure.ac +12 -2
- package/libusb/examples/dpfp.c +1 -1
- package/libusb/examples/ezusb.c +6 -1
- package/libusb/examples/fxload.c +7 -5
- package/libusb/examples/hotplugtest.c +19 -11
- package/libusb/examples/listdevs.c +41 -3
- package/libusb/examples/testlibusb.c +1 -0
- package/libusb/examples/xusb.c +142 -77
- package/libusb/libusb/Makefile.am +4 -0
- package/libusb/libusb/core.c +183 -24
- package/libusb/libusb/descriptor.c +404 -96
- package/libusb/libusb/hotplug.c +27 -8
- package/libusb/libusb/io.c +10 -5
- package/libusb/libusb/libusb-1.0.def +14 -0
- package/libusb/libusb/libusb.h +179 -19
- package/libusb/libusb/libusbi.h +101 -25
- package/libusb/libusb/os/darwin_usb.c +216 -90
- package/libusb/libusb/os/darwin_usb.h +10 -8
- package/libusb/libusb/os/emscripten_webusb.cpp +38 -12
- package/libusb/libusb/os/events_posix.c +4 -4
- package/libusb/libusb/os/haiku_usb_raw.cpp +4 -0
- package/libusb/libusb/os/linux_usbfs.c +92 -33
- package/libusb/libusb/os/linux_usbfs.h +13 -3
- package/libusb/libusb/os/netbsd_usb.c +6 -4
- package/libusb/libusb/os/openbsd_usb.c +4 -2
- package/libusb/libusb/os/sunos_usb.c +7 -5
- package/libusb/libusb/os/threads_posix.c +20 -19
- package/libusb/libusb/os/threads_posix.h +9 -3
- package/libusb/libusb/os/threads_windows.h +4 -3
- package/libusb/libusb/os/windows_common.c +86 -1
- package/libusb/libusb/os/windows_common.h +20 -1
- package/libusb/libusb/os/windows_hotplug.c +321 -0
- package/libusb/libusb/os/windows_hotplug.h +28 -0
- package/libusb/libusb/os/windows_usbdk.c +16 -8
- package/libusb/libusb/os/windows_winusb.c +788 -56
- package/libusb/libusb/os/windows_winusb.h +11 -6
- package/libusb/libusb/sync.c +8 -5
- package/libusb/libusb/version.h +1 -1
- package/libusb/libusb/version_nano.h +1 -1
- package/libusb/msvc/Base.props +1 -1
- package/libusb/msvc/Configuration.Base.props +2 -1
- package/libusb/msvc/Configuration.DynamicLibrary.props +12 -0
- package/libusb/msvc/ProjectConfigurations.Base.props +69 -16
- package/libusb/msvc/build_all.ps1 +2 -2
- package/libusb/msvc/config.h +4 -0
- package/libusb/msvc/getopt/bits/getopt_core.h +96 -0
- package/libusb/msvc/getopt/bits/getopt_ext.h +77 -0
- package/libusb/msvc/getopt/features.h +21 -0
- package/libusb/msvc/getopt/getopt.c +456 -705
- package/libusb/msvc/getopt/getopt.h +16 -158
- package/libusb/msvc/getopt/getopt1.c +40 -69
- package/libusb/msvc/getopt/getopt_int.h +118 -0
- package/libusb/msvc/getopt/gettext.h +7 -0
- package/libusb/msvc/getopt/unistd.h +5 -0
- package/libusb/msvc/getopt.vcxproj +11 -4
- package/libusb/msvc/libusb.sln +515 -268
- package/libusb/msvc/libusb_dll.vcxproj +2 -0
- package/libusb/msvc/libusb_static.vcxproj +2 -0
- package/libusb/msvc/xusb.vcxproj +1 -1
- package/libusb/tests/Makefile.am +10 -1
- package/libusb/tests/fuzz/corpus/bos/min.bos +0 -0
- package/libusb/tests/fuzz/corpus/descriptor_parsers/min_valid_config.bin +0 -0
- package/libusb/tests/fuzz/corpus/descriptor_parsers/regression_bug_a_endpoint_null.bin +0 -0
- package/libusb/tests/fuzz/corpus/descriptor_parsers/regression_bug_b_iad_oob.bin +0 -0
- package/libusb/tests/fuzz/fuzz_bos_descriptor.c +49 -0
- package/libusb/tests/fuzz/fuzz_descriptor_parsers.c +83 -0
- package/libusb/tests/macos.c +2 -2
- package/libusb/tests/stress_mt.c +6 -3
- package/libusb/tests/webusb-test-shim/index.js +6 -5
- package/libusb.gypi +5 -0
- package/package.json +3 -3
- package/prebuilds/android-arm/node.napi.armv7.node +0 -0
- package/prebuilds/android-arm64/node.napi.armv8.node +0 -0
- package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
- package/prebuilds/linux-arm/node.napi.armv6.node +0 -0
- package/prebuilds/linux-arm/node.napi.armv7.node +0 -0
- package/prebuilds/linux-arm64/node.napi.armv8.node +0 -0
- package/prebuilds/linux-ia32/node.napi.node +0 -0
- package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
- package/prebuilds/linux-x64/node.napi.musl.node +0 -0
- package/prebuilds/win32-arm64/node.napi.node +0 -0
- package/prebuilds/win32-ia32/node.napi.node +0 -0
- package/prebuilds/win32-x64/node.napi.node +0 -0
- package/src/{hotplug/libusb.cc → hotplug.cc} +2 -3
- package/src/{hotplug/hotplug.h → hotplug.h} +2 -6
- package/src/node_usb.cc +3 -3
- package/test/usb.coffee +4 -4
- package/test/webusb.coffee +22 -12
- package/src/hotplug/windows.cc +0 -168
|
@@ -30,49 +30,18 @@
|
|
|
30
30
|
* for detected devices
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
(((uint16_t)((p)[1]) << 8) | \
|
|
35
|
-
((uint16_t)((p)[0]))))
|
|
36
|
-
|
|
37
|
-
#define READ_LE32(p) ((uint32_t) \
|
|
38
|
-
(((uint32_t)((p)[3]) << 24) | \
|
|
39
|
-
((uint32_t)((p)[2]) << 16) | \
|
|
40
|
-
((uint32_t)((p)[1]) << 8) | \
|
|
41
|
-
((uint32_t)((p)[0]))))
|
|
42
|
-
|
|
43
|
-
static void parse_descriptor(const void *source, const char *descriptor, void *dest)
|
|
33
|
+
static inline uint16_t ReadLittleEndian16(const uint8_t p[2])
|
|
44
34
|
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
while (*descriptor) {
|
|
50
|
-
field_type = *descriptor++;
|
|
51
|
-
switch (field_type) {
|
|
52
|
-
case 'b': /* 8-bit byte */
|
|
53
|
-
*dp++ = *sp++;
|
|
54
|
-
break;
|
|
55
|
-
case 'w': /* 16-bit word, convert from little endian to CPU */
|
|
56
|
-
dp += ((uintptr_t)dp & 1); /* Align to 16-bit word boundary */
|
|
57
|
-
|
|
58
|
-
*((uint16_t *)dp) = READ_LE16(sp);
|
|
59
|
-
sp += 2;
|
|
60
|
-
dp += 2;
|
|
61
|
-
break;
|
|
62
|
-
case 'd': /* 32-bit word, convert from little endian to CPU */
|
|
63
|
-
dp += 4 - ((uintptr_t)dp & 3); /* Align to 32-bit word boundary */
|
|
35
|
+
return (uint16_t)((uint16_t)p[1] << 8 |
|
|
36
|
+
(uint16_t)p[0]);
|
|
37
|
+
}
|
|
64
38
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
sp += 16;
|
|
72
|
-
dp += 16;
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
39
|
+
static inline uint32_t ReadLittleEndian32(const uint8_t p[4])
|
|
40
|
+
{
|
|
41
|
+
return ((uint32_t)p[3] << 24 |
|
|
42
|
+
(uint32_t)p[2] << 16 |
|
|
43
|
+
(uint32_t)p[1] << 8 |
|
|
44
|
+
(uint32_t)p[0]);
|
|
76
45
|
}
|
|
77
46
|
|
|
78
47
|
static void clear_endpoint(struct libusb_endpoint_descriptor *endpoint)
|
|
@@ -87,7 +56,6 @@ static int parse_endpoint(struct libusb_context *ctx,
|
|
|
87
56
|
const uint8_t *begin;
|
|
88
57
|
void *extra;
|
|
89
58
|
int parsed = 0;
|
|
90
|
-
int len;
|
|
91
59
|
|
|
92
60
|
if (size < DESC_HEADER_LENGTH) {
|
|
93
61
|
usbi_err(ctx, "short endpoint descriptor read %d/%d",
|
|
@@ -109,10 +77,16 @@ static int parse_endpoint(struct libusb_context *ctx,
|
|
|
109
77
|
return parsed;
|
|
110
78
|
}
|
|
111
79
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
80
|
+
endpoint->bLength = buffer[0];
|
|
81
|
+
endpoint->bDescriptorType = buffer[1];
|
|
82
|
+
endpoint->bEndpointAddress = buffer[2];
|
|
83
|
+
endpoint->bmAttributes = buffer[3];
|
|
84
|
+
endpoint->wMaxPacketSize = ReadLittleEndian16(&buffer[4]);
|
|
85
|
+
endpoint->bInterval = buffer[6];
|
|
86
|
+
if (header->bLength >= LIBUSB_DT_ENDPOINT_AUDIO_SIZE) {
|
|
87
|
+
endpoint->bRefresh = buffer[7];
|
|
88
|
+
endpoint->bSynchAddress = buffer[8];
|
|
89
|
+
}
|
|
116
90
|
|
|
117
91
|
buffer += header->bLength;
|
|
118
92
|
size -= header->bLength;
|
|
@@ -148,7 +122,7 @@ static int parse_endpoint(struct libusb_context *ctx,
|
|
|
148
122
|
|
|
149
123
|
/* Copy any unknown descriptors into a storage area for drivers */
|
|
150
124
|
/* to later parse */
|
|
151
|
-
len =
|
|
125
|
+
ptrdiff_t len = buffer - begin;
|
|
152
126
|
if (len <= 0)
|
|
153
127
|
return parsed;
|
|
154
128
|
|
|
@@ -156,9 +130,9 @@ static int parse_endpoint(struct libusb_context *ctx,
|
|
|
156
130
|
if (!extra)
|
|
157
131
|
return LIBUSB_ERROR_NO_MEM;
|
|
158
132
|
|
|
159
|
-
memcpy(extra, begin, len);
|
|
133
|
+
memcpy(extra, begin, (size_t)len);
|
|
160
134
|
endpoint->extra = extra;
|
|
161
|
-
endpoint->extra_length = len;
|
|
135
|
+
endpoint->extra_length = (int)len;
|
|
162
136
|
|
|
163
137
|
return parsed;
|
|
164
138
|
}
|
|
@@ -174,6 +148,8 @@ static void clear_interface(struct libusb_interface *usb_interface)
|
|
|
174
148
|
usb_interface->altsetting + i;
|
|
175
149
|
|
|
176
150
|
free((void *)ifp->extra);
|
|
151
|
+
ifp->extra = NULL;
|
|
152
|
+
ifp->extra_length = 0;
|
|
177
153
|
if (ifp->endpoint) {
|
|
178
154
|
uint8_t j;
|
|
179
155
|
|
|
@@ -182,16 +158,18 @@ static void clear_interface(struct libusb_interface *usb_interface)
|
|
|
182
158
|
ifp->endpoint + j);
|
|
183
159
|
}
|
|
184
160
|
free((void *)ifp->endpoint);
|
|
161
|
+
ifp->endpoint = NULL;
|
|
162
|
+
ifp->bNumEndpoints = 0;
|
|
185
163
|
}
|
|
186
164
|
}
|
|
187
165
|
free((void *)usb_interface->altsetting);
|
|
188
166
|
usb_interface->altsetting = NULL;
|
|
167
|
+
usb_interface->num_altsetting = 0;
|
|
189
168
|
}
|
|
190
169
|
|
|
191
170
|
static int parse_interface(libusb_context *ctx,
|
|
192
171
|
struct libusb_interface *usb_interface, const uint8_t *buffer, int size)
|
|
193
172
|
{
|
|
194
|
-
int len;
|
|
195
173
|
int r;
|
|
196
174
|
int parsed = 0;
|
|
197
175
|
int interface_number = -1;
|
|
@@ -212,7 +190,15 @@ static int parse_interface(libusb_context *ctx,
|
|
|
212
190
|
usb_interface->altsetting = altsetting;
|
|
213
191
|
|
|
214
192
|
ifp = altsetting + usb_interface->num_altsetting;
|
|
215
|
-
|
|
193
|
+
ifp->bLength = buffer[0];
|
|
194
|
+
ifp->bDescriptorType = buffer[1];
|
|
195
|
+
ifp->bInterfaceNumber = buffer[2];
|
|
196
|
+
ifp->bAlternateSetting = buffer[3];
|
|
197
|
+
ifp->bNumEndpoints = buffer[4];
|
|
198
|
+
ifp->bInterfaceClass = buffer[5];
|
|
199
|
+
ifp->bInterfaceSubClass = buffer[6];
|
|
200
|
+
ifp->bInterfaceProtocol = buffer[7];
|
|
201
|
+
ifp->iInterface = buffer[8];
|
|
216
202
|
if (ifp->bDescriptorType != LIBUSB_DT_INTERFACE) {
|
|
217
203
|
usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)",
|
|
218
204
|
ifp->bDescriptorType, LIBUSB_DT_INTERFACE);
|
|
@@ -260,6 +246,10 @@ static int parse_interface(libusb_context *ctx,
|
|
|
260
246
|
usbi_warn(ctx,
|
|
261
247
|
"short extra intf desc read %d/%u",
|
|
262
248
|
size, header->bLength);
|
|
249
|
+
/* Keep the invariant: bNumEndpoints > 0 implies
|
|
250
|
+
* endpoint != NULL. The endpoint array isn't
|
|
251
|
+
* allocated yet on this early return. */
|
|
252
|
+
ifp->bNumEndpoints = 0;
|
|
263
253
|
return parsed;
|
|
264
254
|
}
|
|
265
255
|
|
|
@@ -277,7 +267,7 @@ static int parse_interface(libusb_context *ctx,
|
|
|
277
267
|
|
|
278
268
|
/* Copy any unknown descriptors into a storage area for */
|
|
279
269
|
/* drivers to later parse */
|
|
280
|
-
len =
|
|
270
|
+
ptrdiff_t len = buffer - begin;
|
|
281
271
|
if (len > 0) {
|
|
282
272
|
void *extra = malloc((size_t)len);
|
|
283
273
|
|
|
@@ -286,9 +276,9 @@ static int parse_interface(libusb_context *ctx,
|
|
|
286
276
|
goto err;
|
|
287
277
|
}
|
|
288
278
|
|
|
289
|
-
memcpy(extra, begin, len);
|
|
279
|
+
memcpy(extra, begin, (size_t)len);
|
|
290
280
|
ifp->extra = extra;
|
|
291
|
-
ifp->extra_length = len;
|
|
281
|
+
ifp->extra_length = (int)len;
|
|
292
282
|
}
|
|
293
283
|
|
|
294
284
|
if (ifp->bNumEndpoints > 0) {
|
|
@@ -341,7 +331,11 @@ static void clear_configuration(struct libusb_config_descriptor *config)
|
|
|
341
331
|
config->interface + i);
|
|
342
332
|
}
|
|
343
333
|
free((void *)config->interface);
|
|
334
|
+
config->interface = NULL;
|
|
335
|
+
config->bNumInterfaces = 0;
|
|
344
336
|
free((void *)config->extra);
|
|
337
|
+
config->extra = NULL;
|
|
338
|
+
config->extra_length = 0;
|
|
345
339
|
}
|
|
346
340
|
|
|
347
341
|
static int parse_configuration(struct libusb_context *ctx,
|
|
@@ -358,7 +352,14 @@ static int parse_configuration(struct libusb_context *ctx,
|
|
|
358
352
|
return LIBUSB_ERROR_IO;
|
|
359
353
|
}
|
|
360
354
|
|
|
361
|
-
|
|
355
|
+
config->bLength = buffer[0];
|
|
356
|
+
config->bDescriptorType = buffer[1];
|
|
357
|
+
config->wTotalLength = ReadLittleEndian16(&buffer[2]);
|
|
358
|
+
config->bNumInterfaces = buffer[4];
|
|
359
|
+
config->bConfigurationValue = buffer[5];
|
|
360
|
+
config->iConfiguration = buffer[6];
|
|
361
|
+
config->bmAttributes = buffer[7];
|
|
362
|
+
config->MaxPower = buffer[8];
|
|
362
363
|
if (config->bDescriptorType != LIBUSB_DT_CONFIG) {
|
|
363
364
|
usbi_err(ctx, "unexpected descriptor 0x%x (expected 0x%x)",
|
|
364
365
|
config->bDescriptorType, LIBUSB_DT_CONFIG);
|
|
@@ -385,7 +386,6 @@ static int parse_configuration(struct libusb_context *ctx,
|
|
|
385
386
|
size -= config->bLength;
|
|
386
387
|
|
|
387
388
|
for (i = 0; i < config->bNumInterfaces; i++) {
|
|
388
|
-
int len;
|
|
389
389
|
const uint8_t *begin;
|
|
390
390
|
|
|
391
391
|
/* Skip over the rest of the Class Specific or Vendor */
|
|
@@ -421,19 +421,19 @@ static int parse_configuration(struct libusb_context *ctx,
|
|
|
421
421
|
|
|
422
422
|
/* Copy any unknown descriptors into a storage area for */
|
|
423
423
|
/* drivers to later parse */
|
|
424
|
-
len =
|
|
424
|
+
ptrdiff_t len = buffer - begin;
|
|
425
425
|
if (len > 0) {
|
|
426
426
|
uint8_t *extra = realloc((void *)config->extra,
|
|
427
|
-
(size_t)(config->extra_length + len)
|
|
427
|
+
(size_t)(config->extra_length) + (size_t)len);
|
|
428
428
|
|
|
429
429
|
if (!extra) {
|
|
430
430
|
r = LIBUSB_ERROR_NO_MEM;
|
|
431
431
|
goto err;
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
-
memcpy(extra + config->extra_length, begin, len);
|
|
434
|
+
memcpy(extra + config->extra_length, begin, (size_t)len);
|
|
435
435
|
config->extra = extra;
|
|
436
|
-
config->extra_length += len;
|
|
436
|
+
config->extra_length += (int)len;
|
|
437
437
|
}
|
|
438
438
|
|
|
439
439
|
r = parse_interface(ctx, usb_interface + i, buffer, size);
|
|
@@ -707,14 +707,14 @@ int API_EXPORTED libusb_get_ss_endpoint_companion_descriptor(
|
|
|
707
707
|
const struct libusb_endpoint_descriptor *endpoint,
|
|
708
708
|
struct libusb_ss_endpoint_companion_descriptor **ep_comp)
|
|
709
709
|
{
|
|
710
|
-
struct usbi_descriptor_header *header;
|
|
710
|
+
const struct usbi_descriptor_header *header;
|
|
711
711
|
const uint8_t *buffer = endpoint->extra;
|
|
712
712
|
int size = endpoint->extra_length;
|
|
713
713
|
|
|
714
714
|
*ep_comp = NULL;
|
|
715
715
|
|
|
716
716
|
while (size >= DESC_HEADER_LENGTH) {
|
|
717
|
-
header = (struct usbi_descriptor_header *)buffer;
|
|
717
|
+
header = (const struct usbi_descriptor_header *)buffer;
|
|
718
718
|
if (header->bDescriptorType != LIBUSB_DT_SS_ENDPOINT_COMPANION) {
|
|
719
719
|
if (header->bLength < DESC_HEADER_LENGTH) {
|
|
720
720
|
usbi_err(ctx, "invalid descriptor length %u",
|
|
@@ -737,7 +737,11 @@ int API_EXPORTED libusb_get_ss_endpoint_companion_descriptor(
|
|
|
737
737
|
*ep_comp = malloc(sizeof(**ep_comp));
|
|
738
738
|
if (!*ep_comp)
|
|
739
739
|
return LIBUSB_ERROR_NO_MEM;
|
|
740
|
-
|
|
740
|
+
(*ep_comp)->bLength = buffer[0];
|
|
741
|
+
(*ep_comp)->bDescriptorType = buffer[1];
|
|
742
|
+
(*ep_comp)->bMaxBurst = buffer[2];
|
|
743
|
+
(*ep_comp)->bmAttributes = buffer[3];
|
|
744
|
+
(*ep_comp)->wBytesPerInterval = ReadLittleEndian16(&buffer[4]);
|
|
741
745
|
return LIBUSB_SUCCESS;
|
|
742
746
|
}
|
|
743
747
|
return LIBUSB_ERROR_NOT_FOUND;
|
|
@@ -786,11 +790,14 @@ static int parse_bos(struct libusb_context *ctx,
|
|
|
786
790
|
return LIBUSB_ERROR_IO;
|
|
787
791
|
}
|
|
788
792
|
|
|
789
|
-
_bos = calloc(1, sizeof(*_bos) + bos_desc->bNumDeviceCaps * sizeof(void *));
|
|
793
|
+
_bos = calloc(1, sizeof(*_bos) + (bos_desc->bNumDeviceCaps * sizeof(void *)));
|
|
790
794
|
if (!_bos)
|
|
791
795
|
return LIBUSB_ERROR_NO_MEM;
|
|
792
796
|
|
|
793
|
-
|
|
797
|
+
_bos->bLength = buffer[0];
|
|
798
|
+
_bos->bDescriptorType = buffer[1];
|
|
799
|
+
_bos->wTotalLength = ReadLittleEndian16(&buffer[2]);
|
|
800
|
+
_bos->bNumDeviceCaps = buffer[4];
|
|
794
801
|
buffer += _bos->bLength;
|
|
795
802
|
size -= _bos->bLength;
|
|
796
803
|
|
|
@@ -910,7 +917,7 @@ void API_EXPORTED libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos)
|
|
|
910
917
|
*
|
|
911
918
|
* \param ctx the context to operate on, or NULL for the default context
|
|
912
919
|
* \param dev_cap Device Capability descriptor with a bDevCapabilityType of
|
|
913
|
-
* \ref
|
|
920
|
+
* \ref libusb_bos_type::LIBUSB_BT_USB_2_0_EXTENSION
|
|
914
921
|
* LIBUSB_BT_USB_2_0_EXTENSION
|
|
915
922
|
* \param usb_2_0_extension output location for the USB 2.0 Extension
|
|
916
923
|
* descriptor. Only valid if 0 was returned. Must be freed with
|
|
@@ -940,7 +947,10 @@ int API_EXPORTED libusb_get_usb_2_0_extension_descriptor(
|
|
|
940
947
|
if (!_usb_2_0_extension)
|
|
941
948
|
return LIBUSB_ERROR_NO_MEM;
|
|
942
949
|
|
|
943
|
-
|
|
950
|
+
_usb_2_0_extension->bLength = dev_cap->bLength;
|
|
951
|
+
_usb_2_0_extension->bDescriptorType = dev_cap->bDescriptorType;
|
|
952
|
+
_usb_2_0_extension->bDevCapabilityType = dev_cap->bDevCapabilityType;
|
|
953
|
+
_usb_2_0_extension->bmAttributes = ReadLittleEndian32(dev_cap->dev_capability_data);
|
|
944
954
|
|
|
945
955
|
*usb_2_0_extension = _usb_2_0_extension;
|
|
946
956
|
return LIBUSB_SUCCESS;
|
|
@@ -965,7 +975,7 @@ void API_EXPORTED libusb_free_usb_2_0_extension_descriptor(
|
|
|
965
975
|
*
|
|
966
976
|
* \param ctx the context to operate on, or NULL for the default context
|
|
967
977
|
* \param dev_cap Device Capability descriptor with a bDevCapabilityType of
|
|
968
|
-
* \ref
|
|
978
|
+
* \ref libusb_bos_type::LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
|
|
969
979
|
* LIBUSB_BT_SS_USB_DEVICE_CAPABILITY
|
|
970
980
|
* \param ss_usb_device_cap output location for the SuperSpeed USB Device
|
|
971
981
|
* Capability descriptor. Only valid if 0 was returned. Must be freed with
|
|
@@ -995,12 +1005,151 @@ int API_EXPORTED libusb_get_ss_usb_device_capability_descriptor(
|
|
|
995
1005
|
if (!_ss_usb_device_cap)
|
|
996
1006
|
return LIBUSB_ERROR_NO_MEM;
|
|
997
1007
|
|
|
998
|
-
|
|
1008
|
+
_ss_usb_device_cap->bLength = dev_cap->bLength;
|
|
1009
|
+
_ss_usb_device_cap->bDescriptorType = dev_cap->bDescriptorType;
|
|
1010
|
+
_ss_usb_device_cap->bDevCapabilityType = dev_cap->bDevCapabilityType;
|
|
1011
|
+
_ss_usb_device_cap->bmAttributes = dev_cap->dev_capability_data[0];
|
|
1012
|
+
_ss_usb_device_cap->wSpeedSupported = ReadLittleEndian16(&dev_cap->dev_capability_data[1]);
|
|
1013
|
+
_ss_usb_device_cap->bFunctionalitySupport = dev_cap->dev_capability_data[3];
|
|
1014
|
+
_ss_usb_device_cap->bU1DevExitLat = dev_cap->dev_capability_data[4];
|
|
1015
|
+
_ss_usb_device_cap->bU2DevExitLat = ReadLittleEndian16(&dev_cap->dev_capability_data[5]);
|
|
999
1016
|
|
|
1000
1017
|
*ss_usb_device_cap = _ss_usb_device_cap;
|
|
1001
1018
|
return LIBUSB_SUCCESS;
|
|
1002
1019
|
}
|
|
1003
1020
|
|
|
1021
|
+
/// @cond DEV
|
|
1022
|
+
/** \internal \ingroup libusb_desc
|
|
1023
|
+
* We use this private struct only to parse a SuperSpeedPlus device capability
|
|
1024
|
+
* descriptor according to section 9.6.2.5 of the USB 3.1 specification.
|
|
1025
|
+
* We don't expose it.
|
|
1026
|
+
*/
|
|
1027
|
+
struct internal_ssplus_capability_descriptor {
|
|
1028
|
+
/** The length of the descriptor. Must be equal to LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE */
|
|
1029
|
+
uint8_t bLength;
|
|
1030
|
+
|
|
1031
|
+
/** The type of the descriptor */
|
|
1032
|
+
uint8_t bDescriptorType;
|
|
1033
|
+
|
|
1034
|
+
/** Must be equal to LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY */
|
|
1035
|
+
uint8_t bDevCapabilityType;
|
|
1036
|
+
|
|
1037
|
+
/** Unused */
|
|
1038
|
+
uint8_t bReserved;
|
|
1039
|
+
|
|
1040
|
+
/** Contains the number of SublinkSpeedIDs */
|
|
1041
|
+
uint32_t bmAttributes;
|
|
1042
|
+
|
|
1043
|
+
/** Contains the ssid, minRxLaneCount, and minTxLaneCount */
|
|
1044
|
+
uint16_t wFunctionalitySupport;
|
|
1045
|
+
|
|
1046
|
+
/** Unused */
|
|
1047
|
+
uint16_t wReserved;
|
|
1048
|
+
};
|
|
1049
|
+
/// @endcond
|
|
1050
|
+
|
|
1051
|
+
/** \ingroup libusb_desc
|
|
1052
|
+
* Get a SuperSpeedPlus USB Device Capability descriptor
|
|
1053
|
+
*
|
|
1054
|
+
* Since version 1.0.28, \ref LIBUSB_API_VERSION >= 0x0100010B
|
|
1055
|
+
*
|
|
1056
|
+
* \param ctx the context to operate on, or NULL for the default context
|
|
1057
|
+
* \param dev_cap Device Capability descriptor with a bDevCapabilityType of
|
|
1058
|
+
* \ref libusb_bos_type::LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY
|
|
1059
|
+
* LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY
|
|
1060
|
+
* \param ssplus_usb_device_cap output location for the SuperSpeedPlus USB Device
|
|
1061
|
+
* Capability descriptor. Only valid if 0 was returned. Must be freed with
|
|
1062
|
+
* libusb_free_ssplus_usb_device_capability_descriptor() after use.
|
|
1063
|
+
* \returns 0 on success
|
|
1064
|
+
* \returns a LIBUSB_ERROR code on error
|
|
1065
|
+
*/
|
|
1066
|
+
int API_EXPORTED libusb_get_ssplus_usb_device_capability_descriptor(
|
|
1067
|
+
libusb_context *ctx,
|
|
1068
|
+
struct libusb_bos_dev_capability_descriptor *dev_cap,
|
|
1069
|
+
struct libusb_ssplus_usb_device_capability_descriptor **ssplus_usb_device_cap)
|
|
1070
|
+
{
|
|
1071
|
+
struct libusb_ssplus_usb_device_capability_descriptor *_ssplus_cap;
|
|
1072
|
+
|
|
1073
|
+
/* Use a private struct to reuse our descriptor parsing system. */
|
|
1074
|
+
struct internal_ssplus_capability_descriptor parsedDescriptor;
|
|
1075
|
+
|
|
1076
|
+
/* Some size/type checks to make sure everything is in order */
|
|
1077
|
+
if (dev_cap->bDevCapabilityType != LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY) {
|
|
1078
|
+
usbi_err(ctx, "unexpected bDevCapabilityType 0x%x (expected 0x%x)",
|
|
1079
|
+
dev_cap->bDevCapabilityType,
|
|
1080
|
+
LIBUSB_BT_SUPERSPEED_PLUS_CAPABILITY);
|
|
1081
|
+
return LIBUSB_ERROR_INVALID_PARAM;
|
|
1082
|
+
} else if (dev_cap->bLength < LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE) {
|
|
1083
|
+
usbi_err(ctx, "short dev-cap descriptor read %u/%d",
|
|
1084
|
+
dev_cap->bLength, LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE);
|
|
1085
|
+
return LIBUSB_ERROR_IO;
|
|
1086
|
+
}
|
|
1087
|
+
|
|
1088
|
+
const uint8_t* dev_capability_data = dev_cap->dev_capability_data;
|
|
1089
|
+
parsedDescriptor.bLength = dev_cap->bLength;
|
|
1090
|
+
parsedDescriptor.bDescriptorType = dev_cap->bDescriptorType;
|
|
1091
|
+
parsedDescriptor.bDevCapabilityType = dev_cap->bDevCapabilityType;
|
|
1092
|
+
parsedDescriptor.bReserved = dev_capability_data[0];
|
|
1093
|
+
parsedDescriptor.bmAttributes = ReadLittleEndian32(&dev_capability_data[1]);
|
|
1094
|
+
parsedDescriptor.wFunctionalitySupport = ReadLittleEndian16(&dev_capability_data[5]);
|
|
1095
|
+
parsedDescriptor.wReserved = ReadLittleEndian16(&dev_capability_data[7]);
|
|
1096
|
+
|
|
1097
|
+
uint8_t numSublikSpeedAttributes = (parsedDescriptor.bmAttributes & 0xF) + 1;
|
|
1098
|
+
_ssplus_cap = malloc(sizeof(struct libusb_ssplus_usb_device_capability_descriptor) + (numSublikSpeedAttributes * sizeof(struct libusb_ssplus_sublink_attribute)));
|
|
1099
|
+
if (!_ssplus_cap)
|
|
1100
|
+
return LIBUSB_ERROR_NO_MEM;
|
|
1101
|
+
|
|
1102
|
+
/* Parse bmAttributes */
|
|
1103
|
+
_ssplus_cap->numSublinkSpeedAttributes = numSublikSpeedAttributes;
|
|
1104
|
+
_ssplus_cap->numSublinkSpeedIDs = ((parsedDescriptor.bmAttributes & 0xF0) >> 4) + 1;
|
|
1105
|
+
|
|
1106
|
+
/* Parse wFunctionalitySupport */
|
|
1107
|
+
_ssplus_cap->ssid = parsedDescriptor.wFunctionalitySupport & 0xF;
|
|
1108
|
+
_ssplus_cap->minRxLaneCount = (parsedDescriptor.wFunctionalitySupport & 0x0F00) >> 8;
|
|
1109
|
+
_ssplus_cap->minTxLaneCount = (parsedDescriptor.wFunctionalitySupport & 0xF000) >> 12;
|
|
1110
|
+
|
|
1111
|
+
/* Check that we have enough to read all the sublink attributes */
|
|
1112
|
+
if (dev_cap->bLength < LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE + (_ssplus_cap->numSublinkSpeedAttributes * sizeof(uint32_t))) {
|
|
1113
|
+
free(_ssplus_cap);
|
|
1114
|
+
usbi_err(ctx, "short ssplus capability descriptor, unable to read sublinks: Not enough data");
|
|
1115
|
+
return LIBUSB_ERROR_IO;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
/* Read the attributes */
|
|
1119
|
+
uint8_t* base = ((uint8_t*)dev_cap) + LIBUSB_BT_SSPLUS_USB_DEVICE_CAPABILITY_SIZE;
|
|
1120
|
+
for(uint8_t i = 0 ; i < _ssplus_cap->numSublinkSpeedAttributes ; i++) {
|
|
1121
|
+
uint32_t attr = ReadLittleEndian32(base + (i * sizeof(uint32_t)));
|
|
1122
|
+
_ssplus_cap->sublinkSpeedAttributes[i].ssid = attr & 0x0f;
|
|
1123
|
+
_ssplus_cap->sublinkSpeedAttributes[i].mantissa = attr >> 16;
|
|
1124
|
+
_ssplus_cap->sublinkSpeedAttributes[i].exponent = (attr >> 4) & 0x3 ;
|
|
1125
|
+
_ssplus_cap->sublinkSpeedAttributes[i].type = attr & 0x40 ? LIBUSB_SSPLUS_ATTR_TYPE_ASYM : LIBUSB_SSPLUS_ATTR_TYPE_SYM;
|
|
1126
|
+
_ssplus_cap->sublinkSpeedAttributes[i].direction = attr & 0x80 ? LIBUSB_SSPLUS_ATTR_DIR_TX : LIBUSB_SSPLUS_ATTR_DIR_RX;
|
|
1127
|
+
_ssplus_cap->sublinkSpeedAttributes[i].protocol = attr & 0x4000 ? LIBUSB_SSPLUS_ATTR_PROT_SSPLUS: LIBUSB_SSPLUS_ATTR_PROT_SS;
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
*ssplus_usb_device_cap = _ssplus_cap;
|
|
1131
|
+
return LIBUSB_SUCCESS;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
/** \ingroup libusb_desc
|
|
1135
|
+
* Free a SuperSpeedPlus USB Device Capability descriptor obtained from
|
|
1136
|
+
* libusb_get_ssplus_usb_device_capability_descriptor().
|
|
1137
|
+
* It is safe to call this function with a NULL ssplus_usb_device_cap
|
|
1138
|
+
* parameter, in which case the function simply returns.
|
|
1139
|
+
*
|
|
1140
|
+
* Since version 1.0.28, \ref LIBUSB_API_VERSION >= 0x0100010B
|
|
1141
|
+
*
|
|
1142
|
+
* \param ssplus_usb_device_cap the SuperSpeedPlus USB Device Capability descriptor
|
|
1143
|
+
* to free
|
|
1144
|
+
*/
|
|
1145
|
+
void API_EXPORTED libusb_free_ssplus_usb_device_capability_descriptor(
|
|
1146
|
+
struct libusb_ssplus_usb_device_capability_descriptor *ssplus_usb_device_cap)
|
|
1147
|
+
{
|
|
1148
|
+
free(ssplus_usb_device_cap);
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
|
|
1152
|
+
|
|
1004
1153
|
/** \ingroup libusb_desc
|
|
1005
1154
|
* Free a SuperSpeed USB Device Capability descriptor obtained from
|
|
1006
1155
|
* libusb_get_ss_usb_device_capability_descriptor().
|
|
@@ -1021,7 +1170,7 @@ void API_EXPORTED libusb_free_ss_usb_device_capability_descriptor(
|
|
|
1021
1170
|
*
|
|
1022
1171
|
* \param ctx the context to operate on, or NULL for the default context
|
|
1023
1172
|
* \param dev_cap Device Capability descriptor with a bDevCapabilityType of
|
|
1024
|
-
* \ref
|
|
1173
|
+
* \ref libusb_bos_type::LIBUSB_BT_CONTAINER_ID
|
|
1025
1174
|
* LIBUSB_BT_CONTAINER_ID
|
|
1026
1175
|
* \param container_id output location for the Container ID descriptor.
|
|
1027
1176
|
* Only valid if 0 was returned. Must be freed with
|
|
@@ -1050,7 +1199,11 @@ int API_EXPORTED libusb_get_container_id_descriptor(libusb_context *ctx,
|
|
|
1050
1199
|
if (!_container_id)
|
|
1051
1200
|
return LIBUSB_ERROR_NO_MEM;
|
|
1052
1201
|
|
|
1053
|
-
|
|
1202
|
+
_container_id->bLength = dev_cap->bLength;
|
|
1203
|
+
_container_id->bDescriptorType = dev_cap->bDescriptorType;
|
|
1204
|
+
_container_id->bDevCapabilityType = dev_cap->bDevCapabilityType;
|
|
1205
|
+
_container_id->bReserved = dev_cap->dev_capability_data[0];
|
|
1206
|
+
memcpy(_container_id->ContainerID, &dev_cap->dev_capability_data[1], 16);
|
|
1054
1207
|
|
|
1055
1208
|
*container_id = _container_id;
|
|
1056
1209
|
return LIBUSB_SUCCESS;
|
|
@@ -1077,7 +1230,7 @@ void API_EXPORTED libusb_free_container_id_descriptor(
|
|
|
1077
1230
|
*
|
|
1078
1231
|
* \param ctx the context to operate on, or NULL for the default context
|
|
1079
1232
|
* \param dev_cap Device Capability descriptor with a bDevCapabilityType of
|
|
1080
|
-
* \ref
|
|
1233
|
+
* \ref libusb_bos_type::LIBUSB_BT_PLATFORM_DESCRIPTOR
|
|
1081
1234
|
* LIBUSB_BT_PLATFORM_DESCRIPTOR
|
|
1082
1235
|
* \param platform_descriptor output location for the Platform descriptor.
|
|
1083
1236
|
* Only valid if 0 was returned. Must be freed with
|
|
@@ -1106,13 +1259,17 @@ int API_EXPORTED libusb_get_platform_descriptor(libusb_context *ctx,
|
|
|
1106
1259
|
if (!_platform_descriptor)
|
|
1107
1260
|
return LIBUSB_ERROR_NO_MEM;
|
|
1108
1261
|
|
|
1109
|
-
|
|
1262
|
+
_platform_descriptor->bLength = dev_cap->bLength;
|
|
1263
|
+
_platform_descriptor->bDescriptorType = dev_cap->bDescriptorType;
|
|
1264
|
+
_platform_descriptor->bDevCapabilityType = dev_cap->bDevCapabilityType;
|
|
1265
|
+
_platform_descriptor->bReserved = dev_cap->dev_capability_data[0];
|
|
1266
|
+
memcpy(_platform_descriptor->PlatformCapabilityUUID, &(dev_cap->dev_capability_data[1]), 16);
|
|
1110
1267
|
|
|
1111
|
-
/* Capability data is located after reserved byte and
|
|
1268
|
+
/* Capability data is located after reserved byte and 16 byte UUID */
|
|
1112
1269
|
uint8_t* capability_data = dev_cap->dev_capability_data + 1 + 16;
|
|
1113
1270
|
|
|
1114
1271
|
/* Capability data length is total descriptor length minus initial fields */
|
|
1115
|
-
size_t capability_data_length =
|
|
1272
|
+
size_t capability_data_length = dev_cap->bLength - (3 + 1 + 16);
|
|
1116
1273
|
|
|
1117
1274
|
memcpy(_platform_descriptor->CapabilityData, capability_data, capability_data_length);
|
|
1118
1275
|
|
|
@@ -1168,20 +1325,17 @@ int API_EXPORTED libusb_get_string_descriptor_ascii(libusb_device_handle *dev_ha
|
|
|
1168
1325
|
r = libusb_get_string_descriptor(dev_handle, 0, 0, str.buf, 4);
|
|
1169
1326
|
if (r < 0)
|
|
1170
1327
|
return r;
|
|
1171
|
-
else if (r != 4 || str.desc.bLength < 4)
|
|
1328
|
+
else if (r != 4 || str.desc.bLength < 4 || str.desc.bDescriptorType != LIBUSB_DT_STRING) {
|
|
1329
|
+
usbi_warn(HANDLE_CTX(dev_handle), "invalid language ID string descriptor");
|
|
1172
1330
|
return LIBUSB_ERROR_IO;
|
|
1173
|
-
else if (str.desc.
|
|
1174
|
-
return LIBUSB_ERROR_IO;
|
|
1175
|
-
else if (str.desc.bLength & 1)
|
|
1331
|
+
} else if (str.desc.bLength & 1)
|
|
1176
1332
|
usbi_warn(HANDLE_CTX(dev_handle), "suspicious bLength %u for language ID string descriptor", str.desc.bLength);
|
|
1177
1333
|
|
|
1178
1334
|
langid = libusb_le16_to_cpu(str.desc.wData[0]);
|
|
1179
1335
|
r = libusb_get_string_descriptor(dev_handle, desc_index, langid, str.buf, sizeof(str.buf));
|
|
1180
1336
|
if (r < 0)
|
|
1181
1337
|
return r;
|
|
1182
|
-
else if (r < DESC_HEADER_LENGTH || str.desc.bLength > r)
|
|
1183
|
-
return LIBUSB_ERROR_IO;
|
|
1184
|
-
else if (str.desc.bDescriptorType != LIBUSB_DT_STRING)
|
|
1338
|
+
else if (r < DESC_HEADER_LENGTH || str.desc.bLength > r || str.desc.bDescriptorType != LIBUSB_DT_STRING)
|
|
1185
1339
|
return LIBUSB_ERROR_IO;
|
|
1186
1340
|
else if ((str.desc.bLength & 1) || str.desc.bLength != r)
|
|
1187
1341
|
usbi_warn(HANDLE_CTX(dev_handle), "suspicious bLength %u for string descriptor (read %d)", str.desc.bLength, r);
|
|
@@ -1224,15 +1378,21 @@ static int parse_iad_array(struct libusb_context *ctx,
|
|
|
1224
1378
|
return LIBUSB_ERROR_IO;
|
|
1225
1379
|
}
|
|
1226
1380
|
|
|
1227
|
-
|
|
1381
|
+
/* First pass: Iterate through desc list, count number of IADs */
|
|
1228
1382
|
iad_array->length = 0;
|
|
1229
|
-
while (consumed
|
|
1230
|
-
|
|
1231
|
-
|
|
1383
|
+
while (size - consumed >= DESC_HEADER_LENGTH) {
|
|
1384
|
+
header.bLength = buf[0];
|
|
1385
|
+
header.bDescriptorType = buf[1];
|
|
1386
|
+
if (header.bLength < DESC_HEADER_LENGTH) {
|
|
1232
1387
|
usbi_err(ctx, "invalid descriptor bLength %d",
|
|
1233
1388
|
header.bLength);
|
|
1234
1389
|
return LIBUSB_ERROR_IO;
|
|
1235
1390
|
}
|
|
1391
|
+
else if (header.bLength > size - consumed) {
|
|
1392
|
+
usbi_warn(ctx, "short config descriptor read %d/%u",
|
|
1393
|
+
size - consumed, header.bLength);
|
|
1394
|
+
return LIBUSB_ERROR_IO;
|
|
1395
|
+
}
|
|
1236
1396
|
if (header.bDescriptorType == LIBUSB_DT_INTERFACE_ASSOCIATION)
|
|
1237
1397
|
iad_array->length++;
|
|
1238
1398
|
buf += header.bLength;
|
|
@@ -1241,22 +1401,36 @@ static int parse_iad_array(struct libusb_context *ctx,
|
|
|
1241
1401
|
|
|
1242
1402
|
iad_array->iad = NULL;
|
|
1243
1403
|
if (iad_array->length > 0) {
|
|
1244
|
-
iad = calloc(iad_array->length, sizeof(*iad));
|
|
1404
|
+
iad = calloc((size_t)iad_array->length, sizeof(*iad));
|
|
1245
1405
|
if (!iad)
|
|
1246
1406
|
return LIBUSB_ERROR_NO_MEM;
|
|
1247
1407
|
|
|
1248
1408
|
iad_array->iad = iad;
|
|
1249
1409
|
|
|
1250
|
-
|
|
1251
|
-
|
|
1410
|
+
/* Second pass: Iterate through desc list, fill IAD structures */
|
|
1411
|
+
int remaining = size;
|
|
1252
1412
|
i = 0;
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1413
|
+
do {
|
|
1414
|
+
header.bLength = buffer[0];
|
|
1415
|
+
header.bDescriptorType = buffer[1];
|
|
1416
|
+
if (header.bDescriptorType == LIBUSB_DT_INTERFACE_ASSOCIATION && (remaining >= LIBUSB_DT_INTERFACE_ASSOCIATION_SIZE)) {
|
|
1417
|
+
iad[i].bLength = buffer[0];
|
|
1418
|
+
iad[i].bDescriptorType = buffer[1];
|
|
1419
|
+
iad[i].bFirstInterface = buffer[2];
|
|
1420
|
+
iad[i].bInterfaceCount = buffer[3];
|
|
1421
|
+
iad[i].bFunctionClass = buffer[4];
|
|
1422
|
+
iad[i].bFunctionSubClass = buffer[5];
|
|
1423
|
+
iad[i].bFunctionProtocol = buffer[6];
|
|
1424
|
+
iad[i].iFunction = buffer[7];
|
|
1425
|
+
i++;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
remaining -= header.bLength;
|
|
1429
|
+
if (remaining < DESC_HEADER_LENGTH) {
|
|
1430
|
+
break;
|
|
1431
|
+
}
|
|
1432
|
+
buffer += header.bLength;
|
|
1433
|
+
} while (1);
|
|
1260
1434
|
}
|
|
1261
1435
|
|
|
1262
1436
|
return LIBUSB_SUCCESS;
|
|
@@ -1397,3 +1571,137 @@ void API_EXPORTED libusb_free_interface_association_descriptors(
|
|
|
1397
1571
|
free((void*)iad_array->iad);
|
|
1398
1572
|
free(iad_array);
|
|
1399
1573
|
}
|
|
1574
|
+
|
|
1575
|
+
/*
|
|
1576
|
+
* \brief Copy a UTF-8 string with proper truncation if needed.
|
|
1577
|
+
*
|
|
1578
|
+
* \param tgt The target utf-8 string. If NULL, then tgt is ignored,
|
|
1579
|
+
* tgt_size is forced to 0, and this function returns the
|
|
1580
|
+
* required tgt_size for a subsequent call to this function.
|
|
1581
|
+
* \param src The source utf-8 string. If NULL, then
|
|
1582
|
+
* the source string is empty, the return length is 1,
|
|
1583
|
+
* and, if tgt is not NULL, this function
|
|
1584
|
+
* sets tgt[0] to the null terminator.
|
|
1585
|
+
* \param tgt_size The size of target in bytes.
|
|
1586
|
+
* \return the length of src in bytes, including the null terminator.
|
|
1587
|
+
*
|
|
1588
|
+
* utf8_copy(NULL, src, 0) is equivalent to strlen(src) + 1.
|
|
1589
|
+
*/
|
|
1590
|
+
static int usbi_utf8_copy(char *tgt, char const *src, int tgt_size) {
|
|
1591
|
+
uint8_t* t = (uint8_t*)tgt;
|
|
1592
|
+
uint8_t const* s = (uint8_t const*)src;
|
|
1593
|
+
|
|
1594
|
+
if (NULL == src) {
|
|
1595
|
+
if ((NULL != tgt) && (tgt_size > 0)) {
|
|
1596
|
+
tgt[0] = 0;
|
|
1597
|
+
}
|
|
1598
|
+
return 1;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
if ((NULL == tgt) || (tgt_size <= 0)) {
|
|
1602
|
+
return (int)(strlen(src) + 1);
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
// copy UTF-8 string and compute length
|
|
1606
|
+
int k = 0;
|
|
1607
|
+
for (k = 0; s[k]; ++k) {
|
|
1608
|
+
if (k < tgt_size) {
|
|
1609
|
+
t[k] = s[k];
|
|
1610
|
+
} else {
|
|
1611
|
+
break;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
if (k >= tgt_size) {
|
|
1616
|
+
// truncate respecting UTF-8 character boundaries
|
|
1617
|
+
int idx = tgt_size - 1;
|
|
1618
|
+
while (idx && (0x80 == (t[idx] & 0xC0))) { // utf-8 continuation byte
|
|
1619
|
+
--idx;
|
|
1620
|
+
}
|
|
1621
|
+
t[idx] = 0;
|
|
1622
|
+
return (int)(strlen(src) + 1);
|
|
1623
|
+
} else {
|
|
1624
|
+
t[k++] = 0;
|
|
1625
|
+
return k;
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
/** \ingroup libusb_desc
|
|
1630
|
+
* Retrieve a device string without needing to open the device.
|
|
1631
|
+
*
|
|
1632
|
+
* Since version v1.0.30 \ref LIBUSB_API_VERSION >= 0x0100010C
|
|
1633
|
+
*
|
|
1634
|
+
* \param dev the target device
|
|
1635
|
+
* \param string_type the string type to retrieve
|
|
1636
|
+
* \param data the data buffer for the UTF-8 encoded string.
|
|
1637
|
+
* \param length the size of the data buffer in bytes.
|
|
1638
|
+
* USB string descriptors cannot be longer than
|
|
1639
|
+
* LIBUSB_DEVICE_STRING_BYTES_MAX.
|
|
1640
|
+
* \returns a negative error code or
|
|
1641
|
+
* the actual string length in bytes including the null terminator.
|
|
1642
|
+
* \see libusb_get_string_descriptor()
|
|
1643
|
+
* \see libusb_get_string_descriptor_ascii()
|
|
1644
|
+
*
|
|
1645
|
+
* This function works when the device is still closed since it relies
|
|
1646
|
+
* on the operating system to provide the string. The operating system
|
|
1647
|
+
* normally reads and caches the common string descriptors during
|
|
1648
|
+
* USB enumeration.
|
|
1649
|
+
*
|
|
1650
|
+
* Since the USB string descriptor could be processed by the OS,
|
|
1651
|
+
* this function returns a UTF-8 encoded string.
|
|
1652
|
+
*
|
|
1653
|
+
* The string will be returned untranslated or in the default OS language
|
|
1654
|
+
* when supported by the OS and USB device.
|
|
1655
|
+
*
|
|
1656
|
+
* One way to call this function is using a buffer on the stack:
|
|
1657
|
+
*
|
|
1658
|
+
* char buffer[LIBUSB_DEVICE_STRING_BYTES_MAX];
|
|
1659
|
+
* int ret = libusb_get_device_string(dev, LIBUSB_DEVICE_STRING_SERIAL_NUMBER, buffer, sizeof(buffer));
|
|
1660
|
+
* if (ret < 0) {
|
|
1661
|
+
* // handle error
|
|
1662
|
+
* }
|
|
1663
|
+
*
|
|
1664
|
+
* This function is commonly used to get the serial number to allow
|
|
1665
|
+
* for device selection before opening the selected device.
|
|
1666
|
+
*/
|
|
1667
|
+
int API_EXPORTED libusb_get_device_string(libusb_device *dev,
|
|
1668
|
+
enum libusb_device_string_type string_type, char *data, int length) {
|
|
1669
|
+
char * s;
|
|
1670
|
+
if (NULL == dev) {
|
|
1671
|
+
return LIBUSB_ERROR_INVALID_PARAM;
|
|
1672
|
+
}
|
|
1673
|
+
if ((string_type < 0) || (string_type >= LIBUSB_DEVICE_STRING_COUNT)) {
|
|
1674
|
+
return LIBUSB_ERROR_INVALID_PARAM;
|
|
1675
|
+
}
|
|
1676
|
+
if (length <= 0) {
|
|
1677
|
+
return LIBUSB_ERROR_INVALID_PARAM;
|
|
1678
|
+
}
|
|
1679
|
+
if (NULL == data) {
|
|
1680
|
+
length = 0;
|
|
1681
|
+
data = NULL;
|
|
1682
|
+
} else if (length > 0) {
|
|
1683
|
+
*data = 0; // return an empty string on errors when possible
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
if (NULL == dev->device_strings_utf8[string_type]) {
|
|
1687
|
+
if (usbi_backend.get_device_string) {
|
|
1688
|
+
s = malloc(LIBUSB_DEVICE_STRING_BYTES_MAX);
|
|
1689
|
+
int rv = usbi_backend.get_device_string(dev, string_type, s, LIBUSB_DEVICE_STRING_BYTES_MAX);
|
|
1690
|
+
if (rv < 0) {
|
|
1691
|
+
free(s);
|
|
1692
|
+
return rv;
|
|
1693
|
+
} else {
|
|
1694
|
+
dev->device_strings_utf8[string_type] = s;
|
|
1695
|
+
}
|
|
1696
|
+
} else {
|
|
1697
|
+
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1700
|
+
|
|
1701
|
+
s = dev->device_strings_utf8[string_type];
|
|
1702
|
+
if (NULL == s) {
|
|
1703
|
+
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
return usbi_utf8_copy(data, s, length);
|
|
1707
|
+
}
|