usb 2.17.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 (94) hide show
  1. package/CHANGELOG.md +6 -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/index.d.ts +0 -29
  7. package/dist/usb/index.js +4 -18
  8. package/dist/usb/index.js.map +1 -1
  9. package/libusb/.clang-tidy +5 -3
  10. package/libusb/.private/ci-build.sh +5 -1
  11. package/libusb/AUTHORS +14 -0
  12. package/libusb/ChangeLog +15 -2
  13. package/libusb/README +8 -5
  14. package/libusb/Xcode/libusb.xcodeproj/project.pbxproj +4 -0
  15. package/libusb/configure.ac +12 -2
  16. package/libusb/examples/hotplugtest.c +19 -11
  17. package/libusb/examples/listdevs.c +41 -3
  18. package/libusb/examples/xusb.c +6 -1
  19. package/libusb/libusb/Makefile.am +4 -0
  20. package/libusb/libusb/core.c +175 -14
  21. package/libusb/libusb/descriptor.c +163 -14
  22. package/libusb/libusb/io.c +7 -3
  23. package/libusb/libusb/libusb-1.0.def +10 -0
  24. package/libusb/libusb/libusb.h +59 -9
  25. package/libusb/libusb/libusbi.h +89 -25
  26. package/libusb/libusb/os/darwin_usb.c +126 -46
  27. package/libusb/libusb/os/darwin_usb.h +10 -8
  28. package/libusb/libusb/os/emscripten_webusb.cpp +31 -10
  29. package/libusb/libusb/os/haiku_usb_raw.cpp +4 -0
  30. package/libusb/libusb/os/linux_usbfs.c +73 -25
  31. package/libusb/libusb/os/netbsd_usb.c +2 -0
  32. package/libusb/libusb/os/openbsd_usb.c +2 -0
  33. package/libusb/libusb/os/sunos_usb.c +2 -0
  34. package/libusb/libusb/os/threads_posix.c +3 -3
  35. package/libusb/libusb/os/threads_posix.h +8 -2
  36. package/libusb/libusb/os/threads_windows.h +2 -1
  37. package/libusb/libusb/os/windows_common.c +86 -1
  38. package/libusb/libusb/os/windows_common.h +20 -1
  39. package/libusb/libusb/os/windows_hotplug.c +321 -0
  40. package/libusb/libusb/os/windows_hotplug.h +28 -0
  41. package/libusb/libusb/os/windows_usbdk.c +16 -8
  42. package/libusb/libusb/os/windows_winusb.c +753 -41
  43. package/libusb/libusb/os/windows_winusb.h +11 -6
  44. package/libusb/libusb/version.h +1 -1
  45. package/libusb/libusb/version_nano.h +1 -1
  46. package/libusb/msvc/Base.props +1 -1
  47. package/libusb/msvc/Configuration.Base.props +2 -1
  48. package/libusb/msvc/Configuration.DynamicLibrary.props +12 -0
  49. package/libusb/msvc/ProjectConfigurations.Base.props +69 -16
  50. package/libusb/msvc/build_all.ps1 +2 -2
  51. package/libusb/msvc/config.h +4 -0
  52. package/libusb/msvc/getopt/bits/getopt_core.h +96 -0
  53. package/libusb/msvc/getopt/bits/getopt_ext.h +77 -0
  54. package/libusb/msvc/getopt/features.h +21 -0
  55. package/libusb/msvc/getopt/getopt.c +456 -705
  56. package/libusb/msvc/getopt/getopt.h +16 -158
  57. package/libusb/msvc/getopt/getopt1.c +40 -69
  58. package/libusb/msvc/getopt/getopt_int.h +118 -0
  59. package/libusb/msvc/getopt/gettext.h +7 -0
  60. package/libusb/msvc/getopt/unistd.h +5 -0
  61. package/libusb/msvc/getopt.vcxproj +11 -4
  62. package/libusb/msvc/libusb.sln +515 -268
  63. package/libusb/msvc/libusb_dll.vcxproj +2 -0
  64. package/libusb/msvc/libusb_static.vcxproj +2 -0
  65. package/libusb/msvc/xusb.vcxproj +1 -1
  66. package/libusb/tests/Makefile.am +10 -1
  67. package/libusb/tests/fuzz/corpus/bos/min.bos +0 -0
  68. package/libusb/tests/fuzz/corpus/descriptor_parsers/min_valid_config.bin +0 -0
  69. package/libusb/tests/fuzz/corpus/descriptor_parsers/regression_bug_a_endpoint_null.bin +0 -0
  70. package/libusb/tests/fuzz/corpus/descriptor_parsers/regression_bug_b_iad_oob.bin +0 -0
  71. package/libusb/tests/fuzz/fuzz_bos_descriptor.c +49 -0
  72. package/libusb/tests/fuzz/fuzz_descriptor_parsers.c +83 -0
  73. package/libusb/tests/stress_mt.c +2 -1
  74. package/libusb/tests/webusb-test-shim/index.js +6 -5
  75. package/libusb.gypi +5 -0
  76. package/package.json +1 -1
  77. package/prebuilds/android-arm/node.napi.armv7.node +0 -0
  78. package/prebuilds/android-arm64/node.napi.armv8.node +0 -0
  79. package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
  80. package/prebuilds/linux-arm/node.napi.armv6.node +0 -0
  81. package/prebuilds/linux-arm/node.napi.armv7.node +0 -0
  82. package/prebuilds/linux-arm64/node.napi.armv8.node +0 -0
  83. package/prebuilds/linux-ia32/node.napi.node +0 -0
  84. package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
  85. package/prebuilds/linux-x64/node.napi.musl.node +0 -0
  86. package/prebuilds/win32-arm64/node.napi.node +0 -0
  87. package/prebuilds/win32-ia32/node.napi.node +0 -0
  88. package/prebuilds/win32-x64/node.napi.node +0 -0
  89. package/src/{hotplug/libusb.cc → hotplug.cc} +2 -3
  90. package/src/{hotplug/hotplug.h → hotplug.h} +2 -6
  91. package/src/node_usb.cc +3 -3
  92. package/test/usb.coffee +4 -4
  93. package/test/webusb.coffee +22 -12
  94. package/src/hotplug/windows.cc +0 -168
