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.
Files changed (222) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +1 -1
  3. package/dist/index.js +6 -2
  4. package/dist/index.js.map +1 -1
  5. package/dist/usb/bindings.js +1 -1
  6. package/dist/usb/bindings.js.map +1 -1
  7. package/dist/usb/capability.js.map +1 -1
  8. package/dist/usb/device.js.map +1 -1
  9. package/dist/usb/endpoint.d.ts +1 -0
  10. package/dist/usb/endpoint.js +2 -2
  11. package/dist/usb/endpoint.js.map +1 -1
  12. package/dist/usb/index.js.map +1 -1
  13. package/dist/usb/interface.js +2 -2
  14. package/dist/usb/interface.js.map +1 -1
  15. package/dist/webusb/index.d.ts +2 -2
  16. package/dist/webusb/index.js.map +1 -1
  17. package/dist/webusb/webusb-device.js +10 -10
  18. package/dist/webusb/webusb-device.js.map +1 -1
  19. package/libusb/.codespellrc +3 -0
  20. package/libusb/.private/appveyor_build.sh +5 -1
  21. package/libusb/.private/ci-build.sh +26 -1
  22. package/libusb/.private/ci-container-build.sh +2 -5
  23. package/libusb/.private/wbs.txt +5 -8
  24. package/libusb/AUTHORS +22 -0
  25. package/libusb/ChangeLog +19 -2
  26. package/libusb/HACKING +25 -0
  27. package/libusb/INSTALL_WIN.txt +11 -10
  28. package/libusb/NEWS +2 -2
  29. package/libusb/README +3 -2
  30. package/libusb/README.git +1 -1
  31. package/libusb/Xcode/common.xcconfig +8 -1
  32. package/libusb/Xcode/config.h +0 -6
  33. package/libusb/Xcode/debug.xcconfig +4 -1
  34. package/libusb/Xcode/libusb.xcconfig +1 -1
  35. package/libusb/Xcode/libusb.xcodeproj/project.pbxproj +60 -30
  36. package/libusb/Xcode/libusb_debug.xcconfig +1 -1
  37. package/libusb/Xcode/libusb_release.xcconfig +1 -1
  38. package/libusb/Xcode/release.xcconfig +1 -1
  39. package/libusb/appveyor.yml +33 -9
  40. package/libusb/configure.ac +68 -37
  41. package/libusb/examples/dpfp.c +2 -2
  42. package/libusb/examples/fxload.c +2 -2
  43. package/libusb/examples/hotplugtest.c +28 -13
  44. package/libusb/examples/listdevs.c +1 -1
  45. package/libusb/examples/sam3u_benchmark.c +1 -1
  46. package/libusb/examples/testlibusb.c +1 -1
  47. package/libusb/examples/xusb.c +74 -19
  48. package/libusb/libusb/Makefile.am +11 -1
  49. package/libusb/libusb/core.c +364 -186
  50. package/libusb/libusb/descriptor.c +276 -16
  51. package/libusb/libusb/hotplug.c +5 -4
  52. package/libusb/libusb/io.c +72 -61
  53. package/libusb/libusb/libusb-1.0.def +14 -1
  54. package/libusb/libusb/libusb.h +245 -76
  55. package/libusb/libusb/libusbi.h +35 -13
  56. package/libusb/libusb/os/darwin_usb.c +542 -279
  57. package/libusb/libusb/os/darwin_usb.h +44 -115
  58. package/libusb/libusb/os/emscripten_webusb.cpp +870 -0
  59. package/libusb/libusb/os/events_posix.c +40 -0
  60. package/libusb/libusb/os/events_posix.h +3 -0
  61. package/libusb/libusb/os/linux_usbfs.c +27 -16
  62. package/libusb/libusb/os/netbsd_usb.c +36 -36
  63. package/libusb/libusb/os/openbsd_usb.c +34 -34
  64. package/libusb/libusb/os/sunos_usb.c +25 -15
  65. package/libusb/libusb/os/threads_posix.c +1 -5
  66. package/libusb/libusb/os/windows_common.c +13 -5
  67. package/libusb/libusb/os/windows_common.h +8 -0
  68. package/libusb/libusb/os/windows_winusb.c +366 -174
  69. package/libusb/libusb/os/windows_winusb.h +13 -9
  70. package/libusb/libusb/strerror.c +5 -5
  71. package/libusb/libusb/sync.c +24 -19
  72. package/libusb/libusb/version.h +1 -1
  73. package/libusb/libusb/version_nano.h +1 -1
  74. package/libusb/msvc/Base.props +60 -0
  75. package/libusb/msvc/Configuration.Application.props +7 -0
  76. package/libusb/msvc/Configuration.Base.props +47 -0
  77. package/libusb/msvc/Configuration.DynamicLibrary.props +21 -0
  78. package/libusb/msvc/Configuration.StaticLibrary.props +7 -0
  79. package/libusb/msvc/ProjectConfigurations.Base.props +69 -0
  80. package/libusb/msvc/build_all.ps1 +17 -0
  81. package/libusb/msvc/config.h +2 -2
  82. package/libusb/msvc/dpfp.vcxproj +33 -0
  83. package/libusb/msvc/dpfp_threaded.vcxproj +38 -0
  84. package/libusb/msvc/fxload.vcxproj +46 -0
  85. package/libusb/msvc/getopt.vcxproj +33 -0
  86. package/libusb/msvc/hotplugtest.vcxproj +32 -0
  87. package/libusb/msvc/init_context.vcxproj +35 -0
  88. package/libusb/msvc/libusb.sln +542 -0
  89. package/libusb/msvc/libusb_dll.vcxproj +61 -0
  90. package/libusb/msvc/libusb_static.vcxproj +49 -0
  91. package/libusb/msvc/listdevs.vcxproj +32 -0
  92. package/libusb/msvc/sam3u_benchmark.vcxproj +33 -0
  93. package/libusb/msvc/set_option.vcxproj +35 -0
  94. package/libusb/msvc/stress.vcxproj +35 -0
  95. package/libusb/msvc/stress_mt.vcxproj +33 -0
  96. package/libusb/msvc/testlibusb.vcxproj +32 -0
  97. package/libusb/msvc/xusb.vcxproj +38 -0
  98. package/libusb/tests/Makefile.am +25 -3
  99. package/libusb/tests/init_context.c +153 -0
  100. package/libusb/tests/macos.c +130 -0
  101. package/libusb/tests/set_option.c +253 -0
  102. package/libusb/tests/stress.c +17 -14
  103. package/libusb/tests/stress_mt.c +265 -0
  104. package/libusb/tests/testlib.c +1 -1
  105. package/libusb/tests/umockdev.c +9 -9
  106. package/libusb/tests/webusb-test-shim/index.js +12 -0
  107. package/libusb/tests/webusb-test-shim/package-lock.json +50 -0
  108. package/libusb/tests/webusb-test-shim/package.json +10 -0
  109. package/package.json +7 -7
  110. package/prebuilds/android-arm/node.napi.armv7.node +0 -0
  111. package/prebuilds/android-arm64/node.napi.armv8.node +0 -0
  112. package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
  113. package/prebuilds/linux-arm/node.napi.armv6.node +0 -0
  114. package/prebuilds/linux-arm/node.napi.armv7.node +0 -0
  115. package/prebuilds/linux-arm64/node.napi.armv8.node +0 -0
  116. package/prebuilds/linux-ia32/node.napi.node +0 -0
  117. package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
  118. package/prebuilds/linux-x64/node.napi.musl.node +0 -0
  119. package/prebuilds/win32-arm64/node.napi.node +0 -0
  120. package/prebuilds/win32-ia32/node.napi.node +0 -0
  121. package/prebuilds/win32-x64/node.napi.node +0 -0
  122. package/src/device.cc +15 -5
  123. package/libusb/msvc/dpfp_2013.vcxproj +0 -87
  124. package/libusb/msvc/dpfp_2013.vcxproj.filters +0 -26
  125. package/libusb/msvc/dpfp_2015.vcxproj +0 -87
  126. package/libusb/msvc/dpfp_2015.vcxproj.filters +0 -26
  127. package/libusb/msvc/dpfp_2017.vcxproj +0 -106
  128. package/libusb/msvc/dpfp_2017.vcxproj.filters +0 -26
  129. package/libusb/msvc/dpfp_2019.vcxproj +0 -106
  130. package/libusb/msvc/dpfp_2019.vcxproj.filters +0 -26
  131. package/libusb/msvc/dpfp_threaded_2013.vcxproj +0 -87
  132. package/libusb/msvc/dpfp_threaded_2013.vcxproj.filters +0 -26
  133. package/libusb/msvc/dpfp_threaded_2015.vcxproj +0 -87
  134. package/libusb/msvc/dpfp_threaded_2015.vcxproj.filters +0 -26
  135. package/libusb/msvc/dpfp_threaded_2017.vcxproj +0 -106
  136. package/libusb/msvc/dpfp_threaded_2017.vcxproj.filters +0 -26
  137. package/libusb/msvc/dpfp_threaded_2019.vcxproj +0 -106
  138. package/libusb/msvc/dpfp_threaded_2019.vcxproj.filters +0 -26
  139. package/libusb/msvc/fxload_2013.vcxproj +0 -94
  140. package/libusb/msvc/fxload_2013.vcxproj.filters +0 -35
  141. package/libusb/msvc/fxload_2015.vcxproj +0 -94
  142. package/libusb/msvc/fxload_2015.vcxproj.filters +0 -35
  143. package/libusb/msvc/fxload_2017.vcxproj +0 -113
  144. package/libusb/msvc/fxload_2017.vcxproj.filters +0 -35
  145. package/libusb/msvc/fxload_2019.vcxproj +0 -113
  146. package/libusb/msvc/fxload_2019.vcxproj.filters +0 -35
  147. package/libusb/msvc/getopt_2013.vcxproj +0 -72
  148. package/libusb/msvc/getopt_2013.vcxproj.filters +0 -26
  149. package/libusb/msvc/getopt_2015.vcxproj +0 -73
  150. package/libusb/msvc/getopt_2015.vcxproj.filters +0 -26
  151. package/libusb/msvc/getopt_2017.vcxproj +0 -92
  152. package/libusb/msvc/getopt_2017.vcxproj.filters +0 -26
  153. package/libusb/msvc/getopt_2019.vcxproj +0 -92
  154. package/libusb/msvc/getopt_2019.vcxproj.filters +0 -26
  155. package/libusb/msvc/hotplugtest_2013.vcxproj +0 -86
  156. package/libusb/msvc/hotplugtest_2013.vcxproj.filters +0 -23
  157. package/libusb/msvc/hotplugtest_2015.vcxproj +0 -86
  158. package/libusb/msvc/hotplugtest_2015.vcxproj.filters +0 -23
  159. package/libusb/msvc/hotplugtest_2017.vcxproj +0 -105
  160. package/libusb/msvc/hotplugtest_2017.vcxproj.filters +0 -23
  161. package/libusb/msvc/hotplugtest_2019.vcxproj +0 -105
  162. package/libusb/msvc/hotplugtest_2019.vcxproj.filters +0 -23
  163. package/libusb/msvc/libusb_2013.sln +0 -137
  164. package/libusb/msvc/libusb_2015.sln +0 -137
  165. package/libusb/msvc/libusb_2017.sln +0 -240
  166. package/libusb/msvc/libusb_2019.sln +0 -240
  167. package/libusb/msvc/libusb_dll_2013.vcxproj +0 -104
  168. package/libusb/msvc/libusb_dll_2013.vcxproj.filters +0 -94
  169. package/libusb/msvc/libusb_dll_2015.vcxproj +0 -105
  170. package/libusb/msvc/libusb_dll_2015.vcxproj.filters +0 -94
  171. package/libusb/msvc/libusb_dll_2017.vcxproj +0 -124
  172. package/libusb/msvc/libusb_dll_2017.vcxproj.filters +0 -94
  173. package/libusb/msvc/libusb_dll_2019.vcxproj +0 -124
  174. package/libusb/msvc/libusb_dll_2019.vcxproj.filters +0 -94
  175. package/libusb/msvc/libusb_static_2013.vcxproj +0 -94
  176. package/libusb/msvc/libusb_static_2013.vcxproj.filters +0 -80
  177. package/libusb/msvc/libusb_static_2015.vcxproj +0 -95
  178. package/libusb/msvc/libusb_static_2015.vcxproj.filters +0 -80
  179. package/libusb/msvc/libusb_static_2017.vcxproj +0 -114
  180. package/libusb/msvc/libusb_static_2017.vcxproj.filters +0 -80
  181. package/libusb/msvc/libusb_static_2019.vcxproj +0 -114
  182. package/libusb/msvc/libusb_static_2019.vcxproj.filters +0 -80
  183. package/libusb/msvc/listdevs_2013.vcxproj +0 -86
  184. package/libusb/msvc/listdevs_2013.vcxproj.filters +0 -23
  185. package/libusb/msvc/listdevs_2015.vcxproj +0 -86
  186. package/libusb/msvc/listdevs_2015.vcxproj.filters +0 -23
  187. package/libusb/msvc/listdevs_2017.vcxproj +0 -105
  188. package/libusb/msvc/listdevs_2017.vcxproj.filters +0 -23
  189. package/libusb/msvc/listdevs_2019.vcxproj +0 -105
  190. package/libusb/msvc/listdevs_2019.vcxproj.filters +0 -23
  191. package/libusb/msvc/sam3u_benchmark_2013.vcxproj +0 -87
  192. package/libusb/msvc/sam3u_benchmark_2013.vcxproj.filters +0 -26
  193. package/libusb/msvc/sam3u_benchmark_2015.vcxproj +0 -87
  194. package/libusb/msvc/sam3u_benchmark_2015.vcxproj.filters +0 -26
  195. package/libusb/msvc/sam3u_benchmark_2017.vcxproj +0 -106
  196. package/libusb/msvc/sam3u_benchmark_2017.vcxproj.filters +0 -26
  197. package/libusb/msvc/sam3u_benchmark_2019.vcxproj +0 -106
  198. package/libusb/msvc/sam3u_benchmark_2019.vcxproj.filters +0 -26
  199. package/libusb/msvc/stress_2013.vcxproj +0 -89
  200. package/libusb/msvc/stress_2013.vcxproj.filters +0 -32
  201. package/libusb/msvc/stress_2015.vcxproj +0 -89
  202. package/libusb/msvc/stress_2015.vcxproj.filters +0 -32
  203. package/libusb/msvc/stress_2017.vcxproj +0 -108
  204. package/libusb/msvc/stress_2017.vcxproj.filters +0 -32
  205. package/libusb/msvc/stress_2019.vcxproj +0 -108
  206. package/libusb/msvc/stress_2019.vcxproj.filters +0 -32
  207. package/libusb/msvc/testlibusb_2013.vcxproj +0 -86
  208. package/libusb/msvc/testlibusb_2013.vcxproj.filters +0 -23
  209. package/libusb/msvc/testlibusb_2015.vcxproj +0 -86
  210. package/libusb/msvc/testlibusb_2015.vcxproj.filters +0 -23
  211. package/libusb/msvc/testlibusb_2017.vcxproj +0 -105
  212. package/libusb/msvc/testlibusb_2017.vcxproj.filters +0 -23
  213. package/libusb/msvc/testlibusb_2019.vcxproj +0 -105
  214. package/libusb/msvc/testlibusb_2019.vcxproj.filters +0 -23
  215. package/libusb/msvc/xusb_2013.vcxproj +0 -86
  216. package/libusb/msvc/xusb_2013.vcxproj.filters +0 -23
  217. package/libusb/msvc/xusb_2015.vcxproj +0 -86
  218. package/libusb/msvc/xusb_2015.vcxproj.filters +0 -23
  219. package/libusb/msvc/xusb_2017.vcxproj +0 -105
  220. package/libusb/msvc/xusb_2017.vcxproj.filters +0 -23
  221. package/libusb/msvc/xusb_2019.vcxproj +0 -105
  222. 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
