usb 2.16.0 → 2.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +14 -0
  3. package/binding.gyp +2 -9
  4. package/dist/usb/bindings.d.ts +27 -2
  5. package/dist/usb/bindings.js.map +1 -1
  6. package/dist/usb/endpoint.js +1 -1
  7. package/dist/usb/endpoint.js.map +1 -1
  8. package/dist/usb/index.d.ts +0 -29
  9. package/dist/usb/index.js +4 -18
  10. package/dist/usb/index.js.map +1 -1
  11. package/dist/webusb/index.d.ts +1 -1
  12. package/dist/webusb/index.js +1 -1
  13. package/dist/webusb/index.js.map +1 -1
  14. package/dist/webusb/webusb-device.d.ts +4 -4
  15. package/dist/webusb/webusb-device.js +5 -2
  16. package/dist/webusb/webusb-device.js.map +1 -1
  17. package/libusb/.clang-tidy +36 -0
  18. package/libusb/.private/ci-build.sh +5 -1
  19. package/libusb/AUTHORS +21 -0
  20. package/libusb/ChangeLog +29 -2
  21. package/libusb/KEYS +123 -0
  22. package/libusb/README +8 -9
  23. package/libusb/Xcode/common.xcconfig +20 -0
  24. package/libusb/Xcode/libusb.xcodeproj/project.pbxproj +16 -12
  25. package/libusb/android/examples/unrooted_android.c +1 -0
  26. package/libusb/configure.ac +12 -2
  27. package/libusb/examples/dpfp.c +1 -1
  28. package/libusb/examples/ezusb.c +6 -1
  29. package/libusb/examples/fxload.c +7 -5
  30. package/libusb/examples/hotplugtest.c +19 -11
  31. package/libusb/examples/listdevs.c +41 -3
  32. package/libusb/examples/testlibusb.c +1 -0
  33. package/libusb/examples/xusb.c +142 -77
  34. package/libusb/libusb/Makefile.am +4 -0
  35. package/libusb/libusb/core.c +183 -24
  36. package/libusb/libusb/descriptor.c +404 -96
  37. package/libusb/libusb/hotplug.c +27 -8
  38. package/libusb/libusb/io.c +10 -5
  39. package/libusb/libusb/libusb-1.0.def +14 -0
  40. package/libusb/libusb/libusb.h +179 -19
  41. package/libusb/libusb/libusbi.h +101 -25
  42. package/libusb/libusb/os/darwin_usb.c +216 -90
  43. package/libusb/libusb/os/darwin_usb.h +10 -8
  44. package/libusb/libusb/os/emscripten_webusb.cpp +38 -12
  45. package/libusb/libusb/os/events_posix.c +4 -4
  46. package/libusb/libusb/os/haiku_usb_raw.cpp +4 -0
  47. package/libusb/libusb/os/linux_usbfs.c +92 -33
  48. package/libusb/libusb/os/linux_usbfs.h +13 -3
  49. package/libusb/libusb/os/netbsd_usb.c +6 -4
  50. package/libusb/libusb/os/openbsd_usb.c +4 -2
  51. package/libusb/libusb/os/sunos_usb.c +7 -5
  52. package/libusb/libusb/os/threads_posix.c +20 -19
  53. package/libusb/libusb/os/threads_posix.h +9 -3
  54. package/libusb/libusb/os/threads_windows.h +4 -3
  55. package/libusb/libusb/os/windows_common.c +86 -1
  56. package/libusb/libusb/os/windows_common.h +20 -1
  57. package/libusb/libusb/os/windows_hotplug.c +321 -0
  58. package/libusb/libusb/os/windows_hotplug.h +28 -0
  59. package/libusb/libusb/os/windows_usbdk.c +16 -8
  60. package/libusb/libusb/os/windows_winusb.c +788 -56
  61. package/libusb/libusb/os/windows_winusb.h +11 -6
  62. package/libusb/libusb/sync.c +8 -5
  63. package/libusb/libusb/version.h +1 -1
  64. package/libusb/libusb/version_nano.h +1 -1
  65. package/libusb/msvc/Base.props +1 -1
  66. package/libusb/msvc/Configuration.Base.props +2 -1
  67. package/libusb/msvc/Configuration.DynamicLibrary.props +12 -0
  68. package/libusb/msvc/ProjectConfigurations.Base.props +69 -16
  69. package/libusb/msvc/build_all.ps1 +2 -2
  70. package/libusb/msvc/config.h +4 -0
  71. package/libusb/msvc/getopt/bits/getopt_core.h +96 -0
  72. package/libusb/msvc/getopt/bits/getopt_ext.h +77 -0
  73. package/libusb/msvc/getopt/features.h +21 -0
  74. package/libusb/msvc/getopt/getopt.c +456 -705
  75. package/libusb/msvc/getopt/getopt.h +16 -158
  76. package/libusb/msvc/getopt/getopt1.c +40 -69
  77. package/libusb/msvc/getopt/getopt_int.h +118 -0
  78. package/libusb/msvc/getopt/gettext.h +7 -0
  79. package/libusb/msvc/getopt/unistd.h +5 -0
  80. package/libusb/msvc/getopt.vcxproj +11 -4
  81. package/libusb/msvc/libusb.sln +515 -268
  82. package/libusb/msvc/libusb_dll.vcxproj +2 -0
  83. package/libusb/msvc/libusb_static.vcxproj +2 -0
  84. package/libusb/msvc/xusb.vcxproj +1 -1
  85. package/libusb/tests/Makefile.am +10 -1
  86. package/libusb/tests/fuzz/corpus/bos/min.bos +0 -0
  87. package/libusb/tests/fuzz/corpus/descriptor_parsers/min_valid_config.bin +0 -0
  88. package/libusb/tests/fuzz/corpus/descriptor_parsers/regression_bug_a_endpoint_null.bin +0 -0
  89. package/libusb/tests/fuzz/corpus/descriptor_parsers/regression_bug_b_iad_oob.bin +0 -0
  90. package/libusb/tests/fuzz/fuzz_bos_descriptor.c +49 -0
  91. package/libusb/tests/fuzz/fuzz_descriptor_parsers.c +83 -0
  92. package/libusb/tests/macos.c +2 -2
  93. package/libusb/tests/stress_mt.c +6 -3
  94. package/libusb/tests/webusb-test-shim/index.js +6 -5
  95. package/libusb.gypi +5 -0
  96. package/package.json +3 -3
  97. package/prebuilds/android-arm/node.napi.armv7.node +0 -0
  98. package/prebuilds/android-arm64/node.napi.armv8.node +0 -0
  99. package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
  100. package/prebuilds/linux-arm/node.napi.armv6.node +0 -0
  101. package/prebuilds/linux-arm/node.napi.armv7.node +0 -0
  102. package/prebuilds/linux-arm64/node.napi.armv8.node +0 -0
  103. package/prebuilds/linux-ia32/node.napi.node +0 -0
  104. package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
  105. package/prebuilds/linux-x64/node.napi.musl.node +0 -0
  106. package/prebuilds/win32-arm64/node.napi.node +0 -0
  107. package/prebuilds/win32-ia32/node.napi.node +0 -0
  108. package/prebuilds/win32-x64/node.napi.node +0 -0
  109. package/src/{hotplug/libusb.cc → hotplug.cc} +2 -3
  110. package/src/{hotplug/hotplug.h → hotplug.h} +2 -6
  111. package/src/node_usb.cc +3 -3
  112. package/test/usb.coffee +4 -4
  113. package/test/webusb.coffee +22 -12
  114. package/src/hotplug/windows.cc +0 -168
@@ -29,6 +29,7 @@
29
29
  #include <setupapi.h>
30
30
  #include <ctype.h>
31
31
  #include <stdio.h>
32
+ #include <stdlib.h>
32
33
 
33
34
  #include "libusbi.h"
34
35
  #include "windows_winusb.h"
@@ -42,6 +43,8 @@
42
43
  continue; \
43
44
  }
44
45
 
46
+ static int interface_by_endpoint(struct winusb_device_priv *priv,
47
+ struct winusb_device_handle_priv *handle_priv, uint8_t endpoint_address);
45
48
  // WinUSB-like API prototypes
46
49
  static bool winusbx_init(struct libusb_context *ctx);
47
50
  static void winusbx_exit(void);
@@ -58,6 +61,9 @@ static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_hand
58
61
  static int winusbx_cancel_transfer(int sub_api, struct usbi_transfer *itransfer);
59
62
  static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
60
63
  static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length);
64
+ static int winusbx_endpoint_supports_raw_io(int sub_api, struct libusb_device_handle* dev_handle, uint8_t endpoint);
65
+ static int winusbx_endpoint_set_raw_io(int sub_api, struct libusb_device_handle* dev_handle, uint8_t endpoint, int enable);
66
+ static int winusbx_get_max_raw_io_transfer_size(int sub_api, struct libusb_device_handle* dev_handle, uint8_t endpoint);
61
67
  // HID API prototypes
62
68
  static bool hid_init(struct libusb_context *ctx);
63
69
  static void hid_exit(void);