@@ -43,6 +43,8 @@
43
43
  continue; \
44
44
  }
45
45
 
46
+ static int interface_by_endpoint(struct winusb_device_priv *priv,
47
+ struct winusb_device_handle_priv *handle_priv, uint8_t endpoint_address);
46
48
  // WinUSB-like API prototypes
47
49
  static bool winusbx_init(struct libusb_context *ctx);
48
50
  static void winusbx_exit(void);
@@ -59,6 +61,9 @@ static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_hand
59
61
  static int winusbx_cancel_transfer(int sub_api, struct usbi_transfer *itransfer);
60
62
  static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
61
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);
62
67
  // HID API prototypes
63
68
  static bool hid_init(struct libusb_context *ctx);
64
69
  static void hid_exit(void);
@@ -85,6 +90,9 @@ static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_ha
85
90
  static int composite_cancel_transfer(int sub_api, struct usbi_transfer *itransfer);
86
91
  static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
87
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);
88
96
 
89
97
  static usbi_mutex_t autoclaim_lock;
90
98
 
@@ -1150,7 +1158,7 @@ static int init_device(struct libusb_device *dev, struct libusb_device *parent_d
1150
1158
 
1151
1159
  if ((conn_info.DeviceDescriptor.bLength != LIBUSB_DT_DEVICE_SIZE)
1152
1160
  || (conn_info.DeviceDescriptor.bDescriptorType != LIBUSB_DT_DEVICE)) {
1153
- usbi_err(ctx, "device '%s' has invalid descriptor!", priv->dev_id);
1161
+ usbi_warn(ctx, "device '%s' has invalid descriptor!", priv->dev_id);
1154
1162
  CloseHandle(hub_handle);
1155
1163
  return LIBUSB_ERROR_OTHER;
1156
1164
  }
@@ -1368,6 +1376,7 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev
1368
1376
  char* endptr;
1369
1377
  struct libusb_interface_association_descriptor_array *iad_array;
1370
1378
  const struct libusb_interface_association_descriptor *iad;
1379
+ int r = LIBUSB_SUCCESS;
1371
1380
 
1372
1381
  // Because MI_## are not necessarily in sequential order (some composite
1373
1382
  // devices will have only MI_00 & MI_03 for instance), we retrieve the actual
@@ -1392,12 +1401,18 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev
1392
1401
  return LIBUSB_ERROR_ACCESS;
1393
1402
  }
