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.
- package/CHANGELOG.md +6 -0
- package/README.md +14 -0
- package/binding.gyp +2 -9
- package/dist/usb/bindings.d.ts +27 -2
- package/dist/usb/bindings.js.map +1 -1
- package/dist/usb/index.d.ts +0 -29
- package/dist/usb/index.js +4 -18
- package/dist/usb/index.js.map +1 -1
- package/libusb/.clang-tidy +5 -3
- package/libusb/.private/ci-build.sh +5 -1
- package/libusb/AUTHORS +14 -0
- package/libusb/ChangeLog +15 -2
- package/libusb/README +8 -5
- package/libusb/Xcode/libusb.xcodeproj/project.pbxproj +4 -0
- package/libusb/configure.ac +12 -2
- package/libusb/examples/hotplugtest.c +19 -11
- package/libusb/examples/listdevs.c +41 -3
- package/libusb/examples/xusb.c +6 -1
- package/libusb/libusb/Makefile.am +4 -0
- package/libusb/libusb/core.c +175 -14
- package/libusb/libusb/descriptor.c +163 -14
- package/libusb/libusb/io.c +7 -3
- package/libusb/libusb/libusb-1.0.def +10 -0
- package/libusb/libusb/libusb.h +59 -9
- package/libusb/libusb/libusbi.h +89 -25
- package/libusb/libusb/os/darwin_usb.c +126 -46
- package/libusb/libusb/os/darwin_usb.h +10 -8
- package/libusb/libusb/os/emscripten_webusb.cpp +31 -10
- package/libusb/libusb/os/haiku_usb_raw.cpp +4 -0
- package/libusb/libusb/os/linux_usbfs.c +73 -25
- package/libusb/libusb/os/netbsd_usb.c +2 -0
- package/libusb/libusb/os/openbsd_usb.c +2 -0
- package/libusb/libusb/os/sunos_usb.c +2 -0
- package/libusb/libusb/os/threads_posix.c +3 -3
- package/libusb/libusb/os/threads_posix.h +8 -2
- package/libusb/libusb/os/threads_windows.h +2 -1
- package/libusb/libusb/os/windows_common.c +86 -1
- package/libusb/libusb/os/windows_common.h +20 -1
- package/libusb/libusb/os/windows_hotplug.c +321 -0
- package/libusb/libusb/os/windows_hotplug.h +28 -0
- package/libusb/libusb/os/windows_usbdk.c +16 -8
- package/libusb/libusb/os/windows_winusb.c +753 -41
- package/libusb/libusb/os/windows_winusb.h +11 -6
- package/libusb/libusb/version.h +1 -1
- package/libusb/libusb/version_nano.h +1 -1
- package/libusb/msvc/Base.props +1 -1
- package/libusb/msvc/Configuration.Base.props +2 -1
- package/libusb/msvc/Configuration.DynamicLibrary.props +12 -0
- package/libusb/msvc/ProjectConfigurations.Base.props +69 -16
- package/libusb/msvc/build_all.ps1 +2 -2
- package/libusb/msvc/config.h +4 -0
- package/libusb/msvc/getopt/bits/getopt_core.h +96 -0
- package/libusb/msvc/getopt/bits/getopt_ext.h +77 -0
- package/libusb/msvc/getopt/features.h +21 -0
- package/libusb/msvc/getopt/getopt.c +456 -705
- package/libusb/msvc/getopt/getopt.h +16 -158
- package/libusb/msvc/getopt/getopt1.c +40 -69
- package/libusb/msvc/getopt/getopt_int.h +118 -0
- package/libusb/msvc/getopt/gettext.h +7 -0
- package/libusb/msvc/getopt/unistd.h +5 -0
- package/libusb/msvc/getopt.vcxproj +11 -4
- package/libusb/msvc/libusb.sln +515 -268
- package/libusb/msvc/libusb_dll.vcxproj +2 -0
- package/libusb/msvc/libusb_static.vcxproj +2 -0
- package/libusb/msvc/xusb.vcxproj +1 -1
- package/libusb/tests/Makefile.am +10 -1
- package/libusb/tests/fuzz/corpus/bos/min.bos +0 -0
- package/libusb/tests/fuzz/corpus/descriptor_parsers/min_valid_config.bin +0 -0
- package/libusb/tests/fuzz/corpus/descriptor_parsers/regression_bug_a_endpoint_null.bin +0 -0
- package/libusb/tests/fuzz/corpus/descriptor_parsers/regression_bug_b_iad_oob.bin +0 -0
- package/libusb/tests/fuzz/fuzz_bos_descriptor.c +49 -0
- package/libusb/tests/fuzz/fuzz_descriptor_parsers.c +83 -0
- package/libusb/tests/stress_mt.c +2 -1
- package/libusb/tests/webusb-test-shim/index.js +6 -5
- package/libusb.gypi +5 -0
- package/package.json +1 -1
- package/prebuilds/android-arm/node.napi.armv7.node +0 -0
- package/prebuilds/android-arm64/node.napi.armv8.node +0 -0
- package/prebuilds/darwin-x64+arm64/node.napi.node +0 -0
- package/prebuilds/linux-arm/node.napi.armv6.node +0 -0
- package/prebuilds/linux-arm/node.napi.armv7.node +0 -0
- package/prebuilds/linux-arm64/node.napi.armv8.node +0 -0
- package/prebuilds/linux-ia32/node.napi.node +0 -0
- package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
- package/prebuilds/linux-x64/node.napi.musl.node +0 -0
- package/prebuilds/win32-arm64/node.napi.node +0 -0
- package/prebuilds/win32-ia32/node.napi.node +0 -0
- package/prebuilds/win32-x64/node.napi.node +0 -0
- package/src/{hotplug/libusb.cc → hotplug.cc} +2 -3
- package/src/{hotplug/hotplug.h → hotplug.h} +2 -6
- package/src/node_usb.cc +3 -3
- package/test/usb.coffee +4 -4
- package/test/webusb.coffee +22 -12
- package/src/hotplug/windows.cc +0 -168
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
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
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
2061
|
+
if (_discdevs) {
|
|
2062
|
+
discdevs = discovered_devs_append(*_discdevs, dev);
|
|
2063
|
+
if (!discdevs)
|
|
2064
|
+
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1978
2065
|
|
|
1979
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3392
|
+
if (priv->usb_interface[i].endpoint[j] == endpoint_address) {
|
|
3393
|
+
result = i;
|
|
3394
|
+
goto out;
|
|
3395
|
+
}
|
|
2971
3396
|
}
|
|
2972
3397
|
}
|
|
2973
3398
|
|
|
2974
|
-
|
|
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
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
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
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3623
|
+
if (pipe_info_ex.PipeId == transfer->endpoint && pipe_info_ex.PipeType == UsbdPipeTypeIsochronous)
|
|
3624
|
+
break;
|
|
3625
|
+
}
|
|
3187
3626
|
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
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
|
+
}
|