usb 2.12.1 → 2.13.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 +8 -0
- package/README.md +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/usb/bindings.js +1 -1
- package/dist/usb/bindings.js.map +1 -1
- package/dist/usb/capability.js.map +1 -1
- package/dist/usb/device.js.map +1 -1
- package/dist/usb/endpoint.d.ts +1 -0
- package/dist/usb/endpoint.js +2 -2
- package/dist/usb/endpoint.js.map +1 -1
- package/dist/usb/index.js.map +1 -1
- package/dist/usb/interface.js +2 -2
- package/dist/usb/interface.js.map +1 -1
- package/dist/webusb/index.d.ts +2 -2
- package/dist/webusb/index.js.map +1 -1
- package/dist/webusb/webusb-device.js +10 -10
- package/dist/webusb/webusb-device.js.map +1 -1
- package/libusb/.codespellrc +3 -0
- package/libusb/.private/appveyor_build.sh +5 -1
- package/libusb/.private/ci-build.sh +26 -1
- package/libusb/.private/ci-container-build.sh +2 -5
- package/libusb/.private/wbs.txt +5 -8
- package/libusb/AUTHORS +22 -0
- package/libusb/ChangeLog +19 -2
- package/libusb/HACKING +25 -0
- package/libusb/INSTALL_WIN.txt +11 -10
- package/libusb/NEWS +2 -2
- package/libusb/README +3 -2
- package/libusb/README.git +1 -1
- package/libusb/Xcode/common.xcconfig +8 -1
- package/libusb/Xcode/config.h +0 -6
- package/libusb/Xcode/debug.xcconfig +4 -1
- package/libusb/Xcode/libusb.xcconfig +1 -1
- package/libusb/Xcode/libusb.xcodeproj/project.pbxproj +60 -30
- package/libusb/Xcode/libusb_debug.xcconfig +1 -1
- package/libusb/Xcode/libusb_release.xcconfig +1 -1
- package/libusb/Xcode/release.xcconfig +1 -1
- package/libusb/appveyor.yml +33 -9
- package/libusb/configure.ac +68 -37
- package/libusb/examples/dpfp.c +2 -2
- package/libusb/examples/fxload.c +2 -2
- package/libusb/examples/hotplugtest.c +28 -13
- package/libusb/examples/listdevs.c +1 -1
- package/libusb/examples/sam3u_benchmark.c +1 -1
- package/libusb/examples/testlibusb.c +1 -1
- package/libusb/examples/xusb.c +74 -19
- package/libusb/libusb/Makefile.am +11 -1
- package/libusb/libusb/core.c +364 -186
- package/libusb/libusb/descriptor.c +276 -16
- package/libusb/libusb/hotplug.c +5 -4
- package/libusb/libusb/io.c +72 -61
- package/libusb/libusb/libusb-1.0.def +14 -1
- package/libusb/libusb/libusb.h +245 -76
- package/libusb/libusb/libusbi.h +35 -13
- package/libusb/libusb/os/darwin_usb.c +542 -279
- package/libusb/libusb/os/darwin_usb.h +44 -115
- package/libusb/libusb/os/emscripten_webusb.cpp +870 -0
- package/libusb/libusb/os/events_posix.c +40 -0
- package/libusb/libusb/os/events_posix.h +3 -0
- package/libusb/libusb/os/linux_usbfs.c +27 -16
- package/libusb/libusb/os/netbsd_usb.c +36 -36
- package/libusb/libusb/os/openbsd_usb.c +34 -34
- package/libusb/libusb/os/sunos_usb.c +25 -15
- package/libusb/libusb/os/threads_posix.c +1 -5
- package/libusb/libusb/os/windows_common.c +13 -5
- package/libusb/libusb/os/windows_common.h +8 -0
- package/libusb/libusb/os/windows_winusb.c +366 -174
- package/libusb/libusb/os/windows_winusb.h +13 -9
- package/libusb/libusb/strerror.c +5 -5
- package/libusb/libusb/sync.c +24 -19
- package/libusb/libusb/version.h +1 -1
- package/libusb/libusb/version_nano.h +1 -1
- package/libusb/msvc/Base.props +60 -0
- package/libusb/msvc/Configuration.Application.props +7 -0
- package/libusb/msvc/Configuration.Base.props +47 -0
- package/libusb/msvc/Configuration.DynamicLibrary.props +21 -0
- package/libusb/msvc/Configuration.StaticLibrary.props +7 -0
- package/libusb/msvc/ProjectConfigurations.Base.props +69 -0
- package/libusb/msvc/build_all.ps1 +17 -0
- package/libusb/msvc/config.h +2 -2
- package/libusb/msvc/dpfp.vcxproj +33 -0
- package/libusb/msvc/dpfp_threaded.vcxproj +38 -0
- package/libusb/msvc/fxload.vcxproj +46 -0
- package/libusb/msvc/getopt.vcxproj +33 -0
- package/libusb/msvc/hotplugtest.vcxproj +32 -0
- package/libusb/msvc/init_context.vcxproj +35 -0
- package/libusb/msvc/libusb.sln +542 -0
- package/libusb/msvc/libusb_dll.vcxproj +61 -0
- package/libusb/msvc/libusb_static.vcxproj +49 -0
- package/libusb/msvc/listdevs.vcxproj +32 -0
- package/libusb/msvc/sam3u_benchmark.vcxproj +33 -0
- package/libusb/msvc/set_option.vcxproj +35 -0
- package/libusb/msvc/stress.vcxproj +35 -0
- package/libusb/msvc/stress_mt.vcxproj +33 -0
- package/libusb/msvc/testlibusb.vcxproj +32 -0
- package/libusb/msvc/xusb.vcxproj +38 -0
- package/libusb/tests/Makefile.am +25 -3
- package/libusb/tests/init_context.c +153 -0
- package/libusb/tests/macos.c +130 -0
- package/libusb/tests/set_option.c +253 -0
- package/libusb/tests/stress.c +17 -14
- package/libusb/tests/stress_mt.c +265 -0
- package/libusb/tests/testlib.c +1 -1
- package/libusb/tests/umockdev.c +9 -9
- package/libusb/tests/webusb-test-shim/index.js +12 -0
- package/libusb/tests/webusb-test-shim/package-lock.json +50 -0
- package/libusb/tests/webusb-test-shim/package.json +10 -0
- package/package.json +7 -7
- 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/device.cc +15 -5
- package/libusb/msvc/dpfp_2013.vcxproj +0 -87
- package/libusb/msvc/dpfp_2013.vcxproj.filters +0 -26
- package/libusb/msvc/dpfp_2015.vcxproj +0 -87
- package/libusb/msvc/dpfp_2015.vcxproj.filters +0 -26
- package/libusb/msvc/dpfp_2017.vcxproj +0 -106
- package/libusb/msvc/dpfp_2017.vcxproj.filters +0 -26
- package/libusb/msvc/dpfp_2019.vcxproj +0 -106
- package/libusb/msvc/dpfp_2019.vcxproj.filters +0 -26
- package/libusb/msvc/dpfp_threaded_2013.vcxproj +0 -87
- package/libusb/msvc/dpfp_threaded_2013.vcxproj.filters +0 -26
- package/libusb/msvc/dpfp_threaded_2015.vcxproj +0 -87
- package/libusb/msvc/dpfp_threaded_2015.vcxproj.filters +0 -26
- package/libusb/msvc/dpfp_threaded_2017.vcxproj +0 -106
- package/libusb/msvc/dpfp_threaded_2017.vcxproj.filters +0 -26
- package/libusb/msvc/dpfp_threaded_2019.vcxproj +0 -106
- package/libusb/msvc/dpfp_threaded_2019.vcxproj.filters +0 -26
- package/libusb/msvc/fxload_2013.vcxproj +0 -94
- package/libusb/msvc/fxload_2013.vcxproj.filters +0 -35
- package/libusb/msvc/fxload_2015.vcxproj +0 -94
- package/libusb/msvc/fxload_2015.vcxproj.filters +0 -35
- package/libusb/msvc/fxload_2017.vcxproj +0 -113
- package/libusb/msvc/fxload_2017.vcxproj.filters +0 -35
- package/libusb/msvc/fxload_2019.vcxproj +0 -113
- package/libusb/msvc/fxload_2019.vcxproj.filters +0 -35
- package/libusb/msvc/getopt_2013.vcxproj +0 -72
- package/libusb/msvc/getopt_2013.vcxproj.filters +0 -26
- package/libusb/msvc/getopt_2015.vcxproj +0 -73
- package/libusb/msvc/getopt_2015.vcxproj.filters +0 -26
- package/libusb/msvc/getopt_2017.vcxproj +0 -92
- package/libusb/msvc/getopt_2017.vcxproj.filters +0 -26
- package/libusb/msvc/getopt_2019.vcxproj +0 -92
- package/libusb/msvc/getopt_2019.vcxproj.filters +0 -26
- package/libusb/msvc/hotplugtest_2013.vcxproj +0 -86
- package/libusb/msvc/hotplugtest_2013.vcxproj.filters +0 -23
- package/libusb/msvc/hotplugtest_2015.vcxproj +0 -86
- package/libusb/msvc/hotplugtest_2015.vcxproj.filters +0 -23
- package/libusb/msvc/hotplugtest_2017.vcxproj +0 -105
- package/libusb/msvc/hotplugtest_2017.vcxproj.filters +0 -23
- package/libusb/msvc/hotplugtest_2019.vcxproj +0 -105
- package/libusb/msvc/hotplugtest_2019.vcxproj.filters +0 -23
- package/libusb/msvc/libusb_2013.sln +0 -137
- package/libusb/msvc/libusb_2015.sln +0 -137
- package/libusb/msvc/libusb_2017.sln +0 -240
- package/libusb/msvc/libusb_2019.sln +0 -240
- package/libusb/msvc/libusb_dll_2013.vcxproj +0 -104
- package/libusb/msvc/libusb_dll_2013.vcxproj.filters +0 -94
- package/libusb/msvc/libusb_dll_2015.vcxproj +0 -105
- package/libusb/msvc/libusb_dll_2015.vcxproj.filters +0 -94
- package/libusb/msvc/libusb_dll_2017.vcxproj +0 -124
- package/libusb/msvc/libusb_dll_2017.vcxproj.filters +0 -94
- package/libusb/msvc/libusb_dll_2019.vcxproj +0 -124
- package/libusb/msvc/libusb_dll_2019.vcxproj.filters +0 -94
- package/libusb/msvc/libusb_static_2013.vcxproj +0 -94
- package/libusb/msvc/libusb_static_2013.vcxproj.filters +0 -80
- package/libusb/msvc/libusb_static_2015.vcxproj +0 -95
- package/libusb/msvc/libusb_static_2015.vcxproj.filters +0 -80
- package/libusb/msvc/libusb_static_2017.vcxproj +0 -114
- package/libusb/msvc/libusb_static_2017.vcxproj.filters +0 -80
- package/libusb/msvc/libusb_static_2019.vcxproj +0 -114
- package/libusb/msvc/libusb_static_2019.vcxproj.filters +0 -80
- package/libusb/msvc/listdevs_2013.vcxproj +0 -86
- package/libusb/msvc/listdevs_2013.vcxproj.filters +0 -23
- package/libusb/msvc/listdevs_2015.vcxproj +0 -86
- package/libusb/msvc/listdevs_2015.vcxproj.filters +0 -23
- package/libusb/msvc/listdevs_2017.vcxproj +0 -105
- package/libusb/msvc/listdevs_2017.vcxproj.filters +0 -23
- package/libusb/msvc/listdevs_2019.vcxproj +0 -105
- package/libusb/msvc/listdevs_2019.vcxproj.filters +0 -23
- package/libusb/msvc/sam3u_benchmark_2013.vcxproj +0 -87
- package/libusb/msvc/sam3u_benchmark_2013.vcxproj.filters +0 -26
- package/libusb/msvc/sam3u_benchmark_2015.vcxproj +0 -87
- package/libusb/msvc/sam3u_benchmark_2015.vcxproj.filters +0 -26
- package/libusb/msvc/sam3u_benchmark_2017.vcxproj +0 -106
- package/libusb/msvc/sam3u_benchmark_2017.vcxproj.filters +0 -26
- package/libusb/msvc/sam3u_benchmark_2019.vcxproj +0 -106
- package/libusb/msvc/sam3u_benchmark_2019.vcxproj.filters +0 -26
- package/libusb/msvc/stress_2013.vcxproj +0 -89
- package/libusb/msvc/stress_2013.vcxproj.filters +0 -32
- package/libusb/msvc/stress_2015.vcxproj +0 -89
- package/libusb/msvc/stress_2015.vcxproj.filters +0 -32
- package/libusb/msvc/stress_2017.vcxproj +0 -108
- package/libusb/msvc/stress_2017.vcxproj.filters +0 -32
- package/libusb/msvc/stress_2019.vcxproj +0 -108
- package/libusb/msvc/stress_2019.vcxproj.filters +0 -32
- package/libusb/msvc/testlibusb_2013.vcxproj +0 -86
- package/libusb/msvc/testlibusb_2013.vcxproj.filters +0 -23
- package/libusb/msvc/testlibusb_2015.vcxproj +0 -86
- package/libusb/msvc/testlibusb_2015.vcxproj.filters +0 -23
- package/libusb/msvc/testlibusb_2017.vcxproj +0 -105
- package/libusb/msvc/testlibusb_2017.vcxproj.filters +0 -23
- package/libusb/msvc/testlibusb_2019.vcxproj +0 -105
- package/libusb/msvc/testlibusb_2019.vcxproj.filters +0 -23
- package/libusb/msvc/xusb_2013.vcxproj +0 -86
- package/libusb/msvc/xusb_2013.vcxproj.filters +0 -23
- package/libusb/msvc/xusb_2015.vcxproj +0 -86
- package/libusb/msvc/xusb_2015.vcxproj.filters +0 -23
- package/libusb/msvc/xusb_2017.vcxproj +0 -105
- package/libusb/msvc/xusb_2017.vcxproj.filters +0 -23
- package/libusb/msvc/xusb_2019.vcxproj +0 -105
- package/libusb/msvc/xusb_2019.vcxproj.filters +0 -23
|
@@ -263,6 +263,9 @@ static int get_interface_details(struct libusb_context *ctx, HDEVINFO dev_info,
|
|
|
263
263
|
char guid_string[MAX_GUID_STRING_LENGTH];
|
|
264
264
|
DWORD size;
|
|
265
265
|
|
|
266
|
+
#ifndef ENABLE_LOGGING
|
|
267
|
+
UNUSED(*guid_string);
|
|
268
|
+
#endif
|
|
266
269
|
dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
|
|
267
270
|
dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
|
268
271
|
for (;;) {
|
|
@@ -485,6 +488,20 @@ static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc,
|
|
|
485
488
|
return LIBUSB_ERROR_NOT_FOUND;
|
|
486
489
|
}
|
|
487
490
|
|
|
491
|
+
static const struct libusb_interface_descriptor *get_interface_descriptor_by_number(struct libusb_device_handle *dev_handle, struct libusb_config_descriptor *conf_desc, int iface, uint8_t altsetting)
|
|
492
|
+
{
|
|
493
|
+
int i;
|
|
494
|
+
|
|
495
|
+
for (i = 0; i < conf_desc->bNumInterfaces; i++) {
|
|
496
|
+
if (altsetting < conf_desc->interface[i].num_altsetting && conf_desc->interface[i].altsetting[altsetting].bInterfaceNumber == iface) {
|
|
497
|
+
return &conf_desc->interface[i].altsetting[altsetting];
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
usbi_err(HANDLE_CTX(dev_handle), "interface %d with altsetting %d not found for device", iface, (int)altsetting);
|
|
502
|
+
return NULL;
|
|
503
|
+
}
|
|
504
|
+
|
|
488
505
|
/*
|
|
489
506
|
* Open a device and associate the HANDLE with the context's I/O completion port
|
|
490
507
|
*/
|
|
@@ -523,11 +540,12 @@ static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, uin
|
|
|
523
540
|
return r;
|
|
524
541
|
}
|
|
525
542
|
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
543
|
+
if_desc = get_interface_descriptor_by_number(dev_handle, conf_desc, iface, altsetting);
|
|
544
|
+
if (if_desc == NULL) {
|
|
545
|
+
r = LIBUSB_ERROR_NOT_FOUND;
|
|
546
|
+
goto end;
|
|
529
547
|
}
|
|
530
|
-
|
|
548
|
+
|
|
531
549
|
safe_free(priv->usb_interface[iface].endpoint);
|
|
532
550
|
|
|
533
551
|
if (if_desc->bNumEndpoints == 0) {
|
|
@@ -535,8 +553,8 @@ static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, uin
|
|
|
535
553
|
} else {
|
|
536
554
|
priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints);
|
|
537
555
|
if (priv->usb_interface[iface].endpoint == NULL) {
|
|
538
|
-
|
|
539
|
-
|
|
556
|
+
r = LIBUSB_ERROR_NO_MEM;
|
|
557
|
+
goto end;
|
|
540
558
|
}
|
|
541
559
|
priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints;
|
|
542
560
|
for (i = 0; i < if_desc->bNumEndpoints; i++) {
|
|
@@ -544,7 +562,6 @@ static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, uin
|
|
|
544
562
|
usbi_dbg(HANDLE_CTX(dev_handle), "(re)assigned endpoint %02X to interface %u", priv->usb_interface[iface].endpoint[i], iface);
|
|
545
563
|
}
|
|
546
564
|
}
|
|
547
|
-
libusb_free_config_descriptor(conf_desc);
|
|
548
565
|
|
|
549
566
|
// Extra init may be required to configure endpoints
|
|
550
567
|
if (priv->apib->configure_endpoints)
|
|
@@ -553,6 +570,8 @@ static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, uin
|
|
|
553
570
|
if (r == LIBUSB_SUCCESS)
|
|
554
571
|
priv->usb_interface[iface].current_altsetting = altsetting;
|
|
555
572
|
|
|
573
|
+
end:
|
|
574
|
+
libusb_free_config_descriptor(conf_desc);
|
|
556
575
|
return r;
|
|
557
576
|
}
|
|
558
577
|
|
|
@@ -1053,7 +1072,6 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d
|
|
|
1053
1072
|
DWORD size;
|
|
1054
1073
|
uint8_t bus_number, depth;
|
|
1055
1074
|
int r;
|
|
1056
|
-
int ginfotimeout;
|
|
1057
1075
|
|
|
1058
1076
|
priv = usbi_get_device_priv(dev);
|
|
1059
1077
|
|
|
@@ -1114,61 +1132,45 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d
|
|
|
1114
1132
|
|
|
1115
1133
|
conn_info.ConnectionIndex = (ULONG)port_number;
|
|
1116
1134
|
// coverity[tainted_data_argument]
|
|
1117
|
-
ginfotimeout = 20;
|
|
1118
|
-
do {
|
|
1119
|
-
if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, sizeof(conn_info),
|
|
1120
|
-
&conn_info, sizeof(conn_info), &size, NULL)) {
|
|
1121
|
-
usbi_warn(ctx, "could not get node connection information for device '%s': %s",
|
|
1122
|
-
priv->dev_id, windows_error_str(0));
|
|
1123
|
-
CloseHandle(hub_handle);
|
|
1124
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
1125
|
-
}
|
|
1126
1135
|
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|| (conn_info.DeviceDescriptor.bDescriptorType != LIBUSB_DT_DEVICE)) {
|
|
1135
|
-
SleepEx(50, TRUE);
|
|
1136
|
-
continue;
|
|
1137
|
-
}
|
|
1136
|
+
if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, sizeof(conn_info),
|
|
1137
|
+
&conn_info, sizeof(conn_info), &size, NULL)) {
|
|
1138
|
+
usbi_warn(ctx, "could not get node connection information for device '%s': %s",
|
|
1139
|
+
priv->dev_id, windows_error_str(0));
|
|
1140
|
+
CloseHandle(hub_handle);
|
|
1141
|
+
return LIBUSB_ERROR_NO_DEVICE;
|
|
1142
|
+
}
|
|
1138
1143
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
priv->active_config = conn_info.CurrentConfigurationValue;
|
|
1145
|
-
if (priv->active_config == 0) {
|
|
1146
|
-
usbi_dbg(ctx, "0x%x:0x%x found %u configurations (not configured)",
|
|
1147
|
-
dev->device_descriptor.idVendor,
|
|
1148
|
-
dev->device_descriptor.idProduct,
|
|
1149
|
-
dev->device_descriptor.bNumConfigurations);
|
|
1150
|
-
SleepEx(50, TRUE);
|
|
1151
|
-
}
|
|
1152
|
-
} while (priv->active_config == 0 && --ginfotimeout >= 0);
|
|
1144
|
+
if (conn_info.ConnectionStatus == NoDeviceConnected) {
|
|
1145
|
+
usbi_err(ctx, "device '%s' is no longer connected!", priv->dev_id);
|
|
1146
|
+
CloseHandle(hub_handle);
|
|
1147
|
+
return LIBUSB_ERROR_NO_DEVICE;
|
|
1148
|
+
}
|
|
1153
1149
|
|
|
1154
1150
|
if ((conn_info.DeviceDescriptor.bLength != LIBUSB_DT_DEVICE_SIZE)
|
|
1155
|
-
|
|
1151
|
+
|| (conn_info.DeviceDescriptor.bDescriptorType != LIBUSB_DT_DEVICE)) {
|
|
1156
1152
|
usbi_err(ctx, "device '%s' has invalid descriptor!", priv->dev_id);
|
|
1157
1153
|
CloseHandle(hub_handle);
|
|
1158
1154
|
return LIBUSB_ERROR_OTHER;
|
|
1159
1155
|
}
|
|
1160
1156
|
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1157
|
+
static_assert(sizeof(dev->device_descriptor) == sizeof(conn_info.DeviceDescriptor),
|
|
1158
|
+
"mismatch between libusb and OS device descriptor sizes");
|
|
1159
|
+
memcpy(&dev->device_descriptor, &conn_info.DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
|
|
1160
|
+
usbi_localize_device_descriptor(&dev->device_descriptor);
|
|
1161
|
+
|
|
1162
|
+
if (conn_info.CurrentConfigurationValue == 0) {
|
|
1163
|
+
usbi_dbg(ctx, "found %u configurations for device '%s' but device is not configured (i.e. current config: 0), ignoring it",
|
|
1164
|
+
dev->device_descriptor.bNumConfigurations,
|
|
1165
|
+
priv->dev_id);
|
|
1166
|
+
CloseHandle(hub_handle);
|
|
1167
|
+
return LIBUSB_ERROR_OTHER;
|
|
1170
1168
|
}
|
|
1171
1169
|
|
|
1170
|
+
priv->active_config = conn_info.CurrentConfigurationValue;
|
|
1171
|
+
usbi_dbg(ctx, "found %u configurations (current config: %u) for device '%s'",
|
|
1172
|
+
dev->device_descriptor.bNumConfigurations, priv->active_config, priv->dev_id);
|
|
1173
|
+
|
|
1172
1174
|
// Cache as many config descriptors as we can
|
|
1173
1175
|
cache_config_descriptors(dev, hub_handle);
|
|
1174
1176
|
|
|
@@ -1265,37 +1267,24 @@ static bool get_dev_port_number(HDEVINFO dev_info, SP_DEVINFO_DATA *dev_info_dat
|
|
|
1265
1267
|
}
|
|
1266
1268
|
|
|
1267
1269
|
static int enumerate_hcd_root_hub(struct libusb_context *ctx, const char *dev_id,
|
|
1268
|
-
|
|
1270
|
+
DEVINST devinst)
|
|
1269
1271
|
{
|
|
1270
|
-
struct libusb_device *dev;
|
|
1271
|
-
struct winusb_device_priv *priv;
|
|
1272
|
-
unsigned long session_id;
|
|
1273
1272
|
DEVINST child_devinst;
|
|
1273
|
+
struct libusb_device* dev;
|
|
1274
1274
|
|
|
1275
1275
|
if (CM_Get_Child(&child_devinst, devinst, 0) != CR_SUCCESS) {
|
|
1276
1276
|
usbi_warn(ctx, "could not get child devinst for '%s'", dev_id);
|
|
1277
1277
|
return LIBUSB_SUCCESS;
|
|
1278
1278
|
}
|
|
1279
1279
|
|
|
1280
|
-
|
|
1281
|
-
dev = usbi_get_device_by_session_id(ctx, session_id);
|
|
1280
|
+
dev = usbi_get_device_by_session_id(ctx, (unsigned long)child_devinst);
|
|
1282
1281
|
if (dev == NULL) {
|
|
1283
|
-
|
|
1282
|
+
usbi_warn(ctx, "HCD '%s' child not found", dev_id);
|
|
1284
1283
|
return LIBUSB_SUCCESS;
|
|
1285
1284
|
}
|
|
1286
1285
|
|
|
1287
|
-
if (dev->
|
|
1288
|
-
|
|
1289
|
-
usbi_dbg(ctx, "assigning HCD '%s' bus number %u", dev_id, bus_number);
|
|
1290
|
-
dev->bus_number = bus_number;
|
|
1291
|
-
|
|
1292
|
-
if (sscanf(dev_id, "PCI\\VEN_%04hx&DEV_%04hx%*s", &dev->device_descriptor.idVendor, &dev->device_descriptor.idProduct) != 2)
|
|
1293
|
-
usbi_warn(ctx, "could not infer VID/PID of HCD root hub from '%s'", dev_id);
|
|
1294
|
-
|
|
1295
|
-
priv = usbi_get_device_priv(dev);
|
|
1296
|
-
priv->root_hub = true;
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1286
|
+
if (sscanf(dev_id, "PCI\\VEN_%04hx&DEV_%04hx%*s", &dev->device_descriptor.idVendor, &dev->device_descriptor.idProduct) != 2)
|
|
1287
|
+
usbi_warn(ctx, "could not infer VID/PID of HCD from '%s'", dev_id);
|
|
1299
1288
|
libusb_unref_device(dev);
|
|
1300
1289
|
return LIBUSB_SUCCESS;
|
|
1301
1290
|
}
|
|
@@ -1358,14 +1347,25 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev
|
|
|
1358
1347
|
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
|
|
1359
1348
|
int interface_number;
|
|
1360
1349
|
const char *mi_str;
|
|
1350
|
+
int iadi, iadintfi;
|
|
1351
|
+
char* endptr;
|
|
1352
|
+
struct libusb_interface_association_descriptor_array *iad_array;
|
|
1353
|
+
const struct libusb_interface_association_descriptor *iad;
|
|
1361
1354
|
|
|
1362
1355
|
// Because MI_## are not necessarily in sequential order (some composite
|
|
1363
1356
|
// devices will have only MI_00 & MI_03 for instance), we retrieve the actual
|
|
1364
1357
|
// interface number from the path's MI value
|
|
1365
1358
|
mi_str = strstr(device_id, "MI_");
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1359
|
+
|
|
1360
|
+
endptr = NULL;
|
|
1361
|
+
// This initialization, while redundant, is needed to make MSVC happy
|
|
1362
|
+
interface_number = -1;
|
|
1363
|
+
|
|
1364
|
+
if (mi_str != NULL) {
|
|
1365
|
+
interface_number = strtoul(&mi_str[3], &endptr, 16);
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
if (mi_str == NULL || endptr - &mi_str[3] != 2) {
|
|
1369
1369
|
usbi_warn(ctx, "failure to read interface number for %s, using default value", device_id);
|
|
1370
1370
|
interface_number = 0;
|
|
1371
1371
|
}
|
|
@@ -1396,6 +1396,27 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev
|
|
|
1396
1396
|
return LIBUSB_ERROR_NO_MEM;
|
|
1397
1397
|
}
|
|
1398
1398
|
|
|
1399
|
+
// For WinUSBX, set up associations for interfaces grouped by an IAD
|
|
1400
|
+
if ((api == USB_API_WINUSBX) && !libusb_get_active_interface_association_descriptors(dev, &iad_array)) {
|
|
1401
|
+
for (iadi = 0; iadi < iad_array->length; iadi++) {
|
|
1402
|
+
iad = &iad_array->iad[iadi];
|
|
1403
|
+
if (iad->bFirstInterface == interface_number) {
|
|
1404
|
+
priv->usb_interface[interface_number].num_associated_interfaces = iad->bInterfaceCount;
|
|
1405
|
+
priv->usb_interface[interface_number].first_associated_interface = iad->bFirstInterface;
|
|
1406
|
+
for (iadintfi = 1; iadintfi < iad->bInterfaceCount; iadintfi++) {
|
|
1407
|
+
usbi_dbg(ctx, "interface[%d] is associated with interface[%d]",
|
|
1408
|
+
interface_number + iadintfi, interface_number);
|
|
1409
|
+
priv->usb_interface[interface_number + iadintfi].apib = &usb_api_backend[api];
|
|
1410
|
+
priv->usb_interface[interface_number + iadintfi].sub_api = sub_api;
|
|
1411
|
+
priv->usb_interface[interface_number + iadintfi].num_associated_interfaces = iad->bInterfaceCount;
|
|
1412
|
+
priv->usb_interface[interface_number + iadintfi].first_associated_interface = iad->bFirstInterface;
|
|
1413
|
+
}
|
|
1414
|
+
break;
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
libusb_free_interface_association_descriptors(iad_array);
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1399
1420
|
return LIBUSB_SUCCESS;
|
|
1400
1421
|
}
|
|
1401
1422
|
|
|
@@ -1427,6 +1448,140 @@ static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *d
|
|
|
1427
1448
|
return LIBUSB_SUCCESS;
|
|
1428
1449
|
}
|
|
1429
1450
|
|
|
1451
|
+
// get the n-th device interface GUID indexed by guid_number
|
|
1452
|
+
static int get_guid(struct libusb_context *ctx, char *dev_id, HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data,
|
|
1453
|
+
int guid_number, GUID **if_guid)
|
|
1454
|
+
{
|
|
1455
|
+
DWORD size, reg_type;
|
|
1456
|
+
HKEY key;
|
|
1457
|
+
char *guid_string, *new_guid_string;
|
|
1458
|
+
char *guid, *guid_term;
|
|
1459
|
+
LONG s;
|
|
1460
|
+
int pass, guids_left;
|
|
1461
|
+
int err = LIBUSB_SUCCESS;
|
|
1462
|
+
#if !defined(ENABLE_LOGGING)
|
|
1463
|
+
UNUSED(dev_id);
|
|
1464
|
+
#endif
|
|
1465
|
+
|
|
1466
|
+
key = pSetupDiOpenDevRegKey(*dev_info, dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
|
|
1467
|
+
if (key == INVALID_HANDLE_VALUE) {
|
|
1468
|
+
usbi_warn(ctx, "Cannot get the additional GUIDs for '%s'", dev_id);
|
|
1469
|
+
return LIBUSB_ERROR_ACCESS;
|
|
1470
|
+
}
|
|
1471
|
+
// Reserve buffer large enough to hold one GUID with two terminating characters
|
|
1472
|
+
size = MAX_GUID_STRING_LENGTH + 1;
|
|
1473
|
+
// Allocate memory for storing the guid_string with two extra terminating characters
|
|
1474
|
+
// This is necessary for parsing the REG_MULTI_SZ type below
|
|
1475
|
+
guid_string = malloc(size + 2);
|
|
1476
|
+
if (guid_string == NULL) {
|
|
1477
|
+
usbi_err(ctx, "failed to alloc guid_string");
|
|
1478
|
+
return LIBUSB_ERROR_NO_MEM;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
// The 1st pass tries to get the guid. If it fails due to ERROR_MORE_DATA
|
|
1482
|
+
// then reallocate enough memory for the 2nd pass
|
|
1483
|
+
for (pass = 0; pass < 2; pass++) {
|
|
1484
|
+
// Look for both DeviceInterfaceGUIDs *and* DeviceInterfaceGUID, in that order
|
|
1485
|
+
// If multiple GUIDs, find the n-th that is indexed by guid_number
|
|
1486
|
+
s = pRegQueryValueExA(key, "DeviceInterfaceGUIDs", NULL, ®_type,
|
|
1487
|
+
(LPBYTE)guid_string, &size);
|
|
1488
|
+
if (s == ERROR_FILE_NOT_FOUND)
|
|
1489
|
+
s = pRegQueryValueExA(key, "DeviceInterfaceGUID", NULL, ®_type,
|
|
1490
|
+
(LPBYTE)guid_string, &size);
|
|
1491
|
+
if (s == ERROR_SUCCESS) {
|
|
1492
|
+
// The GUID was read successfully
|
|
1493
|
+
break;
|
|
1494
|
+
} else if (s == ERROR_FILE_NOT_FOUND) {
|
|
1495
|
+
usbi_info(ctx, "no DeviceInterfaceGUID registered for '%s'", dev_id);
|
|
1496
|
+
err = LIBUSB_ERROR_ACCESS;
|
|
1497
|
+
goto exit;
|
|
1498
|
+
} else if (s == ERROR_MORE_DATA) {
|
|
1499
|
+
if (pass == 1) {
|
|
1500
|
+
// Previous pass should have allocated enough memory, but reading failed
|
|
1501
|
+
usbi_warn(ctx, "unexpected error from pRegQueryValueExA for '%s'", dev_id);
|
|
1502
|
+
err = LIBUSB_ERROR_OTHER;
|
|
1503
|
+
goto exit;
|
|
1504
|
+
}
|
|
1505
|
+
new_guid_string = realloc((void *)guid_string, size + 2);
|
|
1506
|
+
if (new_guid_string == NULL) {
|
|
1507
|
+
usbi_err(ctx, "failed to realloc guid string");
|
|
1508
|
+
err = LIBUSB_ERROR_NO_MEM;
|
|
1509
|
+
goto exit;
|
|
1510
|
+
}
|
|
1511
|
+
guid_string = new_guid_string;
|
|
1512
|
+
} else {
|
|
1513
|
+
usbi_warn(ctx, "unexpected error from pRegQueryValueExA for '%s'", dev_id);
|
|
1514
|
+
err = LIBUSB_ERROR_ACCESS;
|
|
1515
|
+
goto exit;
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
// https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexa#remarks
|
|
1520
|
+
// - "string may not have been stored with the proper terminating null characters"
|
|
1521
|
+
// - The following GUIDs should be consider as valid:
|
|
1522
|
+
// "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\0", "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}",
|
|
1523
|
+
// "{xxx.....xx}\0\0\0", "{xxx.....xx}\0{xxx.....xx}\0{xxx.....xx}\0",
|
|
1524
|
+
// "{xxx.....xx}\0{xxx.....xx}\0{xxx.....xx}", "{xxx.....xx}{xxx.....xx}{xxx.....xx}",
|
|
1525
|
+
// "{xxx.....xx}\0{xxx.....xx}\0{xxx.....xx}\0\0\0\0"
|
|
1526
|
+
if ((reg_type == REG_SZ ) || (reg_type == REG_MULTI_SZ)) {
|
|
1527
|
+
/* Get the n-th GUID indexed by guid_number since the DeviceInterfaceGUIDs may
|
|
1528
|
+
contain more GUIDs */
|
|
1529
|
+
guid = guid_string;
|
|
1530
|
+
// Add two terminating chars for not overrunning the allocated memory while iterating
|
|
1531
|
+
guid[size] = '\0';
|
|
1532
|
+
guid[size + 1] = '\0';
|
|
1533
|
+
// Iterate the GUIDs in the guid string
|
|
1534
|
+
guids_left = guid_number;
|
|
1535
|
+
while (guids_left) {
|
|
1536
|
+
guid = strchr(guid, '}');
|
|
1537
|
+
if (guid == NULL) {
|
|
1538
|
+
usbi_warn(ctx, "no GUID with index %d registered for '%s'", guid_number, dev_id);
|
|
1539
|
+
err = LIBUSB_ERROR_ACCESS;
|
|
1540
|
+
goto exit;
|
|
1541
|
+
}
|
|
1542
|
+
guid++;
|
|
1543
|
+
// Skip the terminating char if available
|
|
1544
|
+
if (*guid == '\0') {
|
|
1545
|
+
guid++;
|
|
1546
|
+
}
|
|
1547
|
+
guids_left--;
|
|
1548
|
+
}
|
|
1549
|
+
// Add terminating char to the string
|
|
1550
|
+
guid_term = strchr(guid, '}');
|
|
1551
|
+
if (guid_term == NULL) {
|
|
1552
|
+
usbi_warn(ctx, "no GUID with index %d registered for '%s'", guid_number, dev_id);
|
|
1553
|
+
err = LIBUSB_ERROR_ACCESS;
|
|
1554
|
+
goto exit;
|
|
1555
|
+
}
|
|
1556
|
+
// Terminate the current guid string to handle the variant without separators
|
|
1557
|
+
guid_term++;
|
|
1558
|
+
*guid_term = '\0';
|
|
1559
|
+
} else {
|
|
1560
|
+
usbi_warn(ctx, "unexpected type of DeviceInterfaceGUID for '%s'", dev_id);
|
|
1561
|
+
err = LIBUSB_ERROR_ACCESS;
|
|
1562
|
+
goto exit;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
*if_guid = malloc(sizeof(GUID));
|
|
1566
|
+
if (*if_guid == NULL) {
|
|
1567
|
+
usbi_err(ctx, "failed to alloc if_guid");
|
|
1568
|
+
err = LIBUSB_ERROR_NO_MEM;
|
|
1569
|
+
goto exit;
|
|
1570
|
+
}
|
|
1571
|
+
if (!string_to_guid(guid, *if_guid)) {
|
|
1572
|
+
usbi_warn(ctx, "device '%s' has malformed DeviceInterfaceGUID string '%s', skipping", dev_id, guid);
|
|
1573
|
+
free(*if_guid);
|
|
1574
|
+
*if_guid = NULL;
|
|
1575
|
+
err = LIBUSB_ERROR_NO_MEM;
|
|
1576
|
+
goto exit;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
exit:
|
|
1580
|
+
pRegCloseKey(key);
|
|
1581
|
+
free(guid_string);
|
|
1582
|
+
return err;
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1430
1585
|
/*
|
|
1431
1586
|
* get_device_list: libusb backend device enumeration function
|
|
1432
1587
|
*/
|
|
@@ -1439,18 +1594,19 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
|
|
|
1439
1594
|
GUID hid_guid;
|
|
1440
1595
|
int r = LIBUSB_SUCCESS;
|
|
1441
1596
|
int api, sub_api;
|
|
1442
|
-
unsigned int pass, i, j;
|
|
1597
|
+
unsigned int pass, pass_type, i, j;
|
|
1443
1598
|
char enumerator[16];
|
|
1444
1599
|
char dev_id[MAX_PATH_LENGTH];
|
|
1445
1600
|
struct libusb_device *dev, *parent_dev;
|
|
1446
1601
|
struct winusb_device_priv *priv, *parent_priv;
|
|
1447
1602
|
char *dev_interface_path = NULL;
|
|
1448
1603
|
unsigned long session_id;
|
|
1449
|
-
DWORD size, port_nr,
|
|
1450
|
-
|
|
1604
|
+
DWORD size, port_nr, install_state;
|
|
1605
|
+
uint8_t bus_number = 0;
|
|
1606
|
+
#if defined(ENABLE_LOGGING)
|
|
1451
1607
|
char guid_string[MAX_GUID_STRING_LENGTH];
|
|
1608
|
+
#endif
|
|
1452
1609
|
GUID *if_guid;
|
|
1453
|
-
LONG s;
|
|
1454
1610
|
#define HUB_PASS 0
|
|
1455
1611
|
#define DEV_PASS 1
|
|
1456
1612
|
#define HCD_PASS 2
|
|
@@ -1471,14 +1627,16 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
|
|
|
1471
1627
|
libusb_device **unref_list, **new_unref_list;
|
|
1472
1628
|
unsigned int unref_size = UNREF_SIZE_STEP;
|
|
1473
1629
|
unsigned int unref_cur = 0;
|
|
1630
|
+
DWORD hub_port_nr;
|
|
1474
1631
|
|
|
1475
|
-
// PASS
|
|
1476
|
-
// PASS
|
|
1477
|
-
// PASS
|
|
1478
|
-
//
|
|
1479
|
-
//
|
|
1480
|
-
// PASS
|
|
1481
|
-
// set the device interfaces
|
|
1632
|
+
// PASS 0 : enumerate HUBs
|
|
1633
|
+
// PASS 1 : (re)enumerate master devices that have a DEVice interface
|
|
1634
|
+
// PASS 2 : (re)enumerate HCDs (allow for HCD hotplug)
|
|
1635
|
+
// PASS 3 : (re)enumerate GENeric devices (including driverless)
|
|
1636
|
+
// and list additional device interface GUIDs to explore
|
|
1637
|
+
// PASS 4 : (re)enumerate device interface GUIDs (including HID)
|
|
1638
|
+
// and set the device interfaces
|
|
1639
|
+
// PASS 5+: (re)enumerate additional EXTra GUID devices
|
|
1482
1640
|
|
|
1483
1641
|
// Init the GUID table
|
|
1484
1642
|
guid_list = malloc(guid_size * sizeof(void *));
|
|
@@ -1515,10 +1673,10 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
|
|
|
1515
1673
|
}
|
|
1516
1674
|
|
|
1517
1675
|
for (pass = 0; ((pass < nb_guids) && (r == LIBUSB_SUCCESS)); pass++) {
|
|
1518
|
-
|
|
1519
|
-
#if defined(ENABLE_LOGGING)
|
|
1676
|
+
pass_type = MIN(pass, EXT_PASS);
|
|
1677
|
+
#if defined(ENABLE_LOGGING)
|
|
1520
1678
|
const char * const passname[] = {"HUB", "DEV", "HCD", "GEN", "HID", "EXT"};
|
|
1521
|
-
usbi_dbg(ctx, "
|
|
1679
|
+
usbi_dbg(ctx, "ENUM pass %s %s", passname[pass_type], guid_to_string(guid_list[pass], guid_string));
|
|
1522
1680
|
#endif
|
|
1523
1681
|
if ((pass == HID_PASS) && (guid_list[HID_PASS] == NULL))
|
|
1524
1682
|
continue;
|
|
@@ -1536,11 +1694,6 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
|
|
|
1536
1694
|
if (r != LIBUSB_SUCCESS)
|
|
1537
1695
|
break;
|
|
1538
1696
|
|
|
1539
|
-
if ((pass == HCD_PASS) && (i == UINT8_MAX)) {
|
|
1540
|
-
usbi_warn(ctx, "program assertion failed - found more than %u buses, skipping the rest", UINT8_MAX);
|
|
1541
|
-
break;
|
|
1542
|
-
}
|
|
1543
|
-
|
|
1544
1697
|
if (pass != GEN_PASS) {
|
|
1545
1698
|
// Except for GEN, all passes deal with device interfaces
|
|
1546
1699
|
r = get_interface_details(ctx, *dev_info, &dev_info_data, guid_list[pass], &_index, &dev_interface_path);
|
|
@@ -1569,14 +1722,12 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
|
|
|
1569
1722
|
continue;
|
|
1570
1723
|
}
|
|
1571
1724
|
|
|
1572
|
-
|
|
1573
|
-
usbi_dbg(ctx, "PRO: %s", dev_id);
|
|
1574
|
-
#endif
|
|
1725
|
+
usbi_dbg(ctx, "ENUM processing %s", dev_id);
|
|
1575
1726
|
|
|
1576
1727
|
// Set API to use or get additional data from generic pass
|
|
1577
1728
|
api = USB_API_UNSUPPORTED;
|
|
1578
1729
|
sub_api = SUB_API_NOTSET;
|
|
1579
|
-
switch (
|
|
1730
|
+
switch (pass_type) {
|
|
1580
1731
|
case HCD_PASS:
|
|
1581
1732
|
break;
|
|
1582
1733
|
case HUB_PASS:
|
|
@@ -1615,68 +1766,44 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
|
|
|
1615
1766
|
usbi_info(ctx, "libusb will not be able to access it");
|
|
1616
1767
|
}
|
|
1617
1768
|
// ...and to add the additional device interface GUIDs
|
|
1618
|
-
|
|
1619
|
-
if (
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
s = pRegQueryValueExA(key, "DeviceInterfaceGUIDs", NULL, ®_type,
|
|
1625
|
-
(LPBYTE)guid_string, &size);
|
|
1626
|
-
if (s == ERROR_FILE_NOT_FOUND)
|
|
1627
|
-
s = pRegQueryValueExA(key, "DeviceInterfaceGUID", NULL, ®_type,
|
|
1628
|
-
(LPBYTE)guid_string, &size);
|
|
1629
|
-
pRegCloseKey(key);
|
|
1630
|
-
if (s == ERROR_FILE_NOT_FOUND) {
|
|
1631
|
-
break; /* no DeviceInterfaceGUID registered */
|
|
1632
|
-
} else if (s != ERROR_SUCCESS && s != ERROR_MORE_DATA) {
|
|
1633
|
-
usbi_warn(ctx, "unexpected error from pRegQueryValueExA for '%s'", dev_id);
|
|
1634
|
-
break;
|
|
1635
|
-
}
|
|
1636
|
-
// https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexa#remarks
|
|
1637
|
-
// - "string may not have been stored with the proper terminating null characters"
|
|
1638
|
-
// - "Note that REG_MULTI_SZ strings could have two terminating null characters"
|
|
1639
|
-
if ((reg_type == REG_SZ && size >= sizeof(guid_string) - sizeof(char))
|
|
1640
|
-
|| (reg_type == REG_MULTI_SZ && size >= sizeof(guid_string) - 2 * sizeof(char))) {
|
|
1641
|
-
if (nb_guids == guid_size) {
|
|
1642
|
-
new_guid_list = realloc((void *)guid_list, (guid_size + GUID_SIZE_STEP) * sizeof(void *));
|
|
1643
|
-
if (new_guid_list == NULL) {
|
|
1644
|
-
usbi_err(ctx, "failed to realloc guid list");
|
|
1645
|
-
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1646
|
-
}
|
|
1647
|
-
guid_list = new_guid_list;
|
|
1648
|
-
guid_size += GUID_SIZE_STEP;
|
|
1649
|
-
}
|
|
1650
|
-
if_guid = malloc(sizeof(*if_guid));
|
|
1651
|
-
if (if_guid == NULL) {
|
|
1652
|
-
usbi_err(ctx, "failed to alloc if_guid");
|
|
1653
|
-
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1769
|
+
r = get_guid(ctx, dev_id, dev_info, &dev_info_data, 0, &if_guid);
|
|
1770
|
+
if (r == LIBUSB_SUCCESS) {
|
|
1771
|
+
// Check if we've already seen this GUID
|
|
1772
|
+
for (j = EXT_PASS; j < nb_guids; j++) {
|
|
1773
|
+
if (memcmp(guid_list[j], if_guid, sizeof(*if_guid)) == 0)
|
|
1774
|
+
break;
|
|
1654
1775
|
}
|
|
1655
|
-
if (
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
} else {
|
|
1668
|
-
// Duplicate, ignore
|
|
1669
|
-
free(if_guid);
|
|
1776
|
+
if (j == nb_guids) {
|
|
1777
|
+
usbi_dbg(ctx, "extra GUID: %s", guid_to_string(if_guid, guid_string));
|
|
1778
|
+
// Extend the guid_list capacity if needed
|
|
1779
|
+
if (nb_guids == guid_size) {
|
|
1780
|
+
new_guid_list = realloc((void *)guid_list, (guid_size + GUID_SIZE_STEP) * sizeof(void *));
|
|
1781
|
+
if (new_guid_list == NULL) {
|
|
1782
|
+
usbi_err(ctx, "failed to realloc guid list");
|
|
1783
|
+
free(if_guid);
|
|
1784
|
+
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1785
|
+
}
|
|
1786
|
+
guid_list = new_guid_list;
|
|
1787
|
+
guid_size += GUID_SIZE_STEP;
|
|
1670
1788
|
}
|
|
1789
|
+
guid_list[nb_guids++] = if_guid;
|
|
1790
|
+
} else {
|
|
1791
|
+
// Duplicate, ignore
|
|
1792
|
+
free(if_guid);
|
|
1671
1793
|
}
|
|
1794
|
+
} else if (r == LIBUSB_ERROR_ACCESS) {
|
|
1795
|
+
r = LIBUSB_SUCCESS;
|
|
1796
|
+
} else if (r == LIBUSB_ERROR_NO_MEM) {
|
|
1797
|
+
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1672
1798
|
} else {
|
|
1673
|
-
usbi_warn(ctx, "unexpected
|
|
1799
|
+
usbi_warn(ctx, "unexpected error during getting DeviceInterfaceGUID for '%s'", dev_id);
|
|
1674
1800
|
}
|
|
1675
1801
|
break;
|
|
1676
1802
|
case HID_PASS:
|
|
1677
1803
|
api = USB_API_HID;
|
|
1678
1804
|
break;
|
|
1679
|
-
|
|
1805
|
+
case DEV_PASS:
|
|
1806
|
+
case EXT_PASS:
|
|
1680
1807
|
// Get the API type (after checking that the driver installation is OK)
|
|
1681
1808
|
if ((!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_INSTALL_STATE,
|
|
1682
1809
|
NULL, (PBYTE)&install_state, sizeof(install_state), &size)) || (size != sizeof(install_state))) {
|
|
@@ -1689,6 +1816,8 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
|
|
|
1689
1816
|
}
|
|
1690
1817
|
get_api_type(dev_info, &dev_info_data, &api, &sub_api);
|
|
1691
1818
|
break;
|
|
1819
|
+
default:
|
|
1820
|
+
assert(false); // unreachable since all pass types covered explicitly
|
|
1692
1821
|
}
|
|
1693
1822
|
|
|
1694
1823
|
// Find parent device (for the passes that need it)
|
|
@@ -1768,7 +1897,7 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
|
|
|
1768
1897
|
}
|
|
1769
1898
|
|
|
1770
1899
|
// Setup device
|
|
1771
|
-
switch (
|
|
1900
|
+
switch (pass_type) {
|
|
1772
1901
|
case HUB_PASS:
|
|
1773
1902
|
case DEV_PASS:
|
|
1774
1903
|
// If the device has already been setup, don't do it again
|
|
@@ -1781,7 +1910,22 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
|
|
|
1781
1910
|
priv->sub_api = sub_api;
|
|
1782
1911
|
switch (api) {
|
|
1783
1912
|
case USB_API_COMPOSITE:
|
|
1913
|
+
break;
|
|
1784
1914
|
case USB_API_HUB:
|
|
1915
|
+
parent_dev = get_ancestor(ctx, dev_info_data.DevInst, NULL);
|
|
1916
|
+
if (parent_dev == NULL) {
|
|
1917
|
+
if (!get_dev_port_number(*dev_info, &dev_info_data, &hub_port_nr) || hub_port_nr == 0) {
|
|
1918
|
+
if (bus_number == UINT8_MAX) {
|
|
1919
|
+
usbi_warn(ctx, "program assertion failed - found more than %u buses, skipping the rest", UINT8_MAX);
|
|
1920
|
+
break;
|
|
1921
|
+
}
|
|
1922
|
+
priv->root_hub = true;
|
|
1923
|
+
dev->bus_number = ++bus_number;
|
|
1924
|
+
usbi_dbg(ctx, "assigning Root Hub '%s' bus number %u", dev_id, bus_number);
|
|
1925
|
+
}
|
|
1926
|
+
} else {
|
|
1927
|
+
libusb_unref_device(parent_dev);
|
|
1928
|
+
}
|
|
1785
1929
|
break;
|
|
1786
1930
|
case USB_API_HID:
|
|
1787
1931
|
priv->hid = calloc(1, sizeof(struct hid_device_priv));
|
|
@@ -1801,7 +1945,7 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
|
|
|
1801
1945
|
}
|
|
1802
1946
|
break;
|
|
1803
1947
|
case HCD_PASS:
|
|
1804
|
-
r = enumerate_hcd_root_hub(ctx, dev_id,
|
|
1948
|
+
r = enumerate_hcd_root_hub(ctx, dev_id, dev_info_data.DevInst);
|
|
1805
1949
|
break;
|
|
1806
1950
|
case GEN_PASS:
|
|
1807
1951
|
port_nr = 0;
|
|
@@ -1822,7 +1966,8 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
|
|
|
1822
1966
|
r = LIBUSB_SUCCESS;
|
|
1823
1967
|
}
|
|
1824
1968
|
break;
|
|
1825
|
-
|
|
1969
|
+
case HID_PASS:
|
|
1970
|
+
case EXT_PASS:
|
|
1826
1971
|
if (parent_priv->apib->id == USB_API_HID || parent_priv->apib->id == USB_API_COMPOSITE) {
|
|
1827
1972
|
if (parent_priv->apib->id == USB_API_HID) {
|
|
1828
1973
|
usbi_dbg(ctx, "setting HID interface for [%lX]:", parent_dev->session_data);
|
|
@@ -1846,6 +1991,8 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
|
|
|
1846
1991
|
}
|
|
1847
1992
|
libusb_unref_device(parent_dev);
|
|
1848
1993
|
break;
|
|
1994
|
+
default:
|
|
1995
|
+
assert(false); // unreachable since all pass types covered explicitly
|
|
1849
1996
|
}
|
|
1850
1997
|
}
|
|
1851
1998
|
}
|
|
@@ -2152,7 +2299,10 @@ const struct windows_backend winusb_backend = {
|
|
|
2152
2299
|
* USB API backends
|
|
2153
2300
|
*/
|
|
2154
2301
|
|
|
2155
|
-
static const char * const composite_driver_names[] = {
|
|
2302
|
+
static const char * const composite_driver_names[] = {
|
|
2303
|
+
"USBCCGP", // (Windows built-in) USB Composite Device
|
|
2304
|
+
"dg_ssudbus" // SAMSUNG Mobile USB Composite Device
|
|
2305
|
+
};
|
|
2156
2306
|
static const char * const winusbx_driver_names[] = {"libusbK", "libusb0", "WinUSB"};
|
|
2157
2307
|
static const char * const hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"};
|
|
2158
2308
|
const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
|
|
@@ -2301,6 +2451,7 @@ static bool winusbx_init(struct libusb_context *ctx)
|
|
|
2301
2451
|
WinUSB_Set(hWinUSB, ResetPipe, true);
|
|
2302
2452
|
WinUSB_Set(hWinUSB, SetCurrentAlternateSetting, true);
|
|
2303
2453
|
WinUSB_Set(hWinUSB, SetPipePolicy, true);
|
|
2454
|
+
WinUSB_Set(hWinUSB, GetPipePolicy, true);
|
|
2304
2455
|
WinUSB_Set(hWinUSB, WritePipe, true);
|
|
2305
2456
|
|
|
2306
2457
|
// Check for isochronous transfers support (available starting with Windows 8.1)
|
|
@@ -2463,7 +2614,7 @@ static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle)
|
|
|
2463
2614
|
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
2464
2615
|
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2465
2616
|
HANDLE handle;
|
|
2466
|
-
int i;
|
|
2617
|
+
int i, ai;
|
|
2467
2618
|
|
|
2468
2619
|
if (sub_api == SUB_API_NOTSET)
|
|
2469
2620
|
sub_api = priv->sub_api;
|
|
@@ -2472,17 +2623,41 @@ static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle)
|
|
|
2472
2623
|
return;
|
|
2473
2624
|
|
|
2474
2625
|
if (priv->apib->id == USB_API_COMPOSITE) {
|
|
2475
|
-
// If this is a composite device, just free and close
|
|
2476
|
-
// interfaces
|
|
2626
|
+
// If this is a composite device, just free and close any WinUSB-like
|
|
2627
|
+
// interfaces that are not part of an associated group
|
|
2628
|
+
// (each is independent and not associated with another).
|
|
2629
|
+
// For associated interface groupings, free interfaces that
|
|
2630
|
+
// are NOT the first within that group (i.e. not bFirstInterface),
|
|
2631
|
+
// then free & close bFirstInterface last.
|
|
2477
2632
|
for (i = 0; i < USB_MAXINTERFACES; i++) {
|
|
2478
2633
|
if (priv->usb_interface[i].apib->id == USB_API_WINUSBX) {
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2634
|
+
if (priv->usb_interface[i].num_associated_interfaces == 0) {
|
|
2635
|
+
handle = handle_priv->interface_handle[i].api_handle;
|
|
2636
|
+
if (HANDLE_VALID(handle))
|
|
2637
|
+
WinUSBX[sub_api].Free(handle);
|
|
2638
|
+
|
|
2639
|
+
handle = handle_priv->interface_handle[i].dev_handle;
|
|
2640
|
+
if (HANDLE_VALID(handle))
|
|
2641
|
+
CloseHandle(handle);
|
|
2642
|
+
} else {
|
|
2643
|
+
if (i==priv->usb_interface[i].first_associated_interface) {
|
|
2644
|
+
//first free all handles for all *other* associated interfaces
|
|
2645
|
+
for (ai = 1; ai < priv->usb_interface[i].num_associated_interfaces; ai++) {
|
|
2646
|
+
handle = handle_priv->interface_handle[i + ai].api_handle;
|
|
2647
|
+
if (HANDLE_VALID(handle))
|
|
2648
|
+
WinUSBX[sub_api].Free(handle);
|
|
2649
|
+
}
|
|
2650
|
+
|
|
2651
|
+
//free & close bFirstInterface
|
|
2652
|
+
handle = handle_priv->interface_handle[i].api_handle;
|
|
2653
|
+
if (HANDLE_VALID(handle))
|
|
2654
|
+
WinUSBX[sub_api].Free(handle);
|
|
2482
2655
|
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2656
|
+
handle = handle_priv->interface_handle[i].dev_handle;
|
|
2657
|
+
if (HANDLE_VALID(handle))
|
|
2658
|
+
CloseHandle(handle);
|
|
2659
|
+
}
|
|
2660
|
+
}
|
|
2486
2661
|
}
|
|
2487
2662
|
}
|
|
2488
2663
|
} else {
|
|
@@ -2563,6 +2738,7 @@ static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev
|
|
|
2563
2738
|
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
2564
2739
|
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2565
2740
|
bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE);
|
|
2741
|
+
bool is_associated_interface = (priv->usb_interface[iface].num_associated_interfaces != 0);
|
|
2566
2742
|
HDEVINFO dev_info;
|
|
2567
2743
|
char *dev_interface_path = NULL;
|
|
2568
2744
|
char *dev_interface_path_guid_start;
|
|
@@ -2571,12 +2747,18 @@ static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev
|
|
|
2571
2747
|
HANDLE file_handle, winusb_handle;
|
|
2572
2748
|
DWORD err, _index;
|
|
2573
2749
|
int r;
|
|
2750
|
+
uint8_t initialized_iface;
|
|
2574
2751
|
|
|
2575
2752
|
CHECK_WINUSBX_AVAILABLE(sub_api);
|
|
2576
2753
|
|
|
2577
2754
|
// If the device is composite, but using the default Windows composite parent driver (usbccgp)
|
|
2578
2755
|
// or if it's the first WinUSB-like interface, we get a handle through Initialize().
|
|
2579
|
-
|
|
2756
|
+
// If it's an associated interface, and is the first one (iface==bFirstInterface), we also
|
|
2757
|
+
// want to get the handle through Initialize(). If it's an associated interface, and NOT
|
|
2758
|
+
// the first one, we want to direct control to the 'else' where the handle will be obtained
|
|
2759
|
+
// via GetAssociatedInterface().
|
|
2760
|
+
if (((is_using_usbccgp) || (iface == 0)) &&
|
|
2761
|
+
(!is_associated_interface || (iface==priv->usb_interface[iface].first_associated_interface))) {
|
|
2580
2762
|
// composite device (independent interfaces) or interface 0
|
|
2581
2763
|
file_handle = handle_priv->interface_handle[iface].dev_handle;
|
|
2582
2764
|
if (!HANDLE_VALID(file_handle))
|
|
@@ -2637,21 +2819,32 @@ static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev
|
|
|
2637
2819
|
}
|
|
2638
2820
|
handle_priv->interface_handle[iface].api_handle = winusb_handle;
|
|
2639
2821
|
} else {
|
|
2822
|
+
if (is_associated_interface) {
|
|
2823
|
+
initialized_iface = priv->usb_interface[iface].first_associated_interface;
|
|
2824
|
+
if (iface <= initialized_iface) {
|
|
2825
|
+
usbi_err(ctx, "invalid associated index. iface=%u, initialized iface=%u", iface, initialized_iface);
|
|
2826
|
+
return LIBUSB_ERROR_NOT_FOUND;
|
|
2827
|
+
}
|
|
2828
|
+
} else {
|
|
2829
|
+
initialized_iface = 0;
|
|
2830
|
+
}
|
|
2831
|
+
|
|
2640
2832
|
// For all other interfaces, use GetAssociatedInterface()
|
|
2641
|
-
winusb_handle = handle_priv->interface_handle[
|
|
2833
|
+
winusb_handle = handle_priv->interface_handle[initialized_iface].api_handle;
|
|
2642
2834
|
// It is a requirement for multiple interface devices on Windows that, to you
|
|
2643
2835
|
// must first claim the first interface before you claim the others
|
|
2644
2836
|
if (!HANDLE_VALID(winusb_handle)) {
|
|
2645
|
-
file_handle = handle_priv->interface_handle[
|
|
2837
|
+
file_handle = handle_priv->interface_handle[initialized_iface].dev_handle;
|
|
2646
2838
|
if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
|
|
2647
|
-
handle_priv->interface_handle[
|
|
2648
|
-
usbi_warn(ctx, "auto-claimed interface
|
|
2839
|
+
handle_priv->interface_handle[initialized_iface].api_handle = winusb_handle;
|
|
2840
|
+
usbi_warn(ctx, "auto-claimed interface %u (required to claim %u with WinUSB)", initialized_iface, iface);
|
|
2649
2841
|
} else {
|
|
2650
|
-
usbi_warn(ctx, "failed to auto-claim interface
|
|
2842
|
+
usbi_warn(ctx, "failed to auto-claim interface %u (required to claim %u with WinUSB): %s",
|
|
2843
|
+
initialized_iface, iface, windows_error_str(0));
|
|
2651
2844
|
return LIBUSB_ERROR_ACCESS;
|
|
2652
2845
|
}
|
|
2653
2846
|
}
|
|
2654
|
-
if (!WinUSBX[sub_api].GetAssociatedInterface(winusb_handle, (UCHAR)(iface - 1),
|
|
2847
|
+
if (!WinUSBX[sub_api].GetAssociatedInterface(winusb_handle, (UCHAR)(iface - 1 - initialized_iface),
|
|
2655
2848
|
&handle_priv->interface_handle[iface].api_handle)) {
|
|
2656
2849
|
handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
|
|
2657
2850
|
switch (GetLastError()) {
|
|
@@ -2666,7 +2859,7 @@ static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev
|
|
|
2666
2859
|
return LIBUSB_ERROR_ACCESS;
|
|
2667
2860
|
}
|
|
2668
2861
|
}
|
|
2669
|
-
handle_priv->interface_handle[iface].dev_handle = handle_priv->interface_handle[
|
|
2862
|
+
handle_priv->interface_handle[iface].dev_handle = handle_priv->interface_handle[initialized_iface].dev_handle;
|
|
2670
2863
|
}
|
|
2671
2864
|
usbi_dbg(ctx, "claimed interface %u", iface);
|
|
2672
2865
|
handle_priv->active_interface = iface;
|
|
@@ -2849,7 +3042,7 @@ static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_ha
|
|
|
2849
3042
|
static void WINAPI winusbx_native_iso_transfer_continue_stream_callback(struct libusb_transfer *transfer)
|
|
2850
3043
|
{
|
|
2851
3044
|
// If this callback is invoked, this means that we attempted to set ContinueStream
|
|
2852
|
-
// to TRUE when calling Read/WriteIsochPipeAsap in
|
|
3045
|
+
// to TRUE when calling Read/WriteIsochPipeAsap in winusbx_submit_iso_transfer().
|
|
2853
3046
|
// The role of this callback is to fallback to ContinueStream = FALSE if the transfer
|
|
2854
3047
|
// did not succeed.
|
|
2855
3048
|
|
|
@@ -3252,8 +3445,7 @@ static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struc
|
|
|
3252
3445
|
// Copy the requested value back for consistency with other platforms.
|
|
3253
3446
|
transfer->iso_packet_desc[i].actual_length = transfer->iso_packet_desc[i].length;
|
|
3254
3447
|
}
|
|
3255
|
-
|
|
3256
|
-
//transfer->iso_packet_desc[i].status = transfer_priv->iso_context->IsoPackets[i].status;
|
|
3448
|
+
transfer->iso_packet_desc[i].status = usbd_status_to_libusb_transfer_status(iso_context->IsoPackets[i].status);
|
|
3257
3449
|
}
|
|
3258
3450
|
} else if (sub_api == SUB_API_WINUSB) {
|
|
3259
3451
|
if (IS_XFERIN(transfer)) {
|