1394
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
+
1395
1409
  if (priv->usb_interface[interface_number].path != NULL) {
1396
1410
  if (api == USB_API_HID) {
1397
1411
  // HID devices can have multiple collections (COL##) for each MI_## interface
1398
1412
  usbi_dbg(ctx, "interface[%d] already set - ignoring HID collection: %s",
1399
1413
  interface_number, device_id);
1400
- return LIBUSB_ERROR_ACCESS;
1414
+ r = LIBUSB_ERROR_ACCESS;
1415
+ goto out;
1401
1416
  }
1402
1417
  // In other cases, just use the latest data
1403
1418
  safe_free(priv->usb_interface[interface_number].path);
@@ -1409,8 +1424,10 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev
1409
1424
  priv->usb_interface[interface_number].sub_api = sub_api;
1410
1425
  if ((api == USB_API_HID) && (priv->hid == NULL)) {
1411
1426
  priv->hid = calloc(1, sizeof(struct hid_device_priv));
1412
- if (priv->hid == NULL)
1413
- return LIBUSB_ERROR_NO_MEM;
1427
+ if (priv->hid == NULL) {
1428
+ r = LIBUSB_ERROR_NO_MEM;
1429
+ goto out;
1430
+ }
1414
1431
  }
1415
1432
 
1416
1433
  // For WinUSBX, set up associations for interfaces grouped by an IAD
@@ -1434,7 +1451,9 @@ static int set_composite_interface(struct libusb_context *ctx, struct libusb_dev
1434
1451
  libusb_free_interface_association_descriptors(iad_array);
1435
1452
  }
1436
1453
 
1437
- return LIBUSB_SUCCESS;
1454
+ out:
1455
+ usbi_mutex_unlock(&priv->interface_lock);
1456
+ return r;
1438
1457
  }
1439
1458
 
1440
1459
  static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *dev,
@@ -1442,19 +1461,28 @@ static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *d
1442
1461
  {
1443
1462
  struct winusb_device_priv *priv = usbi_get_device_priv(dev);
1444
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);
1445
1470
 
1446
1471
  if (priv->hid == NULL) {
1447
1472
  usbi_err(ctx, "program assertion failed - parent is not HID");
1448
- return LIBUSB_ERROR_NO_DEVICE;
1473
+ r = LIBUSB_ERROR_NO_DEVICE;
1474
+ goto out;
1449
1475
  } else if (priv->hid->nb_interfaces == USB_MAXINTERFACES) {
1450
1476
  usbi_err(ctx, "program assertion failed - max USB interfaces reached for HID device");
1451
- return LIBUSB_ERROR_NO_DEVICE;
1477
+ r = LIBUSB_ERROR_NO_DEVICE;
1478
+ goto out;
1452
1479
  }
1453
1480
 
1454
1481
  for (i = 0; i < priv->hid->nb_interfaces; i++) {
1455
1482
  if ((priv->usb_interface[i].path != NULL) && strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) {
1456
1483
  usbi_dbg(ctx, "interface[%u] already set to %s", i, dev_interface_path);
1457
- return LIBUSB_ERROR_ACCESS;
1484
+ r = LIBUSB_ERROR_ACCESS;
1485
+ goto out;
1458
1486
  }
1459
1487
  }
1460
1488
 
@@ -1462,7 +1490,10 @@ static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *d
1462
1490
  priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID];
1463
1491
  usbi_dbg(ctx, "interface[%u] = %s", priv->hid->nb_interfaces, dev_interface_path);
1464
1492
  priv->hid->nb_interfaces++;
1465
- return LIBUSB_SUCCESS;
1493
+
1494
+ out:
1495
+ usbi_mutex_unlock(&priv->interface_lock);
1496
+ return r;
1466
1497
  }
1467
1498
 
1468
1499
  // get the n-th device interface GUID indexed by guid_number
@@ -1874,7 +1905,18 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
1874
1905
  dev = usbi_alloc_device(ctx, session_id);
1875
1906
  if (dev == NULL)
1876
1907
  LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
1877
-
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.
1878
1920
  priv = winusb_device_priv_init(dev);
1879
1921
  priv->dev_id = _strdup(dev_id);
1880
1922
  priv->class_guid = dev_info_data.ClassGuid;
@@ -1882,22 +1924,40 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
1882
1924
  libusb_unref_device(dev);
1883
1925
  LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