@@ -84,6 +90,9 @@ static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_ha
84
90
  static int composite_cancel_transfer(int sub_api, struct usbi_transfer *itransfer);
85
91
  static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
86
92
  static enum libusb_transfer_status composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length);
93
+ static int composite_endpoint_supports_raw_io(int sub_api, struct libusb_device_handle* dev_handle, uint8_t endpoint);
94
+ static int composite_endpoint_set_raw_io(int sub_api, struct libusb_device_handle* dev_handle, uint8_t endpoint, int enable);
95
+ static int composite_get_max_raw_io_transfer_size(int sub_api, struct libusb_device_handle* dev_handle, uint8_t endpoint);
87
96
 
88
97
  static usbi_mutex_t autoclaim_lock;
89
98
 
@@ -1149,7 +1158,7 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d
1149
1158
 
1150
1159
  if ((conn_info.DeviceDescriptor.bLength != LIBUSB_DT_DEVICE_SIZE)
1151
1160
  || (conn_info.DeviceDescriptor.bDescriptorType != LIBUSB_DT_DEVICE)) {
1152
- usbi_err(ctx, "device '%s' has invalid descriptor!", priv->dev_id);
1161
+ usbi_warn(ctx, "device '%s' has invalid descriptor!", priv->dev_id);
1153
1162
  CloseHandle(hub_handle);
1154
1163
  return LIBUSB_ERROR_OTHER;
1155
1164
  }
@@ -1229,6 +1238,9 @@ static bool get_dev_port_number(HDEVINFO dev_info, SP_DEVINFO_DATA *dev_info_dat
1229
1238
  {
1230
1239
  char buffer[MAX_KEY_LENGTH];
1231
1240
  DWORD size;
1241
+ const char *start = NULL;
1242
+ char *end = NULL;
1243
+ long long port;
1232
1244
 
1233
1245
  // First try SPDRP_LOCATION_INFORMATION, which returns a REG_SZ. The string *may* have a format
1234
1246
  // similar to "Port_#0002.Hub_#000D", in which case we can extract the port number. However, we
@@ -1237,7 +1249,15 @@ static bool get_dev_port_number(HDEVINFO dev_info, SP_DEVINFO_DATA *dev_info_dat
1237
1249
  NULL, (PBYTE)buffer, sizeof(buffer), NULL)) {
1238
1250
  // Check for the required format.
1239
1251
  if (strncmp(buffer, "Port_#", 6) == 0) {
1240
- *port_nr = atoi(buffer + 6);
1252
+ start = buffer + 6;
1253
+ // Note that 0 is both strtoll's sentinel return value to indicate failure, as well
1254
+ // as (obviously) the return value for the literal "0". Fortunately we can always treat
1255
+ // 0 as a failure, since Windows USB port numbers are numbered 1..n.
1256
+ port = strtoll(start, &end, 10);
1257
+ if (port <= 0 || port >= ULONG_MAX || end == start || (*end != '.' && *end != '\0')) {
1258
+ return false;
1259
+ }
1260
+ *port_nr = (DWORD)port;
1241
1261
  return true;
1242
1262
  }
1243
1263
  }
@@ -1251,7 +1271,12 @@ static bool get_dev_port_number(HDEVINFO dev_info, SP_DEVINFO_DATA *dev_info_dat
1251
1271
  // Find the last "#USB(x)" substring
1252
1272
  for (char *token = strrchr(buffer, '#'); token != NULL; token = strrchr(buffer, '#')) {
1253
1273
  if (strncmp(token, "#USB(", 5) == 0) {
1254
- *port_nr = atoi(token + 5);
1274
+ start = token + 5;
1275
+ port = strtoll(start, &end, 10);
1276
+ if (port <= 0 || port >= ULONG_MAX || end == start || (*end != ')' && *end != '\0')) {
1277
+ return false;
1278
+ }
1279
+ *port_nr = (DWORD)port;
1255
1280
  return true;
1256
1281
  }
1257
1282
  // Shorten the string and try again.
@@ -1351,6 +1376,7 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev
1351
1376
  char* endptr;
1352
1377
  struct libusb_interface_association_descriptor_array *iad_array;
1353
1378
  const struct libusb_interface_association_descriptor *iad;
1379
+ int r = LIBUSB_SUCCESS;
1354
1380
 
1355
1381
  // Because MI_## are not necessarily in sequential order (some composite
1356
1382
  // devices will have only MI_00 & MI_03 for instance), we retrieve the actual
@@ -1375,12 +1401,18 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev
1375
1401
  return LIBUSB_ERROR_ACCESS;
1376
1402
  }
1377
1403
 
1404
+ // Serialize concurrent enumeration callers that all reach this for the
1405
+ // same parent device. Without this, the check-then-modify on
1406
+ // priv->usb_interface[].path causes double-free / use-after-free.
1407
+ usbi_mutex_lock(&priv->interface_lock);
1408
+
1378
1409
  if (priv->usb_interface[interface_number].path != NULL) {
1379
1410
  if (api == USB_API_HID) {
1380
1411
  // HID devices can have multiple collections (COL##) for each MI_## interface
1381
1412
  usbi_dbg(ctx, "interface[%d] already set - ignoring HID collection: %s",
1382
1413
  interface_number, device_id);
1383
- return LIBUSB_ERROR_ACCESS;
1414
+ r = LIBUSB_ERROR_ACCESS;
1415
+ goto out;
1384
1416
  }
1385
1417
  // In other cases, just use the latest data
1386
1418
  safe_free(priv->usb_interface[interface_number].path);
@@ -1392,8 +1424,10 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev
1392
1424
  priv->usb_interface[interface_number].sub_api = sub_api;
1393
1425
  if ((api == USB_API_HID) && (priv->hid == NULL)) {
1394
1426
  priv->hid = calloc(1, sizeof(struct hid_device_priv));
1395
- if (priv->hid == NULL)
1396
- return LIBUSB_ERROR_NO_MEM;
1427
+ if (priv->hid == NULL) {
1428
+ r = LIBUSB_ERROR_NO_MEM;
1429
+ goto out;
1430
+ }
1397
1431
  }
1398
1432
 
1399
1433
  // For WinUSBX, set up associations for interfaces grouped by an IAD
@@ -1417,7 +1451,9 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev
1417
1451
  libusb_free_interface_association_descriptors(iad_array);
1418
1452
  }
1419
1453
 
1420
- return LIBUSB_SUCCESS;
1454
+ out:
1455
+ usbi_mutex_unlock(&priv->interface_lock);
1456
+ return r;
1421
1457
  }
1422
1458
 
1423
1459
  static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *dev,
@@ -1425,19 +1461,28 @@ static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *d
1425
1461
  {
1426
1462
  struct winusb_device_priv *priv = usbi_get_device_priv(dev);
1427
1463
  uint8_t i;
1464
+ int r = LIBUSB_SUCCESS;
1465
+
1466
+ // Serialize concurrent enumeration callers that all reach this for the
1467
+ // same parent device. Protects priv->hid->nb_interfaces and
1468
+ // priv->usb_interface[].path / apib.
1469
+ usbi_mutex_lock(&priv->interface_lock);
1428
1470
 
1429
1471
  if (priv->hid == NULL) {
1430
1472
  usbi_err(ctx, "program assertion failed - parent is not HID");
1431
- return LIBUSB_ERROR_NO_DEVICE;
1473
+ r = LIBUSB_ERROR_NO_DEVICE;
1474
+ goto out;
1432
1475
  } else if (priv->hid->nb_interfaces == USB_MAXINTERFACES) {
1433
1476
  usbi_err(ctx, "program assertion failed - max USB interfaces reached for HID device");
1434
- return LIBUSB_ERROR_NO_DEVICE;
1477
+ r = LIBUSB_ERROR_NO_DEVICE;
1478
+ goto out;
1435
1479
  }
1436
1480
 
1437
1481
  for (i = 0; i < priv->hid->nb_interfaces; i++) {
1438
1482
  if ((priv->usb_interface[i].path != NULL) && strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) {
1439
1483
  usbi_dbg(ctx, "interface[%u] already set to %s", i, dev_interface_path);
1440
- return LIBUSB_ERROR_ACCESS;
1484
+ r = LIBUSB_ERROR_ACCESS;
1485
+ goto out;
1441
1486
  }
1442
1487
  }
1443
1488
 
@@ -1445,7 +1490,10 @@ static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *d
1445
1490
  priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID];
1446
1491
  usbi_dbg(ctx, "interface[%u] = %s", priv->hid->nb_interfaces, dev_interface_path);
1447
1492
  priv->hid->nb_interfaces++;
1448
- return LIBUSB_SUCCESS;
1493
+
1494
+ out:
1495
+ usbi_mutex_unlock(&priv->interface_lock);
1496
+ return r;
1449
1497
  }
1450
1498
 
1451
1499
  // get the n-th device interface GUID indexed by guid_number