- if (iface >= conf_desc->bNumInterfaces) {
527
- usbi_err(HANDLE_CTX(dev_handle), "interface %d out of range for device", iface);
528
- return LIBUSB_ERROR_NOT_FOUND;
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
- if_desc = &conf_desc->interface[iface].altsetting[altsetting];
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
- libusb_free_config_descriptor(conf_desc);
539
- return LIBUSB_ERROR_NO_MEM;
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
- if (conn_info.ConnectionStatus == NoDeviceConnected) {
1128
- usbi_err(ctx, "device '%s' is no longer connected!", priv->dev_id);
1129
- CloseHandle(hub_handle);
1130
- return LIBUSB_ERROR_NO_DEVICE;
1131
- }
1132
-
1133
- if ((conn_info.DeviceDescriptor.bLength != LIBUSB_DT_DEVICE_SIZE)
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
- static_assert(sizeof(dev->device_descriptor) == sizeof(conn_info.DeviceDescriptor),
1140
- "mismatch between libusb and OS device descriptor sizes");
1141
- memcpy(&dev->device_descriptor, &conn_info.DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
1142
- usbi_localize_device_descriptor(&dev->device_descriptor);
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
- || (conn_info.DeviceDescriptor.bDescriptorType != LIBUSB_DT_DEVICE)) {
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
- if (priv->active_config == 0) {
1162
- usbi_info(ctx, "0x%x:0x%x found %u configurations but device isn't configured, "
1163
- "forcing current configuration to 1",
1164
- dev->device_descriptor.idVendor,
1165
- dev->device_descriptor.idProduct,
1166
- dev->device_descriptor.bNumConfigurations);
1167
- priv->active_config = 1;
1168
- } else {
1169
- usbi_dbg(ctx, "found %u configurations (current config: %u)", dev->device_descriptor.bNumConfigurations, priv->active_config);
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
- uint8_t bus_number, DEVINST devinst)
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
- session_id = (unsigned long)child_devinst;
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
- usbi_err(ctx, "program assertion failed - HCD '%s' child not found", dev_id);
1282
+ usbi_warn(ctx, "HCD '%s' child not found", dev_id);
1284
1283
  return LIBUSB_SUCCESS;
1285
1284
  }
1286
1285
 
1287
- if (dev->bus_number == 0) {
1288
- // Only do this once
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
- if ((mi_str != NULL) && isdigit((unsigned char)mi_str[3]) && isdigit((unsigned char)mi_str[4])) {
1367
- interface_number = ((mi_str[3] - '0') * 10) + (mi_str[4] - '0');
1368
- } else {
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, &reg_type,
1487
+ (LPBYTE)guid_string, &size);
1488
+ if (s == ERROR_FILE_NOT_FOUND)
1489
+ s = pRegQueryValueExA(key, "DeviceInterfaceGUID", NULL, &reg_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, reg_type, install_state;
1450
- HKEY key;
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 1 : (re)enumerate HCDs (allows for HCD hotplug)
1476
- // PASS 2 : (re)enumerate HUBS
1477
- // PASS 3 : (re)enumerate generic USB devices (including driverless)
1478
- // and list additional USB device interface GUIDs to explore
1479
- // PASS 4 : (re)enumerate master USB devices that have a device interface
1480
- // PASS 5+: (re)enumerate device interfaced GUIDs (including HID) and
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
- //#define ENUM_DEBUG
1519
- #if defined(ENABLE_LOGGING) && defined(ENUM_DEBUG)
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, "#### PROCESSING %ss %s", passname[MIN(pass, EXT_PASS)], guid_to_string(guid_list[pass], guid_string));
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
- #ifdef ENUM_DEBUG
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 (pass) {
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
- key = pSetupDiOpenDevRegKey(*dev_info, &dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
1619
- if (key == INVALID_HANDLE_VALUE)
1620
- break;
1621
- // Look for both DeviceInterfaceGUIDs *and* DeviceInterfaceGUID, in that order
1622
- // If multiple GUIDs just process the first and ignore the others
1623
- size = sizeof(guid_string);
1624
- s = pRegQueryValueExA(key, "DeviceInterfaceGUIDs", NULL, &reg_type,
1625
- (LPBYTE)guid_string, &size);
1626
- if (s == ERROR_FILE_NOT_FOUND)
1627
- s = pRegQueryValueExA(key, "DeviceInterfaceGUID", NULL, &reg_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 (!string_to_guid(guid_string, if_guid)) {
1656
- usbi_warn(ctx, "device '%s' has malformed DeviceInterfaceGUID string '%s', skipping", dev_id, guid_string);
1657
- free(if_guid);
1658
- } else {
1659
- // Check if we've already seen this GUID
1660
- for (j = EXT_PASS; j < nb_guids; j++) {
1661
- if (memcmp(guid_list[j], if_guid, sizeof(*if_guid)) == 0)
1662
- break;
1663
- }
1664
- if (j == nb_guids) {
1665
- usbi_dbg(ctx, "extra GUID: %s", guid_string);
1666
- guid_list[nb_guids++] = if_guid;
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 type/size of DeviceInterfaceGUID for '%s'", dev_id);
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
- default:
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 (pass) {
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, (uint8_t)(i + 1), dev_info_data.DevInst);
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
- default: // HID_PASS and later
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[] = {"USBCCGP"};
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 all WinUSB-like
2476
- // interfaces directly (each is independent and not associated with another)
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
- handle = handle_priv->interface_handle[i].api_handle;
2480
- if (HANDLE_VALID(handle))
2481
- WinUSBX[sub_api].Free(handle);
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
- handle = handle_priv->interface_handle[i].dev_handle;
2484
- if (HANDLE_VALID(handle))
2485
- CloseHandle(handle);
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
- if ((is_using_usbccgp) || (iface == 0)) {
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[0].api_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[0].dev_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[0].api_handle = winusb_handle;
2648
- usbi_warn(ctx, "auto-claimed interface 0 (required to claim %u with WinUSB)", iface);
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 0 (required to claim %u with WinUSB): %s", iface, windows_error_str(0));
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[0].dev_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 winusbx_do_iso_transfer.
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
- // TODO translate USDB_STATUS codes http://msdn.microsoft.com/en-us/library/ff539136(VS.85).aspx to libusb_transfer_status
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)) {