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