@@ -1492,7 +1540,7 @@ static int get_guid(struct libusb_context *ctx, char *dev_id, HDEVINFO *dev_info
1492
1540
  // The GUID was read successfully
1493
1541
  break;
1494
1542
  } else if (s == ERROR_FILE_NOT_FOUND) {
1495
- usbi_info(ctx, "no DeviceInterfaceGUID registered for '%s'", dev_id);
1543
+ usbi_dbg(ctx, "no DeviceInterfaceGUID registered for '%s'", dev_id);
1496
1544
  err = LIBUSB_ERROR_ACCESS;
1497
1545
  goto exit;
1498
1546
  } else if (s == ERROR_MORE_DATA) {
@@ -1572,7 +1620,6 @@ static int get_guid(struct libusb_context *ctx, char *dev_id, HDEVINFO *dev_info
1572
1620
  usbi_warn(ctx, "device '%s' has malformed DeviceInterfaceGUID string '%s', skipping", dev_id, guid);
1573
1621
  free(*if_guid);
1574
1622
  *if_guid = NULL;
1575
- err = LIBUSB_ERROR_NO_MEM;
1576
1623
  goto exit;
1577
1624
  }
1578
1625
 
@@ -1767,7 +1814,7 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
1767
1814
  }
1768
1815
  // ...and to add the additional device interface GUIDs
1769
1816
  r = get_guid(ctx, dev_id, dev_info, &dev_info_data, 0, &if_guid);
1770
- if (r == LIBUSB_SUCCESS) {
1817
+ if (r == LIBUSB_SUCCESS && if_guid != NULL) {
1771
1818
  // Check if we've already seen this GUID
1772
1819
  for (j = EXT_PASS; j < nb_guids; j++) {
1773
1820
  if (memcmp(guid_list[j], if_guid, sizeof(*if_guid)) == 0)
@@ -1796,7 +1843,9 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
1796
1843
  } else if (r == LIBUSB_ERROR_NO_MEM) {
1797
1844
  LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
1798
1845
  } else {
1799
- usbi_warn(ctx, "unexpected error during getting DeviceInterfaceGUID for '%s'", dev_id);
1846
+ if (r != LIBUSB_SUCCESS) {
1847
+ usbi_warn(ctx, "unexpected error during getting DeviceInterfaceGUID for '%s'", dev_id);
1848
+ }
1800
1849
  }
1801
1850
  break;
1802
1851
  case HID_PASS:
@@ -1856,7 +1905,18 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
1856
1905
  dev = usbi_alloc_device(ctx, session_id);
1857
1906
  if (dev == NULL)
1858
1907
  LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
1859
-
1908
+ // Initialize priv (including interface_lock) and the
1909
+ // fields read by concurrent enumeration paths
1910
+ // (dev_id, class_guid) BEFORE making the device visible
1911
+ // via usbi_attach_device or usbi_connect_device. This
1912
+ // closes a use-after-free in the HOTPLUG error path:
1913
+ // if usbi_attach_device runs before _strdup(dev_id) and
1914
+ // the strdup then fails, libusb_unref_device frees the
1915
+ // device while it is still in ctx->usb_devs, leaving a
1916
+ // dangling pointer for the next list traversal. It also
1917
+ // removes the (theoretical, in practice unreachable in
1918
+ // HOTPLUG mode) window where concurrent paths could see
1919
+ // the device with priv->dev_id == NULL.
1860
1920
  priv = winusb_device_priv_init(dev);
1861
1921
  priv->dev_id = _strdup(dev_id);
1862
1922
  priv->class_guid = dev_info_data.ClassGuid;
@@ -1864,22 +1924,40 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
1864
1924
  libusb_unref_device(dev);
1865
1925
  LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
1866
1926
  }
1927
+ #if defined(LIBUSB_WINDOWS_HOTPLUG)
1928
+ usbi_attach_device(dev);
1929
+ priv->seen_during_scan = true;
1930
+ goto dont_track_unref;
1931
+ #else
1932
+ // Device priv is now initialized; make it
1933
+ // discoverable via usbi_get_device_by_session_id
1934
+ usbi_connect_device(dev);
1935
+ #endif
1867
1936
  } else {
1868
1937
  usbi_dbg(ctx, "found existing device for session [%lX]", session_id);
1869
1938
 
1870
1939
  priv = usbi_get_device_priv(dev);
1940
+
1941
+ if (priv->root_hub && dev->bus_number == bus_number + 1) {
1942
+ // The bus number has already been assigned
1943
+ bus_number++;
1944
+ }
1945
+
1871
1946
  if (strcmp(priv->dev_id, dev_id) != 0) {
1872
1947
  usbi_dbg(ctx, "device instance ID for session [%lX] changed", session_id);
1873
- usbi_disconnect_device(dev);
1948
+ usbi_detach_device(dev); // usbi_detach_device is equivalent do usbi_disconnect_device but for the firing of LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT
1874
1949
  libusb_unref_device(dev);
1875
1950
  goto alloc_device;
1876
1951
  }
1877
1952
  if (!IsEqualGUID(&priv->class_guid, &dev_info_data.ClassGuid)) {
1878
1953
  usbi_dbg(ctx, "device class GUID for session [%lX] changed", session_id);
1879
- usbi_disconnect_device(dev);
1954
+ usbi_detach_device(dev); // usbi_detach_device is equivalent do usbi_disconnect_device but for the firing of LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT
1880
1955
  libusb_unref_device(dev);
1881
1956
  goto alloc_device;
1882
1957
  }
1958
+ #if defined(LIBUSB_WINDOWS_HOTPLUG)
1959
+ priv->seen_during_scan = true;
1960
+ #endif
1883
1961
  }
1884
1962
 
1885
1963
  track_unref:
@@ -1895,14 +1973,22 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
1895
1973
  }
1896
1974
  unref_list[unref_cur++] = dev;
1897
1975
  }
1898
-
1976
+ #if defined(LIBUSB_WINDOWS_HOTPLUG)
1977
+ dont_track_unref:
1978
+ #endif
1899
1979
  // Setup device
1900
1980
  switch (pass_type) {
1901
1981
  case HUB_PASS:
1902
1982
  case DEV_PASS:
1983
+ // Serialize concurrent enumerations so they don't both see
1984
+ // priv->path == NULL and both run setup, racing on the
1985
+ // writes below.
1986
+ usbi_mutex_lock(&priv->interface_lock);
1903
1987
  // If the device has already been setup, don't do it again
1904
- if (priv->path != NULL)
1988
+ if (priv->path != NULL) {
1989
+ usbi_mutex_unlock(&priv->interface_lock);
1905
1990
  break;
1991
+ }
1906
1992
  // Take care of API initialization
1907
1993
  priv->path = dev_interface_path;
1908
1994
  dev_interface_path = NULL;
@@ -1929,41 +2015,65 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
1929
2015
  break;
1930
2016
  case USB_API_HID:
1931
2017
  priv->hid = calloc(1, sizeof(struct hid_device_priv));
1932
- if (priv->hid == NULL)
2018
+ if (priv->hid == NULL) {
2019
+ usbi_mutex_unlock(&priv->interface_lock);
1933
2020
  LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
2021
+ }
1934
2022
  break;
1935
2023
  default:
1936
2024
  // For other devices, the first interface is the same as the device
1937
2025
  priv->usb_interface[0].path = _strdup(priv->path);
1938
- if (priv->usb_interface[0].path == NULL)
2026
+ if (priv->usb_interface[0].path == NULL) {
2027
+ usbi_mutex_unlock(&priv->interface_lock);
1939
2028
  LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
2029
+ }
1940
2030
  // The following is needed if we want API calls to work for both simple
1941
2031
  // and composite devices.
1942
2032
  for (j = 0; j < USB_MAXINTERFACES; j++)
1943
2033
  priv->usb_interface[j].apib = &usb_api_backend[api];
1944
2034
  break;
1945
2035
  }
2036
+ usbi_mutex_unlock(&priv->interface_lock);
1946
2037
  break;
1947
2038
  case HCD_PASS:
1948
2039
  r = enumerate_hcd_root_hub(ctx, dev_id, dev_info_data.DevInst);
1949
2040
  break;
1950
2041
  case GEN_PASS:
1951
2042
  port_nr = 0;