1884
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
1885
1936
  } else {
1886
1937
  usbi_dbg(ctx, "found existing device for session [%lX]", session_id);
1887
1938
 
1888
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
+
1889
1946
  if (strcmp(priv->dev_id, dev_id) != 0) {
1890
1947
  usbi_dbg(ctx, "device instance ID for session [%lX] changed", session_id);
1891
- 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
1892
1949
  libusb_unref_device(dev);
1893
1950
  goto alloc_device;
1894
1951
  }
1895
1952
  if (!IsEqualGUID(&priv->class_guid, &dev_info_data.ClassGuid)) {
1896
1953
  usbi_dbg(ctx, "device class GUID for session [%lX] changed", session_id);
1897
- 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
1898
1955
  libusb_unref_device(dev);
1899
1956
  goto alloc_device;
1900
1957
  }
1958
+ #if defined(LIBUSB_WINDOWS_HOTPLUG)
1959
+ priv->seen_during_scan = true;
1960
+ #endif
1901
1961
  }
1902
1962
 
1903
1963
  track_unref:
@@ -1913,14 +1973,22 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
1913
1973
  }
1914
1974
  unref_list[unref_cur++] = dev;
1915
1975
  }
1916
-
1976
+ #if defined(LIBUSB_WINDOWS_HOTPLUG)
1977
+ dont_track_unref:
1978
+ #endif
1917
1979
  // Setup device
1918
1980
  switch (pass_type) {
1919
1981
  case HUB_PASS:
1920
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);
1921
1987
  // If the device has already been setup, don't do it again
1922
- if (priv->path != NULL)
1988
+ if (priv->path != NULL) {
1989
+ usbi_mutex_unlock(&priv->interface_lock);
1923
1990
  break;
1991
+ }
1924
1992
  // Take care of API initialization
1925
1993
  priv->path = dev_interface_path;
1926
1994
  dev_interface_path = NULL;
@@ -1947,41 +2015,65 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
1947
2015
  break;
1948
2016
  case USB_API_HID:
1949
2017
  priv->hid = calloc(1, sizeof(struct hid_device_priv));
1950
- if (priv->hid == NULL)
2018
+ if (priv->hid == NULL) {
2019
+ usbi_mutex_unlock(&priv->interface_lock);
1951
2020
  LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
2021
+ }
1952
2022
  break;
1953
2023
  default:
1954
2024
  // For other devices, the first interface is the same as the device
1955
2025
  priv->usb_interface[0].path = _strdup(priv->path);
1956
- if (priv->usb_interface[0].path == NULL)
2026
+ if (priv->usb_interface[0].path == NULL) {
2027
+ usbi_mutex_unlock(&priv->interface_lock);
1957
2028
  LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
2029
+ }
1958
2030
  // The following is needed if we want API calls to work for both simple
1959
2031
  // and composite devices.
1960
2032
  for (j = 0; j < USB_MAXINTERFACES; j++)
1961
2033
  priv->usb_interface[j].apib = &usb_api_backend[api];
1962
2034
  break;
1963
2035
  }
2036
+ usbi_mutex_unlock(&priv->interface_lock);
1964
2037
  break;
1965
2038
  case HCD_PASS:
1966
2039
  r = enumerate_hcd_root_hub(ctx, dev_id, dev_info_data.DevInst);
1967
2040
  break;
1968
2041
  case GEN_PASS:
1969
2042
  port_nr = 0;
1970
- if (!get_dev_port_number(*dev_info, &dev_info_data, &port_nr))
1971
- usbi_warn(ctx, "could not retrieve port number for device '%s': %s", dev_id, windows_error_str(0));
1972
- 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
+ }
1973
2059
  if (r == LIBUSB_SUCCESS) {
1974
2060
  // Append device to the list of discovered devices
1975
- discdevs = discovered_devs_append(*_discdevs, dev);
1976
- if (!discdevs)
1977
- 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);
1978
2065
 
1979
- *_discdevs = discdevs;
2066
+ *_discdevs = discdevs;
2067
+ }
1980
2068
  } else {
1981
2069
  // Failed to initialize a single device doesn't stop us from enumerating all other devices,
1982
2070
  // but we skip it (don't add to list of discovered devices)
1983
2071
  usbi_warn(ctx, "failed to initialize device '%s'", priv->dev_id);
1984
2072
  r = LIBUSB_SUCCESS;
2073
+ #if defined(LIBUSB_WINDOWS_HOTPLUG)
2074
+ usbi_detach_device(dev);
2075
+ libusb_unref_device(dev);
2076
+ #endif
1985
2077
  }
1986
2078
  break;
1987
2079
  case HID_PASS:
@@ -2034,6 +2126,252 @@ static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_
2034
2126
  return r;
2035
2127
  }
2036
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
+
2037
2375
  static int winusb_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len)