1952
- if (!get_dev_port_number(*dev_info, &dev_info_data, &port_nr))
1953
- usbi_warn(ctx, "could not retrieve port number for device '%s': %s", dev_id, windows_error_str(0));
1954
- r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_info_data.DevInst);
2043
+ // Serialize concurrent enumerations so they don't both see
2044
+ // priv->initialized == false and both run init_device,
2045
+ // which allocates priv->config_descriptor[] and other
2046
+ // per-device state. Without this, the loser of the race
2047
+ // overwrites the winner's allocations, leaking them.
2048
+ usbi_mutex_lock(&priv->interface_lock);
2049
+ if (priv->initialized) {
2050
+ usbi_mutex_unlock(&priv->interface_lock);
2051
+ libusb_unref_device(parent_dev);
2052
+ r = LIBUSB_SUCCESS;
2053
+ } else {
2054
+ if (!get_dev_port_number(*dev_info, &dev_info_data, &port_nr))
2055
+ usbi_warn(ctx, "could not retrieve port number for device '%s': %s", dev_id, windows_error_str(0));
2056
+ r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_info_data.DevInst);
2057
+ usbi_mutex_unlock(&priv->interface_lock);
2058
+ }
1955
2059
  if (r == LIBUSB_SUCCESS) {
1956
2060
  // Append device to the list of discovered devices
1957
- discdevs = discovered_devs_append(*_discdevs, dev);
1958
- if (!discdevs)
1959
- LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
2061
+ if (_discdevs) {
2062
+ discdevs = discovered_devs_append(*_discdevs, dev);
2063
+ if (!discdevs)
2064
+ LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
1960
2065
 
1961
- *_discdevs = discdevs;
2066
+ *_discdevs = discdevs;
2067
+ }
1962
2068
  } else {
1963
2069
  // Failed to initialize a single device doesn't stop us from enumerating all other devices,
1964
2070
  // but we skip it (don't add to list of discovered devices)
1965
2071
  usbi_warn(ctx, "failed to initialize device '%s'", priv->dev_id);
1966
2072
  r = LIBUSB_SUCCESS;
2073
+ #if defined(LIBUSB_WINDOWS_HOTPLUG)
2074
+ usbi_detach_device(dev);
2075
+ libusb_unref_device(dev);
2076
+ #endif
1967
2077
  }
1968
2078
  break;
1969
2079
  case HID_PASS:
@@ -2016,6 +2126,252 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
2016
2126
  return r;
2017
2127
  }
2018
2128
 
2129
+ #ifdef _MSC_VER
2130
+ #pragma pack(push, 1)
2131
+ #endif
2132
+
2133
+ struct string_descriptor_s {
2134
+ UCHAR bLength;
2135
+ UCHAR bDescriptorType;
2136
+ uint8_t bString[252]; // UTF-16LE, must be even length
2137
+ } LIBUSB_PACKED;
2138
+
2139
+ #ifdef _MSC_VER
2140
+ #pragma pack(pop)
2141
+ #endif
2142
+
2143
+ struct string_descriptor_req_s {
2144
+ USB_DESCRIPTOR_REQUEST req;
2145
+ struct string_descriptor_s desc;
2146
+ };
2147
+
2148
+ /*
2149
+ * \brief Convert a UTF-16 little endian string to a UTF-8 string.
2150
+ *
2151
+ * \param src The input UTF-16 little endian string.
2152
+ * \param src_length The length of the src buffer in bytes which
2153
+ * may or may not include the null terminator.
2154
+ * \param dst The output UTF-8 string.
2155
+ * \param dst_length The length of dst buffer in bytes, which should
2156
+ * be large enough to fit the string including null terminator.
2157
+ * \return The total number of bytes in the UTF-8 string, including
2158
+ * the null terminator.
2159
+ * If this is greater than dst_length, then dst is truncated.
2160
+ * \note From MiniBitty RTOS & framework, currently closed source.
2161
+ */
2162
+ static int usbi_utf16le_to_utf8(uint8_t const *src, int src_length, char *dst, int dst_length) {
2163
+ int count = 0;
2164
+ uint32_t codepoint = 0;
2165
+ uint32_t next_codepoint = 0;
2166
+ bool is_surrogate_pair = false;
2167
+ bool overflow = false;
2168
+
2169
+ if (NULL == dst) {
2170
+ dst_length = 0;
2171
+ }
2172
+ if (dst_length > 0) {
2173
+ dst[0] = 0; // empty string by default
2174
+ }
2175
+ if (src_length & 1) {
2176
+ --src_length; // odd length not valid, but proceed.
2177
+ }
2178
+ if ((src == NULL) || (src_length <= 0)) {
2179
+ return 1;
2180
+ }
2181
+
2182
+ for (int k = 0; k < src_length; k += 2) {
2183
+ next_codepoint = *src++;
2184
+ next_codepoint |= ((uint16_t)*src++) << 8;
2185
+ if (is_surrogate_pair) {
2186
+ is_surrogate_pair = false;
2187
+ if ((next_codepoint >= 0xDC00) && (next_codepoint <= 0xDFFF)) {
2188
+ // correct encoding
2189
+ codepoint |= (next_codepoint & 0x3ff);
2190
+ } else {
2191
+ // incorrect encoding, skip previous codepoint
2192
+ codepoint = next_codepoint;
2193
+ }
2194
+ } else if ((next_codepoint >= 0xD800) && (next_codepoint <= 0xDBFF)) {
2195
+ is_surrogate_pair = true;
2196
+ codepoint = 0x010000 + ((next_codepoint & 0x3ff) << 10);
2197
+ continue;
2198
+ } else {
2199
+ codepoint = next_codepoint;
2200
+ }
2201
+
2202
+ if (codepoint <= 0x7f) {
2203
+ if (count < dst_length) {
2204
+ dst[count] = (char)codepoint;
2205
+ } else {
2206
+ overflow = true;
2207
+ }
2208
+ count += 1;
2209
+ if (0 == codepoint) {
2210
+ --count; // add null-terminator below
2211
+ break;
2212
+ }
2213
+ } else if (codepoint <= 0x7ff) {
2214
+ if ((count + 1) < dst_length) {
2215
+ dst[count] = (char)(0xC0 | (codepoint >> 6));
2216
+ dst[count + 1] = (char)(0x80 | (codepoint & 0x3F));
2217
+ } else {
2218
+ overflow = true;
2219
+ }
2220
+ count += 2;
2221
+ } else if (codepoint <= 0xffff) {
2222
+ if ((count + 2) < dst_length) {
2223
+ dst[count] = (char)(0xE0 | (codepoint >> 12));
2224
+ dst[count + 1] = (char)(0x80 | ((codepoint >> 6) & 0x3F));
2225
+ dst[count + 2] = (char)(0x80 | (codepoint & 0x3F));
2226
+ } else {
2227
+ overflow = true;
2228
+ }
2229
+ count += 3;
2230
+ } else if (codepoint <= 0x10ffff) {
2231
+ if ((count + 3) < dst_length) {
2232
+ dst[count] = (char)(0xF0 | ((codepoint >> 18) & 7));
2233
+ dst[count + 1] = (char)(0x80 | ((codepoint >> 12) & 0x3F));
2234
+ dst[count + 2] = (char)(0x80 | ((codepoint >> 6) & 0x3F));
2235
+ dst[count + 3] = (char)(0x80 | (codepoint & 0x3F));
2236
+ } else {
2237
+ overflow = true;
2238
+ }
2239
+ count += 4;
2240
+ } else {
2241
+ // invalid codepoint, skip
2242
+ }
2243
+ }
2244
+
2245
+ if (count < dst_length) {
2246
+ dst[count] = 0;
2247
+ }
2248
+ ++count; // include null terminator
2249
+
2250
+ if (overflow && dst_length) {
2251
+ // truncate respecting UTF-8 character boundaries
2252
+ int idx = dst_length - 1;
2253
+ while (idx && (0x80 == (dst[idx] & 0xC0))) { // utf-8 continuation byte
2254
+ --idx;
2255
+ }
2256
+ dst[idx] = 0;
2257
+ }
2258
+
2259
+ return count;
2260
+ }
2261
+
2262
+ /*
2263
+ * Backend implementation for libusb_get_device_string().
2264
+ *
2265
+ * Windows makes getting the common device strings
2266
+ * very difficult. DEVPKEY_Device_* does not have SerialNumber,
2267
+ * and it reports the driver manufacturer, not the device manufacturer.
2268
+ *
2269
+ * We could parse the serial number from the DEVICE_ID string:
2270
+ * https://learn.microsoft.com/en-us/windows-hardware/drivers/install/device-instance-ids
2271
+ * https://learn.microsoft.com/en-us/windows-hardware/drivers/install/standard-usb-identifiers
2272
+ *
2273
+ * However, using the dev_id for getting the serial number is
2274
+ * definitely not recommended.
2275
+ *
2276
+ * The following implementation uses an IOCTL
2277
+ * to the parent USB hub to perform the USB control request for the
2278
+ * string descriptor without opening the USB device.
2279
+ * While we would rather not invoke USB IO, we currently lack a
2280
+ * better option.
2281
+ */
2282
+ static int winusb_get_device_string(libusb_device *dev,
2283
+ enum libusb_device_string_type string_type, char *data, int length)
2284
+ {
2285
+ struct winusb_device_priv* priv = usbi_get_device_priv(dev);
2286
+ struct libusb_context* ctx = DEVICE_CTX(dev);
2287
+ DWORD size;
2288
+ DWORD ret_size;
2289
+ struct string_descriptor_req_s sd;
2290
+
2291
+ if ((NULL != data) && (length > 0)) {
2292
+ *data = 0;
2293
+ }
2294
+ if (NULL == dev->parent_dev) {
2295
+ return LIBUSB_ERROR_NOT_SUPPORTED;
2296
+ }
2297
+
2298
+ uint8_t string_descriptor_idx;
2299
+ switch (string_type) {
2300
+ case LIBUSB_DEVICE_STRING_MANUFACTURER: string_descriptor_idx = dev->device_descriptor.iManufacturer; break;
2301
+ case LIBUSB_DEVICE_STRING_PRODUCT: string_descriptor_idx = dev->device_descriptor.iProduct; break;
2302
+ case LIBUSB_DEVICE_STRING_SERIAL_NUMBER: string_descriptor_idx = dev->device_descriptor.iSerialNumber; break;
2303
+ default: return LIBUSB_ERROR_INVALID_PARAM;
2304
+ }
2305
+
2306
+ if (0 == string_descriptor_idx) {
2307
+ return LIBUSB_ERROR_NOT_FOUND;
2308
+ }
2309
+
2310
+ struct winusb_device_priv* hub_priv = usbi_get_device_priv(dev->parent_dev);
2311
+ HANDLE hub_handle = CreateFileA(hub_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
2312
+ if (hub_handle == INVALID_HANDLE_VALUE) {
2313
+ usbi_warn(ctx, "could not open hub %s: %s", hub_priv->path, windows_error_str(0));
2314
+ return LIBUSB_ERROR_ACCESS;
2315
+ }
2316
+
2317
+ // Fetch and cache the device's primary USB language ID.
2318
+ // String descriptor 0 with wIndex=0 returns the supported language table
2319
+ // (USB 2.0 spec section 9.6.7). We use the first (primary) LANGID for
2320
+ // all subsequent string descriptor requests.
2321
+ if (0 == priv->langid) {
2322
+ size = sizeof(sd);
2323
+ memset(&sd, 0, size);
2324
+ sd.req.ConnectionIndex = (ULONG)dev->port_number;
2325
+ sd.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
2326
+ sd.req.SetupPacket.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR;
2327
+ sd.req.SetupPacket.wValue = (LIBUSB_DT_STRING << 8) | 0;
2328
+ sd.req.SetupPacket.wIndex = 0;
2329
+ sd.req.SetupPacket.wLength = (USHORT)sizeof(sd.desc);
2330
+
2331
+ if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &sd, size,
2332
+ &sd, size, &ret_size, NULL)) {
2333
+ usbi_warn(ctx, "could not retrieve language IDs for '%s': %s",
2334
+ priv->dev_id, windows_error_str(0));
2335
+ CloseHandle(hub_handle);
2336
+ return LIBUSB_ERROR_IO;
2337
+ }
2338
+
2339
+ if (sd.desc.bDescriptorType != LIBUSB_DT_STRING || sd.desc.bLength < 4) {
2340
+ usbi_warn(ctx, "invalid language ID descriptor for '%s'", priv->dev_id);
2341
+ CloseHandle(hub_handle);
2342
+ return LIBUSB_ERROR_IO;
2343
+ }
2344
+
2345
+ priv->langid = (uint16_t)sd.desc.bString[0] | ((uint16_t)sd.desc.bString[1] << 8);
2346
+ usbi_dbg(ctx, "cached language ID 0x%04x for '%s'", priv->langid, priv->dev_id);
2347
+ }
2348
+
2349
+ size = sizeof(sd);
2350
+ memset(&sd, 0, size);
2351
+ sd.req.ConnectionIndex = (ULONG)dev->port_number;
2352
+ sd.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
2353
+ sd.req.SetupPacket.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR;
2354
+ sd.req.SetupPacket.wValue = (LIBUSB_DT_STRING << 8) | string_descriptor_idx;
2355
+ sd.req.SetupPacket.wIndex = priv->langid;
2356
+ sd.req.SetupPacket.wLength = (USHORT)sizeof(sd.desc);
2357
+
2358
+ BOOL rv = DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &sd, size,
2359
+ &sd, size, &ret_size, NULL);
2360
+ CloseHandle(hub_handle);
2361
+ if (!rv) {
2362
+ usbi_err(ctx, "could not access string descriptor %u for '%s': %s", string_descriptor_idx,
2363
+ priv->dev_id, windows_error_str(0));
2364
+ return LIBUSB_ERROR_IO;
2365
+ }
2366
+
2367
+ if (sd.desc.bDescriptorType != LIBUSB_DT_STRING) {
2368
+ usbi_err(ctx, "descriptor %u not a string descriptor for '%s'", string_descriptor_idx, priv->dev_id);
2369
+ return LIBUSB_ERROR_IO;
2370
+ }
2371
+
2372
+ return usbi_utf16le_to_utf8(sd.desc.bString, (int) (sd.desc.bLength - 2), data, length);
2373
+ }
2374
+
2019
2375
  static int winusb_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len)