2038
2376
  {
2039
2377
  struct winusb_device_priv *priv = usbi_get_device_priv(dev);
@@ -2146,6 +2484,8 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, uint8
2146
2484
 
2147
2485
  CHECK_SUPPORTED_API(priv->apib, claim_interface);
2148
2486
 
2487
+ usbi_mutex_lock(&priv->interface_lock);
2488
+
2149
2489
  safe_free(priv->usb_interface[iface].endpoint);
2150
2490
  priv->usb_interface[iface].nb_endpoints = 0;
2151
2491
 
@@ -2154,6 +2494,8 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, uint8
2154
2494
  if (r == LIBUSB_SUCCESS)
2155
2495
  r = windows_assign_endpoints(dev_handle, iface, 0);
2156
2496
 
2497
+ usbi_mutex_unlock(&priv->interface_lock);
2498
+
2157
2499
  return r;
2158
2500
  }
2159
2501
 
@@ -2164,6 +2506,8 @@ static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_hand
2164
2506
 
2165
2507
  CHECK_SUPPORTED_API(priv->apib, set_interface_altsetting);
2166
2508
 
2509
+ usbi_mutex_lock(&priv->interface_lock);
2510
+
2167
2511
  safe_free(priv->usb_interface[iface].endpoint);
2168
2512
  priv->usb_interface[iface].nb_endpoints = 0;
2169
2513
 
@@ -2172,16 +2516,28 @@ static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_hand
2172
2516
  if (r == LIBUSB_SUCCESS)
2173
2517
  r = windows_assign_endpoints(dev_handle, iface, altsetting);
2174
2518
 
2519
+ usbi_mutex_unlock(&priv->interface_lock);
2520
+
2175
2521
  return r;
2176
2522
  }
2177
2523
 
2178
2524
  static int winusb_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
2179
2525
  {
2180
2526
  struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
2527
+ int r;
2181
2528
 
2182
2529
  CHECK_SUPPORTED_API(priv->apib, release_interface);
2183
2530
 
2184
- 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;
2185
2541
  }
2186
2542
 
2187
2543
  static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
@@ -2289,11 +2645,53 @@ static enum libusb_transfer_status winusb_copy_transfer_data(struct usbi_transfe
2289
2645
  return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, length);
2290
2646
  }
2291
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
+
2292
2689
  // NB: MSVC6 does not support named initializers.
2293
2690
  const struct windows_backend winusb_backend = {
2294
2691
  winusb_init,
2295
2692
  winusb_exit,
2296
2693
  winusb_get_device_list,
2694
+ winusb_get_device_string,
2297
2695
  winusb_open,
2298
2696
  winusb_close,
2299
2697
  winusb_get_active_config_descriptor,
@@ -2311,6 +2709,9 @@ const struct windows_backend winusb_backend = {
2311
2709
  winusb_cancel_transfer,
2312
2710
  winusb_clear_transfer_priv,
2313
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,
2314
2715
  };
2315
2716
 
2316
2717
  /*
@@ -2344,6 +2745,9 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
2344
2745
  NULL, /* submit_control_transfer */
2345
2746
  NULL, /* cancel_transfer */
2346
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 */
2347
2751
  },
2348
2752
  {
2349
2753
  USB_API_HUB,
@@ -2365,6 +2769,9 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
2365
2769
  NULL, /* submit_control_transfer */
2366
2770
  NULL, /* cancel_transfer */
2367
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 */
2368
2775
  },
2369
2776
  {
2370
2777
  USB_API_COMPOSITE,
@@ -2386,6 +2793,9 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
2386
2793
  composite_submit_control_transfer,
2387
2794
  composite_cancel_transfer,
2388
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,
2389
2799
  },
2390
2800
  {
2391
2801
  USB_API_WINUSBX,
@@ -2407,6 +2817,9 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
2407
2817
  winusbx_submit_control_transfer,
2408
2818
  winusbx_cancel_transfer,
2409
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,
2410
2823
  },
2411
2824
  {
2412
2825
  USB_API_HID,
@@ -2428,6 +2841,9 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
2428
2841
  hid_submit_control_transfer,
2429
2842
  NULL, /* cancel_transfer */
2430
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 */
2431
2847
  },
2432
2848
  };
2433
2849
 
@@ -2959,6 +3375,13 @@ static int interface_by_endpoint(struct winusb_device_priv *priv,
2959
3375
  struct winusb_device_handle_priv *handle_priv, uint8_t endpoint_address)
2960
3376
  {
2961
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);
2962
3385
 