2020
2376
  {
2021
2377
  struct winusb_device_priv *priv = usbi_get_device_priv(dev);
@@ -2128,6 +2484,8 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, uint8
2128
2484
 
2129
2485
  CHECK_SUPPORTED_API(priv->apib, claim_interface);
2130
2486
 
2487
+ usbi_mutex_lock(&priv->interface_lock);
2488
+
2131
2489
  safe_free(priv->usb_interface[iface].endpoint);
2132
2490
  priv->usb_interface[iface].nb_endpoints = 0;
2133
2491
 
@@ -2136,6 +2494,8 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, uint8
2136
2494
  if (r == LIBUSB_SUCCESS)
2137
2495
  r = windows_assign_endpoints(dev_handle, iface, 0);
2138
2496
 
2497
+ usbi_mutex_unlock(&priv->interface_lock);
2498
+
2139
2499
  return r;
2140
2500
  }
2141
2501
 
@@ -2146,6 +2506,8 @@ static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_hand
2146
2506
 
2147
2507
  CHECK_SUPPORTED_API(priv->apib, set_interface_altsetting);
2148
2508
 
2509
+ usbi_mutex_lock(&priv->interface_lock);
2510
+
2149
2511
  safe_free(priv->usb_interface[iface].endpoint);
2150
2512
  priv->usb_interface[iface].nb_endpoints = 0;
2151
2513
 
@@ -2154,16 +2516,28 @@ static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_hand
2154
2516
  if (r == LIBUSB_SUCCESS)
2155
2517
  r = windows_assign_endpoints(dev_handle, iface, altsetting);
2156
2518
 
2519
+ usbi_mutex_unlock(&priv->interface_lock);
2520
+
2157
2521
  return r;
2158
2522
  }
2159
2523
 
2160
2524
  static int winusb_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
2161
2525
  {
2162
2526
  struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
2527
+ int r;
2163
2528
 
2164
2529
  CHECK_SUPPORTED_API(priv->apib, release_interface);
2165
2530
 
2166
- return priv->apib->release_interface(SUB_API_NOTSET, dev_handle, iface);
2531
+ // The backend release paths (composite_release_interface,
2532
+ // hid_release_interface) read priv->usb_interface[iface].apib /
2533
+ // .path, which are written under interface_lock by claim/altsetting
2534
+ // and by the enumeration setup paths. Take the lock to make those
2535
+ // reads safe against concurrent writers.
2536
+ usbi_mutex_lock(&priv->interface_lock);
2537
+ r = priv->apib->release_interface(SUB_API_NOTSET, dev_handle, iface);
2538
+ usbi_mutex_unlock(&priv->interface_lock);
2539
+
2540
+ return r;
2167
2541
  }
2168
2542
 
2169
2543
  static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
@@ -2271,11 +2645,53 @@ static enum libusb_transfer_status winusb_copy_transfer_data(struct usbi_transfe
2271
2645
  return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, length);
2272
2646
  }
2273
2647
 
2648
+ static int winusb_endpoint_supports_raw_io(struct libusb_device_handle* dev_handle, uint8_t endpoint)
2649
+ {
2650
+ struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
2651
+
2652
+ if (priv->apib->endpoint_supports_raw_io == NULL)
2653
+ {
2654
+ usbi_dbg(HANDLE_CTX(dev_handle), "device driver does not support RAW_IO query -> unsupported.");
2655
+ return 0;
2656
+ }
2657
+
2658
+ return priv->apib->endpoint_supports_raw_io(SUB_API_NOTSET, dev_handle, endpoint);
2659
+ }
2660
+
2661
+ static int winusb_endpoint_set_raw_io(struct libusb_device_handle* dev_handle, uint8_t endpoint, int enable)
2662
+ {
2663
+ struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
2664
+
2665
+ if (priv->apib->endpoint_set_raw_io == NULL)
2666
+ {
2667
+ usbi_err(HANDLE_CTX(dev_handle), "device driver does not support setting RAW_IO.");
2668
+ return LIBUSB_ERROR_NOT_SUPPORTED;
2669
+ }
2670
+
2671
+ return priv->apib->endpoint_set_raw_io(SUB_API_NOTSET, dev_handle, endpoint, enable);
2672
+ }
2673
+
2674
+ static int winusb_get_max_raw_io_transfer_size(
2675
+ struct libusb_device_handle *dev_handle,
2676
+ uint8_t endpoint)
2677
+ {
2678
+ struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
2679
+
2680
+ if (priv->apib->get_max_raw_io_transfer_size == NULL)
2681
+ {
2682
+ usbi_err(HANDLE_CTX(dev_handle), "device driver does not support RAW_IO max size query.");
2683
+ return LIBUSB_ERROR_NOT_SUPPORTED;
2684
+ }
2685
+
2686
+ return priv->apib->get_max_raw_io_transfer_size(SUB_API_NOTSET, dev_handle, endpoint);
2687
+ }
2688
+
2274
2689
  // NB: MSVC6 does not support named initializers.
2275
2690
  const struct windows_backend winusb_backend = {
2276
2691
  winusb_init,
2277
2692
  winusb_exit,
2278
2693
  winusb_get_device_list,
2694
+ winusb_get_device_string,
2279
2695
  winusb_open,
2280
2696
  winusb_close,
2281
2697
  winusb_get_active_config_descriptor,
@@ -2293,6 +2709,9 @@ const struct windows_backend winusb_backend = {
2293
2709
  winusb_cancel_transfer,
2294
2710
  winusb_clear_transfer_priv,
2295
2711
  winusb_copy_transfer_data,
2712
+ winusb_endpoint_supports_raw_io,
2713
+ winusb_endpoint_set_raw_io,
2714
+ winusb_get_max_raw_io_transfer_size,
2296
2715
  };
2297
2716
 
2298
2717
  /*
@@ -2326,6 +2745,9 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
2326
2745
  NULL, /* submit_control_transfer */
2327
2746
  NULL, /* cancel_transfer */
2328
2747
  NULL, /* copy_transfer_data */
2748
+ NULL, /* endpoint_supports_raw_io */
2749
+ NULL, /* endpoint_set_raw_io */
2750
+ NULL, /* get_max_raw_io_transfer_size */
2329
2751
  },
2330
2752
  {
2331
2753
  USB_API_HUB,
@@ -2347,6 +2769,9 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
2347
2769
  NULL, /* submit_control_transfer */
2348
2770
  NULL, /* cancel_transfer */
2349
2771
  NULL, /* copy_transfer_data */
2772
+ NULL, /* endpoint_supports_raw_io */
2773
+ NULL, /* endpoint_set_raw_io */
2774
+ NULL, /* get_max_raw_io_transfer_size */
2350
2775
  },
2351
2776
  {
2352
2777
  USB_API_COMPOSITE,
@@ -2368,6 +2793,9 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
2368
2793
  composite_submit_control_transfer,
2369
2794
  composite_cancel_transfer,
2370
2795
  composite_copy_transfer_data,
2796
+ composite_endpoint_supports_raw_io,
2797
+ composite_endpoint_set_raw_io,
2798
+ composite_get_max_raw_io_transfer_size,
2371
2799
  },
2372
2800
  {
2373
2801
  USB_API_WINUSBX,
@@ -2389,6 +2817,9 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
2389
2817
  winusbx_submit_control_transfer,
2390
2818
  winusbx_cancel_transfer,
2391
2819
  winusbx_copy_transfer_data,
2820
+ winusbx_endpoint_supports_raw_io,
2821
+ winusbx_endpoint_set_raw_io,
2822
+ winusbx_get_max_raw_io_transfer_size,
2392
2823
  },
2393
2824
  {
2394
2825
  USB_API_HID,
@@ -2410,6 +2841,9 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
2410
2841
  hid_submit_control_transfer,
2411
2842
  NULL, /* cancel_transfer */
2412
2843
  hid_copy_transfer_data,
2844
+ NULL, /* endpoint_supports_raw_io */
2845
+ NULL, /* endpoint_set_raw_io */
2846
+ NULL, /* get_max_raw_io_transfer_size */
2413
2847
  },
2414
2848
  };
2415
2849
 
@@ -2941,6 +3375,13 @@ static int interface_by_endpoint(struct winusb_device_priv *priv,
2941
3375
  struct winusb_device_handle_priv *handle_priv, uint8_t endpoint_address)
2942
3376
  {
2943
3377
  int i, j;
3378
+ int result = -1;
3379
+
3380
+ // priv->usb_interface[].endpoint and .nb_endpoints are written
3381
+ // under interface_lock by claim/altsetting and the enumeration
3382
+ // setup paths. Take the lock so we don't read a freed endpoint
3383
+ // pointer or an inconsistent (nb_endpoints, endpoint[]) pair.
3384
+ usbi_mutex_lock(&priv->interface_lock);
2944
3385
 
2945
3386
  for (i = 0; i < USB_MAXINTERFACES; i++) {
2946
3387
  if (!HANDLE_VALID(handle_priv->interface_handle[i].api_handle))
@@ -2948,12 +3389,16 @@ static int interface_by_endpoint(struct winusb_device_priv *priv,
2948
3389
  if (priv->usb_interface[i].endpoint == NULL)
2949
3390
  continue;
2950
3391
  for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) {
2951
- if (priv->usb_interface[i].endpoint[j] == endpoint_address)
2952
- return i;
3392
+ if (priv->usb_interface[i].endpoint[j] == endpoint_address) {
3393
+ result = i;
3394
+ goto out;
3395
+ }
2953
3396
  }
2954
3397
  }
2955
3398
 
2956
- return -1;
3399
+ out:
3400
+ usbi_mutex_unlock(&priv->interface_lock);
3401
+ return result;
2957
3402
  }
2958
3403
 
2959
3404
  static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
@@ -3156,21 +3601,34 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans
3156
3601
  }
3157
3602
 
3158
3603
  // Query the pipe extended information to find the pipe index corresponding to the endpoint.