2963
3386
  for (i = 0; i < USB_MAXINTERFACES; i++) {
2964
3387
  if (!HANDLE_VALID(handle_priv->interface_handle[i].api_handle))
@@ -2966,12 +3389,16 @@ static int interface_by_endpoint(struct winusb_device_priv *priv,
2966
3389
  if (priv->usb_interface[i].endpoint == NULL)
2967
3390
  continue;
2968
3391
  for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) {
2969
- if (priv->usb_interface[i].endpoint[j] == endpoint_address)
2970
- return i;
3392
+ if (priv->usb_interface[i].endpoint[j] == endpoint_address) {
3393
+ result = i;
3394
+ goto out;
3395
+ }
2971
3396
  }
2972
3397
  }
2973
3398
 
2974
- return -1;
3399
+ out:
3400
+ usbi_mutex_unlock(&priv->interface_lock);
3401
+ return result;
2975
3402
  }
2976
3403
 
2977
3404
  static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
@@ -3174,21 +3601,34 @@ static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itrans
3174
3601
  }
3175
3602
 
3176
3603
  // Query the pipe extended information to find the pipe index corresponding to the endpoint.
3177
- for (idx = 0; idx < priv->usb_interface[current_interface].nb_endpoints; ++idx) {
3178
- ret = WinUSBX[sub_api].QueryPipeEx(winusb_handle, (UINT8)priv->usb_interface[current_interface].current_altsetting, (UCHAR)idx, &pipe_info_ex);
3179
- if (!ret) {
3180
- usbi_err(TRANSFER_CTX(transfer), "couldn't query interface settings for USB pipe with index %d. Error: %s", idx, windows_error_str(0));
3181
- return LIBUSB_ERROR_NOT_FOUND;
3182
- }
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
+ }
3183
3622
 
3184
- if (pipe_info_ex.PipeId == transfer->endpoint && pipe_info_ex.PipeType == UsbdPipeTypeIsochronous)
3185
- break;
3186
- }
3623
+ if (pipe_info_ex.PipeId == transfer->endpoint && pipe_info_ex.PipeType == UsbdPipeTypeIsochronous)
3624
+ break;
3625
+ }
3187
3626
 
3188
- // Make sure we found the index.
3189
- if (idx == priv->usb_interface[current_interface].nb_endpoints) {
3190
- usbi_err(TRANSFER_CTX(transfer), "couldn't find isoch endpoint 0x%02x", transfer->endpoint);
3191
- 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
+ }
3192
3632
  }
3193
3633
 
3194
3634
  if (IS_XFERIN(transfer)) {
@@ -3306,6 +3746,8 @@ static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itran
3306
3746
  overlapped = get_transfer_priv_overlapped(itransfer);
3307
3747
 
3308
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.
3309
3751
  usbi_dbg(TRANSFER_CTX(transfer), "reading %d bytes", transfer->length);
3310
3752
  ret = WinUSBX[sub_api].ReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped);
3311
3753
  } else {
@@ -3404,7 +3846,12 @@ static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_ha
3404
3846
 
3405
3847
  CHECK_WINUSBX_AVAILABLE(sub_api);
3406
3848
 
3407
- // 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);
3408
3855
  for (i = 0; i < USB_MAXINTERFACES; i++) {
3409
3856
  winusb_handle = handle_priv->interface_handle[i].api_handle;
3410
3857
  if (HANDLE_VALID(winusb_handle)) {
@@ -3426,6 +3873,7 @@ static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_ha
3426
3873
  }
3427
3874
  }
3428
3875
  }
3876
+ usbi_mutex_unlock(&priv->interface_lock);
3429
3877
 
3430
3878
  // libusbK & libusb0 have the ability to issue an actual device reset
3431
3879
  if ((sub_api != SUB_API_WINUSB) && (WinUSBX[sub_api].ResetDevice != NULL)) {
@@ -3498,6 +3946,194 @@ static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struc
3498
3946
  return LIBUSB_TRANSFER_COMPLETED;
3499
3947
  }
3500
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
+
3501
4137
  /*
3502
4138
  * Internal HID Support functions (from libusb-win32)
3503
4139
  * Note that functions that complete data transfer synchronously must return
@@ -4764,3 +5400,79 @@ static enum libusb_transfer_status composite_copy_transfer_data(int sub_api, str
4764
5400
  return priv->usb_interface[current_interface].apib->
4765
5401
  copy_transfer_data(priv->usb_interface[current_interface].sub_api, itransfer, length);
4766
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
+ }