3159
- for (idx = 0; idx < priv->usb_interface[current_interface].nb_endpoints; ++idx) {
3160
- ret = WinUSBX[sub_api].QueryPipeEx(winusb_handle, (UINT8)priv->usb_interface[current_interface].current_altsetting, (UCHAR)idx, &pipe_info_ex);
3161
- if (!ret) {
3162
- usbi_err(TRANSFER_CTX(transfer), "couldn't query interface settings for USB pipe with index %d. Error: %s", idx, windows_error_str(0));
3163
- return LIBUSB_ERROR_NOT_FOUND;
3164
- }
3604
+ // nb_endpoints and current_altsetting are written under interface_lock by claim/altsetting
3605
+ // and enumeration setup; take the lock so the loop bound and the QueryPipeEx altsetting
3606
+ // argument come from a consistent snapshot.
3607
+ {
3608
+ int nb_endpoints;
3609
+ uint8_t altsetting;
3610
+
3611
+ usbi_mutex_lock(&priv->interface_lock);
3612
+ nb_endpoints = priv->usb_interface[current_interface].nb_endpoints;
3613
+ altsetting = (uint8_t)priv->usb_interface[current_interface].current_altsetting;
3614
+ usbi_mutex_unlock(&priv->interface_lock);
3615
+
3616
+ for (idx = 0; idx < nb_endpoints; ++idx) {
3617
+ ret = WinUSBX[sub_api].QueryPipeEx(winusb_handle, altsetting, (UCHAR)idx, &pipe_info_ex);
3618
+ if (!ret) {
3619
+ usbi_err(TRANSFER_CTX(transfer), "couldn't query interface settings for USB pipe with index %d. Error: %s", idx, windows_error_str(0));
3620
+ return LIBUSB_ERROR_NOT_FOUND;
3621
+ }
3165
3622
 
3166
- if (pipe_info_ex.PipeId == transfer->endpoint && pipe_info_ex.PipeType == UsbdPipeTypeIsochronous)
3167
- break;
3168
- }
3623
+ if (pipe_info_ex.PipeId == transfer->endpoint && pipe_info_ex.PipeType == UsbdPipeTypeIsochronous)
3624
+ break;
3625
+ }
3169
3626
 
3170
- // Make sure we found the index.
3171
- if (idx == priv->usb_interface[current_interface].nb_endpoints) {
3172
- usbi_err(TRANSFER_CTX(transfer), "couldn't find isoch endpoint 0x%02x", transfer->endpoint);
3173
- return LIBUSB_ERROR_NOT_FOUND;
3627
+ // Make sure we found the index.
3628
+ if (idx == nb_endpoints) {
3629
+ usbi_err(TRANSFER_CTX(transfer), "couldn't find isoch endpoint 0x%02x", transfer->endpoint);
3630
+ return LIBUSB_ERROR_NOT_FOUND;
3631
+ }
3174
3632
  }
3175
3633
 
3176
3634
  if (IS_XFERIN(transfer)) {
@@ -3288,6 +3746,8 @@ static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itran
3288
3746
  overlapped = get_transfer_priv_overlapped(itransfer);
3289
3747
 
3290
3748
  if (IS_XFERIN(transfer)) {
3749
+ // Note: We don't need to handle transfers to pipes with RAW_IO enabled differently,
3750
+ // as ReadPipe() already fails if the length argument doesn't satisfy the RAW_IO requirements.
3291
3751
  usbi_dbg(TRANSFER_CTX(transfer), "reading %d bytes", transfer->length);
3292
3752
  ret = WinUSBX[sub_api].ReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped);
3293
3753
  } else {
@@ -3386,7 +3846,12 @@ static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_ha
3386
3846
 
3387
3847
  CHECK_WINUSBX_AVAILABLE(sub_api);
3388
3848
 
3389
- // Reset any available pipe (except control)
3849
+ // Reset any available pipe (except control).
3850
+ // priv->usb_interface[].endpoint and .nb_endpoints are written under
3851
+ // interface_lock by claim/altsetting and the enumeration setup paths;
3852
+ // take the lock so we don't read a freed endpoint pointer or an
3853
+ // inconsistent (nb_endpoints, endpoint[]) pair.
3854
+ usbi_mutex_lock(&priv->interface_lock);
3390
3855
  for (i = 0; i < USB_MAXINTERFACES; i++) {
3391
3856
  winusb_handle = handle_priv->interface_handle[i].api_handle;
3392
3857
  if (HANDLE_VALID(winusb_handle)) {
@@ -3408,6 +3873,7 @@ static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_ha
3408
3873
  }
3409
3874
  }
3410
3875
  }
3876
+ usbi_mutex_unlock(&priv->interface_lock);
3411
3877
 
3412
3878
  // libusbK & libusb0 have the ability to issue an actual device reset
3413
3879
  if ((sub_api != SUB_API_WINUSB) && (WinUSBX[sub_api].ResetDevice != NULL)) {
@@ -3480,6 +3946,194 @@ static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struc
3480
3946
  return LIBUSB_TRANSFER_COMPLETED;
3481
3947
  }
3482
3948
 
3949
+ static int winusbx_endpoint_supports_raw_io(int sub_api, struct libusb_device_handle* dev_handle, uint8_t endpoint)
3950
+ {
3951
+ struct libusb_context *ctx;
3952
+ struct winusb_device_handle_priv *handle_priv;
3953
+ struct winusb_device_priv *priv;
3954
+ int interface;
3955
+ HANDLE winusb_handle;
3956
+
3957
+ ctx = HANDLE_CTX(dev_handle);
3958
+
3959
+ if (!ctx) {
3960
+ return LIBUSB_ERROR_INVALID_PARAM;
3961
+ }
3962
+
3963
+ if (endpoint & ~(LIBUSB_ENDPOINT_DIR_MASK | LIBUSB_ENDPOINT_ADDRESS_MASK)) {
3964
+ usbi_err(ctx, "invalid endpoint 0x%X passed for RAW_IO support query", endpoint);
3965
+ return LIBUSB_ERROR_INVALID_PARAM;
3966
+ }
3967
+
3968
+ if (!(endpoint & LIBUSB_ENDPOINT_DIR_MASK)) {
3969
+ usbi_err(ctx, "endpoint 0x%02X is OUT not IN for RAW_IO support query", endpoint);
3970
+ return LIBUSB_ERROR_INVALID_PARAM;
3971
+ }
3972
+
3973
+ handle_priv = get_winusb_device_handle_priv(dev_handle);
3974
+ priv = usbi_get_device_priv(dev_handle->dev);
3975
+ interface = interface_by_endpoint(priv, handle_priv, (uint8_t) endpoint);
3976
+
3977
+ if (interface < 0) {
3978
+ usbi_err(ctx, "unable to match endpoint 0x%02X to an open interface for RAW_IO support query", endpoint);
3979
+ return LIBUSB_ERROR_NOT_FOUND;
3980
+ }
3981
+
3982
+ usbi_dbg(ctx, "matched endpoint 0x%02X to interface %d for RAW_IO support query", endpoint, interface);
3983
+
3984
+ if (priv->usb_interface[interface].apib->id != USB_API_WINUSBX) {
3985
+ usbi_err(ctx, "interface %d is not managed by WinUSB, cannot query RAW_IO support", interface);
3986
+ return LIBUSB_ERROR_NOT_SUPPORTED;
3987
+ }
3988
+
3989
+ winusb_handle = handle_priv->interface_handle[interface].api_handle;
3990
+
3991
+ if (!HANDLE_VALID(winusb_handle)) {
3992
+ usbi_err(HANDLE_CTX(dev_handle), "WinUSB handle not valid for interface %d, cannot query RAW_IO support", interface);
3993
+ return LIBUSB_ERROR_NOT_FOUND;
3994
+ }
3995
+
3996
+ CHECK_WINUSBX_AVAILABLE(sub_api);
3997
+
3998
+ // If we made it this far RAW_IO is supported.
3999
+ return 1;
4000
+ }
4001
+
4002
+ int winusbx_endpoint_set_raw_io(int sub_api, libusb_device_handle* dev_handle, uint8_t endpoint, int enable)
4003
+ {
4004
+ struct libusb_context *ctx;
4005
+ struct winusb_device_handle_priv *handle_priv;
4006
+ struct winusb_device_priv *priv;
4007
+ UCHAR policy;
4008
+ int interface;
4009
+ HANDLE winusb_handle;
4010
+
4011
+ ctx = HANDLE_CTX(dev_handle);
4012
+
4013
+ if (!ctx) {
4014
+ return LIBUSB_ERROR_INVALID_PARAM;
4015
+ }
4016
+
4017
+ if (endpoint & ~(LIBUSB_ENDPOINT_DIR_MASK | LIBUSB_ENDPOINT_ADDRESS_MASK)) {
4018
+ usbi_err(ctx, "invalid endpoint 0x%X passed, cannot set RAW_IO", endpoint);
4019
+ return LIBUSB_ERROR_INVALID_PARAM;
4020
+ }
4021
+
4022
+ if (!(endpoint & LIBUSB_ENDPOINT_DIR_MASK)) {
4023
+ usbi_err(ctx, "endpoint 0x%02X is OUT not IN, cannot set RAW_IO", endpoint);
4024
+ return LIBUSB_ERROR_INVALID_PARAM;
4025
+ }
4026
+
4027
+ handle_priv = get_winusb_device_handle_priv(dev_handle);
4028
+ priv = usbi_get_device_priv(dev_handle->dev);
4029
+ interface = interface_by_endpoint(priv, handle_priv, (uint8_t) endpoint);
4030
+
4031
+ if (interface < 0) {
4032
+ usbi_err(ctx, "unable to match endpoint 0x%02X to an open interface for RAW_IO", endpoint);
4033
+ return LIBUSB_ERROR_NOT_FOUND;
4034
+ }
4035
+
4036
+ usbi_dbg(ctx, "matched endpoint 0x%02X to interface %d", endpoint, interface);
4037
+
4038
+ if (priv->usb_interface[interface].apib->id != USB_API_WINUSBX) {
4039
+ usbi_err(ctx, "interface %d is not managed by WinUSB, cannot set RAW_IO", interface);
4040
+ return LIBUSB_ERROR_NOT_SUPPORTED;
4041
+ }
4042
+
4043
+ winusb_handle = handle_priv->interface_handle[interface].api_handle;
4044
+
4045
+ if (!HANDLE_VALID(winusb_handle)) {
4046
+ usbi_err(HANDLE_CTX(dev_handle), "WinUSB handle not valid for interface %d, cannot set RAW_IO", interface);
4047
+ return LIBUSB_ERROR_NOT_FOUND;
4048
+ }
4049
+
4050
+ CHECK_WINUSBX_AVAILABLE(sub_api);
4051
+
4052
+ policy = enable != 0;
4053
+
4054
+ if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, (UCHAR) endpoint,
4055
+ RAW_IO, sizeof(UCHAR), &policy)) {
4056
+ DWORD error = GetLastError();
4057
+ usbi_err(ctx, "failed to change RAW_IO for endpoint %02X: %s", endpoint, windows_error_str(error));
4058
+ switch (error) {
4059
+ case ERROR_INVALID_HANDLE:
4060
+ case ERROR_INVALID_PARAMETER:
4061
+ return LIBUSB_ERROR_INVALID_PARAM;
4062
+ case ERROR_NOT_ENOUGH_MEMORY:
4063
+ return LIBUSB_ERROR_NO_MEM;
4064
+ default:
4065
+ return LIBUSB_ERROR_OTHER;
4066
+ }
4067
+ }
4068
+
4069
+ usbi_dbg(ctx, "%s RAW_IO for endpoint %02X", enable ? "enabled" : "disabled", endpoint);
4070
+
4071
+ return LIBUSB_SUCCESS;
4072
+ }
4073
+
4074
+ static int winusbx_get_max_raw_io_transfer_size(int sub_api, struct libusb_device_handle* dev_handle, uint8_t endpoint)
4075
+ {
4076
+ struct libusb_context *ctx;
4077
+ struct winusb_device_handle_priv *handle_priv;
4078
+ struct winusb_device_priv *priv;
4079
+ int interface;
4080
+ HANDLE winusb_handle;
4081
+ ULONG max_transfer_size = 0;
4082
+
4083
+ ctx = HANDLE_CTX(dev_handle);
4084
+
4085
+ if (!ctx) {
4086
+ return LIBUSB_ERROR_INVALID_PARAM;
4087
+ }
4088
+
4089
+ if (endpoint & ~(LIBUSB_ENDPOINT_DIR_MASK | LIBUSB_ENDPOINT_ADDRESS_MASK)) {
4090
+ usbi_err(ctx, "invalid endpoint 0x%X passed, cannot get maximum transfer size for RAW_IO", endpoint);
4091
+ return LIBUSB_ERROR_INVALID_PARAM;
4092
+ }
4093
+
4094
+ handle_priv = get_winusb_device_handle_priv(dev_handle);
4095
+ priv = usbi_get_device_priv(dev_handle->dev);
4096
+ interface = interface_by_endpoint(priv, handle_priv, (uint8_t) endpoint);
4097
+
4098
+ if (interface < 0) {
4099
+ usbi_err(ctx, "unable to match endpoint 0x%02X to an open interface, cannot get maximum transfer size for RAW_IO", endpoint);
4100
+ return LIBUSB_ERROR_NOT_FOUND;
4101
+ }
4102
+
4103
+ usbi_dbg(ctx, "matched endpoint 0x%02X to interface %d", endpoint, interface);
4104
+
4105
+ if (priv->usb_interface[interface].apib->id != USB_API_WINUSBX) {
4106
+ usbi_err(ctx, "interface %d is not managed by WinUSB, cannot get maximum transfer size for RAW_IO", interface);
4107
+ return LIBUSB_ERROR_NOT_SUPPORTED;
4108
+ }
4109
+
4110
+ winusb_handle = handle_priv->interface_handle[interface].api_handle;
4111
+
4112
+ if (!HANDLE_VALID(winusb_handle)) {
4113
+ usbi_err(HANDLE_CTX(dev_handle), "WinUSB handle not valid for interface %d, cannot get maximum transfer size for RAW_IO", interface);
4114
+ return LIBUSB_ERROR_NOT_FOUND;
4115
+ }
4116
+
4117
+ CHECK_WINUSBX_AVAILABLE(sub_api);
4118
+
4119
+ ULONG size = sizeof(ULONG);
4120
+ if (!WinUSBX[sub_api].GetPipePolicy(winusb_handle, (UCHAR) endpoint,
4121
+ MAXIMUM_TRANSFER_SIZE, &size, &max_transfer_size)) {
4122
+ DWORD error = GetLastError();
4123
+ usbi_err(ctx, "failed to get RAW_IO maximum transfer size for endpoint 0x%02X: %s", endpoint, windows_error_str(error));
4124
+ switch (error) {
4125
+ case ERROR_INVALID_HANDLE:
4126
+ return LIBUSB_ERROR_INVALID_PARAM;
4127
+ default:
4128
+ return LIBUSB_ERROR_OTHER;
4129
+ }
4130
+ }
4131
+
4132
+ usbi_dbg(ctx, "maximum transfer size for endpoint 0x%02X is %lu", endpoint, max_transfer_size);
4133
+
4134
+ return (int)max_transfer_size;
4135
+ }
4136
+
3483
4137
  /*
3484
4138
  * Internal HID Support functions (from libusb-win32)
3485
4139
  * Note that functions that complete data transfer synchronously must return
@@ -3498,24 +4152,26 @@ static int _hid_wcslen(WCHAR *str)
3498
4152
  return i;
3499
4153
  }
3500
4154
 
3501
- static int _hid_get_device_descriptor(struct hid_device_priv *hid_priv, void *data, size_t *size)
4155
+ static int _hid_get_device_descriptor(struct libusb_device *dev, struct hid_device_priv *hid_priv, void *data, size_t *size)
3502
4156
  {
3503
4157
  struct libusb_device_descriptor d;
3504
4158
 
4159
+ /* Copy some values from the cached device descriptor
4160
+ * because we cannot get them through HID */
3505
4161
  d.bLength = LIBUSB_DT_DEVICE_SIZE;
3506
4162
  d.bDescriptorType = LIBUSB_DT_DEVICE;
3507
- d.bcdUSB = 0x0200; /* 2.00 */
3508
- d.bDeviceClass = 0;
3509
- d.bDeviceSubClass = 0;
3510
- d.bDeviceProtocol = 0;
3511
- d.bMaxPacketSize0 = 64; /* fix this! */
4163
+ d.bcdUSB = dev->device_descriptor.bcdUSB;
4164
+ d.bDeviceClass = dev->device_descriptor.bDeviceClass;
4165
+ d.bDeviceSubClass = dev->device_descriptor.bDeviceSubClass;
4166
+ d.bDeviceProtocol = dev->device_descriptor.bDeviceProtocol;
4167
+ d.bMaxPacketSize0 = dev->device_descriptor.bMaxPacketSize0;
3512
4168
  d.idVendor = (uint16_t)hid_priv->vid;
3513
4169
  d.idProduct = (uint16_t)hid_priv->pid;
3514
- d.bcdDevice = 0x0100;
4170
+ d.bcdDevice = dev->device_descriptor.bcdDevice;
3515
4171
  d.iManufacturer = hid_priv->string_index[0];
3516
4172
  d.iProduct = hid_priv->string_index[1];
3517
4173
  d.iSerialNumber = hid_priv->string_index[2];
3518
- d.bNumConfigurations = 1;
4174
+ d.bNumConfigurations = dev->device_descriptor.bNumConfigurations;
3519
4175
 
3520
4176
  if (*size > LIBUSB_DT_DEVICE_SIZE)
3521
4177
  *size = LIBUSB_DT_DEVICE_SIZE;
@@ -3743,7 +4399,7 @@ static int _hid_get_descriptor(struct libusb_device *dev, HANDLE hid_handle, int
3743
4399
  switch (type) {
3744
4400
  case LIBUSB_DT_DEVICE:
3745
4401
  usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_DEVICE");
3746
- return _hid_get_device_descriptor(priv->hid, data, size);
4402
+ return _hid_get_device_descriptor(dev, priv->hid, data, size);
3747
4403
  case LIBUSB_DT_CONFIG:
3748
4404
  usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_CONFIG");
3749
4405
  if (!_index)
@@ -4744,3 +5400,79 @@ static enum libusb_transfer_status composite_copy_transfer_data(int sub_api, str
4744
5400
  return priv->usb_interface[current_interface].apib->
4745
5401
  copy_transfer_data(priv->usb_interface[current_interface].sub_api, itransfer, length);
4746
5402
  }
5403
+
5404
+ static int composite_endpoint_supports_raw_io(int sub_api, struct libusb_device_handle *dev_handle,
5405
+ uint8_t endpoint)
5406
+ {
5407
+ struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
5408
+ struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
5409
+ int current_interface;
5410
+
5411
+ UNUSED(sub_api);
5412
+
5413
+ current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
5414
+ if (current_interface < 0) {
5415
+ usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface, cannot query RAW_IO support");
5416
+ return LIBUSB_ERROR_NOT_FOUND;
5417
+ }
5418
+
5419
+ if (priv->usb_interface[current_interface].apib->endpoint_supports_raw_io == NULL)
5420
+ {
5421
+ usbi_dbg(HANDLE_CTX(dev_handle), "device driver doesn't support RAW_IO support query");
5422
+ return 0;
5423
+ }
5424
+
5425
+ return priv->usb_interface[current_interface].apib->
5426
+ endpoint_supports_raw_io(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint);
5427
+ }
5428
+
5429
+ static int composite_endpoint_set_raw_io(int sub_api, libusb_device_handle *dev_handle,
5430
+ uint8_t endpoint, int enable)
5431
+ {
5432
+ struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
5433
+ struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
5434
+ int current_interface;
5435
+
5436
+ UNUSED(sub_api);
5437
+
5438
+ current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
5439
+ if (current_interface < 0) {
5440
+ usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface, cannot query RAW_IO support");
5441
+ return LIBUSB_ERROR_NOT_FOUND;
5442
+ }
5443
+
5444
+ if (priv->usb_interface[current_interface].apib->endpoint_set_raw_io == NULL)
5445
+ {
5446
+ usbi_dbg(HANDLE_CTX(dev_handle), "device driver doesn't support setting RAW_IO");
5447
+ return LIBUSB_ERROR_NOT_SUPPORTED;
5448
+ }
5449
+
5450
+ return priv->usb_interface[current_interface].apib->
5451
+ endpoint_set_raw_io(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint, enable);
5452
+ }
5453
+
5454
+ static int composite_get_max_raw_io_transfer_size(int sub_api,
5455
+ libusb_device_handle *dev_handle,
5456
+ uint8_t endpoint)
5457
+ {
5458
+ struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
5459
+ struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
5460
+ int current_interface;
5461
+
5462
+ UNUSED(sub_api);
5463
+
5464
+ current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
5465
+ if (current_interface < 0) {
5466
+ usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot get max RAW_IO transfer size");
5467
+ return LIBUSB_ERROR_NOT_FOUND;
5468
+ }
5469
+
5470
+ if (priv->usb_interface[current_interface].apib->get_max_raw_io_transfer_size == NULL)
5471
+ {
5472
+ usbi_dbg(HANDLE_CTX(dev_handle), "device driver doesn't support querying max RAW_IO transfer size");
5473
+ return LIBUSB_ERROR_NOT_SUPPORTED;
5474
+ }
5475
+
5476
+ return priv->usb_interface[current_interface].apib->
5477
+ get_max_raw_io_transfer_size(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint);
5478
+ }