usb 2.17.0 → 3.0.0-alpha.2
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/LICENSE +18 -4
- package/README.md +25 -516
- package/dist/index.d.ts +67 -13
- package/dist/index.js +333 -64
- package/index.d.ts +89 -0
- package/index.js +583 -0
- package/package.json +53 -33
- package/CHANGELOG.md +0 -294
- package/binding.gyp +0 -128
- package/dist/index.js.map +0 -1
- package/dist/usb/bindings.d.ts +0 -266
- package/dist/usb/bindings.js +0 -10
- package/dist/usb/bindings.js.map +0 -1
- package/dist/usb/capability.d.ts +0 -13
- package/dist/usb/capability.js +0 -17
- package/dist/usb/capability.js.map +0 -1
- package/dist/usb/descriptors.d.ts +0 -128
- package/dist/usb/descriptors.js +0 -3
- package/dist/usb/descriptors.js.map +0 -1
- package/dist/usb/device.d.ts +0 -100
- package/dist/usb/device.js +0 -297
- package/dist/usb/device.js.map +0 -1
- package/dist/usb/endpoint.d.ts +0 -94
- package/dist/usb/endpoint.js +0 -219
- package/dist/usb/endpoint.js.map +0 -1
- package/dist/usb/index.d.ts +0 -31
- package/dist/usb/index.js +0 -116
- package/dist/usb/index.js.map +0 -1
- package/dist/usb/interface.d.ts +0 -80
- package/dist/usb/interface.js +0 -133
- package/dist/usb/interface.js.map +0 -1
- package/dist/webusb/index.d.ts +0 -64
- package/dist/webusb/index.js +0 -295
- package/dist/webusb/index.js.map +0 -1
- package/dist/webusb/webusb-device.d.ts +0 -54
- package/dist/webusb/webusb-device.js +0 -434
- package/dist/webusb/webusb-device.js.map +0 -1
- package/libusb/.clang-tidy +0 -34
- package/libusb/.codespellrc +0 -3
- package/libusb/.private/README.txt +0 -5
- package/libusb/.private/appveyor_build.sh +0 -26
- package/libusb/.private/bm.sh +0 -54
- package/libusb/.private/ci-build.sh +0 -92
- package/libusb/.private/ci-container-build.sh +0 -67
- package/libusb/.private/post-rewrite.sh +0 -32
- package/libusb/.private/pre-commit.sh +0 -52
- package/libusb/.private/wbs.txt +0 -43
- package/libusb/.travis.yml +0 -58
- package/libusb/AUTHORS +0 -231
- package/libusb/COPYING +0 -504
- package/libusb/ChangeLog +0 -365
- package/libusb/HACKING +0 -25
- package/libusb/INSTALL_WIN.txt +0 -52
- package/libusb/KEYS +0 -123
- package/libusb/Makefile.am +0 -50
- package/libusb/NEWS +0 -2
- package/libusb/PORTING +0 -94
- package/libusb/README +0 -29
- package/libusb/README.git +0 -41
- package/libusb/TODO +0 -2
- package/libusb/Xcode/common.xcconfig +0 -92
- package/libusb/Xcode/config.h +0 -31
- package/libusb/Xcode/debug.xcconfig +0 -32
- package/libusb/Xcode/libusb.xcconfig +0 -21
- package/libusb/Xcode/libusb.xcodeproj/project.pbxproj +0 -1391
- package/libusb/Xcode/libusb_debug.xcconfig +0 -21
- package/libusb/Xcode/libusb_release.xcconfig +0 -21
- package/libusb/Xcode/release.xcconfig +0 -30
- package/libusb/android/README +0 -152
- package/libusb/android/config.h +0 -55
- package/libusb/android/examples/unrooted_android.c +0 -301
- package/libusb/android/examples/unrooted_android.h +0 -36
- package/libusb/android/jni/Android.mk +0 -23
- package/libusb/android/jni/Application.mk +0 -40
- package/libusb/android/jni/examples.mk +0 -168
- package/libusb/android/jni/libusb.mk +0 -60
- package/libusb/android/jni/tests.mk +0 -45
- package/libusb/appveyor.yml +0 -108
- package/libusb/autogen.sh +0 -10
- package/libusb/bootstrap.sh +0 -10
- package/libusb/configure.ac +0 -450
- package/libusb/doc/Makefile.in +0 -22
- package/libusb/doc/doxygen.cfg.in +0 -2571
- package/libusb/doc/libusb.png +0 -0
- package/libusb/examples/Makefile.am +0 -12
- package/libusb/examples/dpfp.c +0 -711
- package/libusb/examples/ezusb.c +0 -846
- package/libusb/examples/ezusb.h +0 -109
- package/libusb/examples/fxload.c +0 -310
- package/libusb/examples/hotplugtest.c +0 -147
- package/libusb/examples/listdevs.c +0 -73
- package/libusb/examples/sam3u_benchmark.c +0 -228
- package/libusb/examples/testlibusb.c +0 -312
- package/libusb/examples/xusb.c +0 -1254
- package/libusb/libusb/Makefile.am +0 -98
- package/libusb/libusb/Makefile.am.extra +0 -26
- package/libusb/libusb/core.c +0 -2925
- package/libusb/libusb/descriptor.c +0 -1558
- package/libusb/libusb/hotplug.c +0 -489
- package/libusb/libusb/io.c +0 -2865
- package/libusb/libusb/libusb-1.0.def +0 -199
- package/libusb/libusb/libusb-1.0.rc +0 -53
- package/libusb/libusb/libusb.h +0 -2421
- package/libusb/libusb/libusbi.h +0 -1535
- package/libusb/libusb/os/darwin_usb.c +0 -2977
- package/libusb/libusb/os/darwin_usb.h +0 -156
- package/libusb/libusb/os/emscripten_webusb.cpp +0 -875
- package/libusb/libusb/os/events_posix.c +0 -340
- package/libusb/libusb/os/events_posix.h +0 -62
- package/libusb/libusb/os/events_windows.c +0 -214
- package/libusb/libusb/os/events_windows.h +0 -46
- package/libusb/libusb/os/haiku_pollfs.cpp +0 -372
- package/libusb/libusb/os/haiku_usb.h +0 -113
- package/libusb/libusb/os/haiku_usb_backend.cpp +0 -532
- package/libusb/libusb/os/haiku_usb_raw.cpp +0 -231
- package/libusb/libusb/os/haiku_usb_raw.h +0 -188
- package/libusb/libusb/os/linux_netlink.c +0 -401
- package/libusb/libusb/os/linux_udev.c +0 -321
- package/libusb/libusb/os/linux_usbfs.c +0 -2829
- package/libusb/libusb/os/linux_usbfs.h +0 -221
- package/libusb/libusb/os/netbsd_usb.c +0 -617
- package/libusb/libusb/os/null_usb.c +0 -111
- package/libusb/libusb/os/openbsd_usb.c +0 -700
- package/libusb/libusb/os/sunos_usb.c +0 -1619
- package/libusb/libusb/os/sunos_usb.h +0 -79
- package/libusb/libusb/os/threads_posix.c +0 -126
- package/libusb/libusb/os/threads_posix.h +0 -98
- package/libusb/libusb/os/threads_windows.c +0 -40
- package/libusb/libusb/os/threads_windows.h +0 -113
- package/libusb/libusb/os/windows_common.c +0 -923
- package/libusb/libusb/os/windows_common.h +0 -424
- package/libusb/libusb/os/windows_usbdk.c +0 -724
- package/libusb/libusb/os/windows_usbdk.h +0 -106
- package/libusb/libusb/os/windows_winusb.c +0 -4766
- package/libusb/libusb/os/windows_winusb.h +0 -787
- package/libusb/libusb/strerror.c +0 -223
- package/libusb/libusb/sync.c +0 -342
- package/libusb/libusb/version.h +0 -18
- package/libusb/libusb/version_nano.h +0 -1
- package/libusb/libusb-1.0.pc.in +0 -11
- package/libusb/msvc/Base.props +0 -60
- package/libusb/msvc/Configuration.Application.props +0 -7
- package/libusb/msvc/Configuration.Base.props +0 -47
- package/libusb/msvc/Configuration.DynamicLibrary.props +0 -21
- package/libusb/msvc/Configuration.StaticLibrary.props +0 -7
- package/libusb/msvc/ProjectConfigurations.Base.props +0 -69
- package/libusb/msvc/build_all.ps1 +0 -17
- package/libusb/msvc/config.h +0 -58
- package/libusb/msvc/dpfp.vcxproj +0 -33
- package/libusb/msvc/dpfp_threaded.vcxproj +0 -38
- package/libusb/msvc/fxload.vcxproj +0 -46
- package/libusb/msvc/getopt/getopt.c +0 -1060
- package/libusb/msvc/getopt/getopt.h +0 -180
- package/libusb/msvc/getopt/getopt1.c +0 -188
- package/libusb/msvc/getopt.vcxproj +0 -33
- package/libusb/msvc/hotplugtest.vcxproj +0 -32
- package/libusb/msvc/init_context.vcxproj +0 -35
- package/libusb/msvc/libusb.sln +0 -542
- package/libusb/msvc/libusb_dll.vcxproj +0 -61
- package/libusb/msvc/libusb_static.vcxproj +0 -49
- package/libusb/msvc/listdevs.vcxproj +0 -32
- package/libusb/msvc/sam3u_benchmark.vcxproj +0 -33
- package/libusb/msvc/set_option.vcxproj +0 -35
- package/libusb/msvc/stress.vcxproj +0 -35
- package/libusb/msvc/stress_mt.vcxproj +0 -33
- package/libusb/msvc/testlibusb.vcxproj +0 -32
- package/libusb/msvc/xusb.vcxproj +0 -38
- package/libusb/tests/Makefile.am +0 -40
- package/libusb/tests/init_context.c +0 -153
- package/libusb/tests/libusb_testlib.h +0 -76
- package/libusb/tests/macos.c +0 -130
- package/libusb/tests/set_option.c +0 -253
- package/libusb/tests/stress.c +0 -172
- package/libusb/tests/stress_mt.c +0 -267
- package/libusb/tests/testlib.c +0 -184
- package/libusb/tests/umockdev.c +0 -1175
- package/libusb/tests/webusb-test-shim/index.js +0 -12
- package/libusb/tests/webusb-test-shim/package-lock.json +0 -50
- package/libusb/tests/webusb-test-shim/package.json +0 -10
- package/libusb.gypi +0 -154
- package/libusb_config/config.h +0 -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/device.cc +0 -439
- package/src/helpers.h +0 -64
- package/src/hotplug/hotplug.h +0 -22
- package/src/hotplug/libusb.cc +0 -90
- package/src/hotplug/windows.cc +0 -168
- package/src/node_usb.cc +0 -314
- package/src/node_usb.h +0 -131
- package/src/thread_name.cc +0 -79
- package/src/thread_name.h +0 -11
- package/src/transfer.cc +0 -143
- package/src/uv_async_queue.h +0 -41
- package/test/usb.coffee +0 -250
- package/test/webusb.coffee +0 -227
- package/test/worker.cjs +0 -13
|
@@ -1,4766 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
* windows backend for libusb 1.0
|
|
3
|
-
* Copyright © 2009-2012 Pete Batard <pete@akeo.ie>
|
|
4
|
-
* Copyright © 2016-2018 Chris Dickens <christopher.a.dickens@gmail.com>
|
|
5
|
-
* With contributions from Michael Plante, Orin Eman et al.
|
|
6
|
-
* Parts of this code adapted from libusb-win32-v1 by Stephan Meyer
|
|
7
|
-
* HID Reports IOCTLs inspired from HIDAPI by Alan Ott, Signal 11 Software
|
|
8
|
-
* Hash table functions adapted from glibc, by Ulrich Drepper et al.
|
|
9
|
-
* Major code testing contribution by Xiaofan Chen
|
|
10
|
-
*
|
|
11
|
-
* This library is free software; you can redistribute it and/or
|
|
12
|
-
* modify it under the terms of the GNU Lesser General Public
|
|
13
|
-
* License as published by the Free Software Foundation; either
|
|
14
|
-
* version 2.1 of the License, or (at your option) any later version.
|
|
15
|
-
*
|
|
16
|
-
* This library is distributed in the hope that it will be useful,
|
|
17
|
-
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
18
|
-
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
19
|
-
* Lesser General Public License for more details.
|
|
20
|
-
*
|
|
21
|
-
* You should have received a copy of the GNU Lesser General Public
|
|
22
|
-
* License along with this library; if not, write to the Free Software
|
|
23
|
-
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
24
|
-
*/
|
|
25
|
-
|
|
26
|
-
#include <config.h>
|
|
27
|
-
|
|
28
|
-
#include <windows.h>
|
|
29
|
-
#include <setupapi.h>
|
|
30
|
-
#include <ctype.h>
|
|
31
|
-
#include <stdio.h>
|
|
32
|
-
#include <stdlib.h>
|
|
33
|
-
|
|
34
|
-
#include "libusbi.h"
|
|
35
|
-
#include "windows_winusb.h"
|
|
36
|
-
|
|
37
|
-
#define HANDLE_VALID(h) (((h) != NULL) && ((h) != INVALID_HANDLE_VALUE))
|
|
38
|
-
|
|
39
|
-
// The below macro is used in conjunction with safe loops.
|
|
40
|
-
#define LOOP_BREAK(err) \
|
|
41
|
-
{ \
|
|
42
|
-
r = err; \
|
|
43
|
-
continue; \
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
// WinUSB-like API prototypes
|
|
47
|
-
static bool winusbx_init(struct libusb_context *ctx);
|
|
48
|
-
static void winusbx_exit(void);
|
|
49
|
-
static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle);
|
|
50
|
-
static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle);
|
|
51
|
-
static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
|
|
52
|
-
static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
|
|
53
|
-
static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
|
|
54
|
-
static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
|
|
55
|
-
static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting);
|
|
56
|
-
static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer);
|
|
57
|
-
static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
|
|
58
|
-
static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
|
|
59
|
-
static int winusbx_cancel_transfer(int sub_api, struct usbi_transfer *itransfer);
|
|
60
|
-
static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
|
|
61
|
-
static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length);
|
|
62
|
-
// HID API prototypes
|
|
63
|
-
static bool hid_init(struct libusb_context *ctx);
|
|
64
|
-
static void hid_exit(void);
|
|
65
|
-
static int hid_open(int sub_api, struct libusb_device_handle *dev_handle);
|
|
66
|
-
static void hid_close(int sub_api, struct libusb_device_handle *dev_handle);
|
|
67
|
-
static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
|
|
68
|
-
static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
|
|
69
|
-
static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting);
|
|
70
|
-
static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
|
|
71
|
-
static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
|
|
72
|
-
static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
|
|
73
|
-
static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
|
|
74
|
-
static enum libusb_transfer_status hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length);
|
|
75
|
-
// Composite API prototypes
|
|
76
|
-
static int composite_open(int sub_api, struct libusb_device_handle *dev_handle);
|
|
77
|
-
static void composite_close(int sub_api, struct libusb_device_handle *dev_handle);
|
|
78
|
-
static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
|
|
79
|
-
static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting);
|
|
80
|
-
static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface);
|
|
81
|
-
static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer);
|
|
82
|
-
static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer);
|
|
83
|
-
static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer);
|
|
84
|
-
static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint);
|
|
85
|
-
static int composite_cancel_transfer(int sub_api, struct usbi_transfer *itransfer);
|
|
86
|
-
static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle);
|
|
87
|
-
static enum libusb_transfer_status composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length);
|
|
88
|
-
|
|
89
|
-
static usbi_mutex_t autoclaim_lock;
|
|
90
|
-
|
|
91
|
-
// API globals
|
|
92
|
-
static struct winusb_interface WinUSBX[SUB_API_MAX];
|
|
93
|
-
#define CHECK_WINUSBX_AVAILABLE(sub_api) \
|
|
94
|
-
do { \
|
|
95
|
-
if (sub_api == SUB_API_NOTSET) \
|
|
96
|
-
sub_api = priv->sub_api; \
|
|
97
|
-
if (WinUSBX[sub_api].hDll == NULL) \
|
|
98
|
-
return LIBUSB_ERROR_ACCESS; \
|
|
99
|
-
} while (0)
|
|
100
|
-
|
|
101
|
-
#define CHECK_HID_AVAILABLE \
|
|
102
|
-
do { \
|
|
103
|
-
if (DLL_HANDLE_NAME(hid) == NULL) \
|
|
104
|
-
return LIBUSB_ERROR_ACCESS; \
|
|
105
|
-
} while (0)
|
|
106
|
-
|
|
107
|
-
#if defined(ENABLE_LOGGING)
|
|
108
|
-
static const char *guid_to_string(const GUID *guid, char guid_string[MAX_GUID_STRING_LENGTH])
|
|
109
|
-
{
|
|
110
|
-
if (guid == NULL) {
|
|
111
|
-
guid_string[0] = '\0';
|
|
112
|
-
return guid_string;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
sprintf(guid_string, "{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
|
|
116
|
-
(unsigned int)guid->Data1, guid->Data2, guid->Data3,
|
|
117
|
-
guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
|
|
118
|
-
guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
|
|
119
|
-
|
|
120
|
-
return guid_string;
|
|
121
|
-
}
|
|
122
|
-
#endif
|
|
123
|
-
|
|
124
|
-
static bool string_to_guid(const char guid_string[MAX_GUID_STRING_LENGTH], GUID *guid)
|
|
125
|
-
{
|
|
126
|
-
unsigned short tmp[4];
|
|
127
|
-
int num_chars = -1;
|
|
128
|
-
char extra;
|
|
129
|
-
int r;
|
|
130
|
-
|
|
131
|
-
// Unfortunately MinGW complains that '%hhx' is not a valid format specifier,
|
|
132
|
-
// even though Visual Studio 2013 and later support it. Rather than complicating
|
|
133
|
-
// the logic in this function with '#ifdef's, use a temporary array on the stack
|
|
134
|
-
// to store the conversions.
|
|
135
|
-
r = sscanf(guid_string, "{%8x-%4hx-%4hx-%4hx-%4hx%4hx%4hx}%n%c",
|
|
136
|
-
(unsigned int *)&guid->Data1, &guid->Data2, &guid->Data3,
|
|
137
|
-
&tmp[0], &tmp[1], &tmp[2], &tmp[3], &num_chars, &extra);
|
|
138
|
-
|
|
139
|
-
if ((r != 7) || (num_chars != 38))
|
|
140
|
-
return false;
|
|
141
|
-
|
|
142
|
-
// Extract the bytes from the 2-byte shorts
|
|
143
|
-
guid->Data4[0] = (unsigned char)((tmp[0] >> 8) & 0xFF);
|
|
144
|
-
guid->Data4[1] = (unsigned char)(tmp[0] & 0xFF);
|
|
145
|
-
guid->Data4[2] = (unsigned char)((tmp[1] >> 8) & 0xFF);
|
|
146
|
-
guid->Data4[3] = (unsigned char)(tmp[1] & 0xFF);
|
|
147
|
-
guid->Data4[4] = (unsigned char)((tmp[2] >> 8) & 0xFF);
|
|
148
|
-
guid->Data4[5] = (unsigned char)(tmp[2] & 0xFF);
|
|
149
|
-
guid->Data4[6] = (unsigned char)((tmp[3] >> 8) & 0xFF);
|
|
150
|
-
guid->Data4[7] = (unsigned char)(tmp[3] & 0xFF);
|
|
151
|
-
|
|
152
|
-
return true;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/*
|
|
156
|
-
* Normalize Microsoft's paths: return a duplicate of the given path
|
|
157
|
-
* with all characters converted to uppercase
|
|
158
|
-
*/
|
|
159
|
-
static char *normalize_path(const char *path)
|
|
160
|
-
{
|
|
161
|
-
char *ret_path = _strdup(path);
|
|
162
|
-
char *p;
|
|
163
|
-
|
|
164
|
-
if (ret_path == NULL)
|
|
165
|
-
return NULL;
|
|
166
|
-
|
|
167
|
-
for (p = ret_path; *p != '\0'; p++)
|
|
168
|
-
*p = (char)toupper((unsigned char)*p);
|
|
169
|
-
|
|
170
|
-
return ret_path;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
/*
|
|
174
|
-
* Cfgmgr32, AdvAPI32, OLE32 and SetupAPI DLL functions
|
|
175
|
-
*/
|
|
176
|
-
static bool init_dlls(struct libusb_context *ctx)
|
|
177
|
-
{
|
|
178
|
-
DLL_GET_HANDLE(ctx, Cfgmgr32);
|
|
179
|
-
DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Parent, true);
|
|
180
|
-
DLL_LOAD_FUNC(Cfgmgr32, CM_Get_Child, true);
|
|
181
|
-
|
|
182
|
-
// Prefixed to avoid conflict with header files
|
|
183
|
-
DLL_GET_HANDLE(ctx, AdvAPI32);
|
|
184
|
-
DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegQueryValueExA, true);
|
|
185
|
-
DLL_LOAD_FUNC_PREFIXED(AdvAPI32, p, RegCloseKey, true);
|
|
186
|
-
|
|
187
|
-
DLL_GET_HANDLE(ctx, SetupAPI);
|
|
188
|
-
DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetClassDevsA, true);
|
|
189
|
-
DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInfo, true);
|
|
190
|
-
DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiEnumDeviceInterfaces, true);
|
|
191
|
-
DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInstanceIdA, true);
|
|
192
|
-
DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceInterfaceDetailA, true);
|
|
193
|
-
DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiGetDeviceRegistryPropertyA, true);
|
|
194
|
-
DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiDestroyDeviceInfoList, true);
|
|
195
|
-
DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDevRegKey, true);
|
|
196
|
-
DLL_LOAD_FUNC_PREFIXED(SetupAPI, p, SetupDiOpenDeviceInterfaceRegKey, true);
|
|
197
|
-
|
|
198
|
-
return true;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
static void exit_dlls(void)
|
|
202
|
-
{
|
|
203
|
-
DLL_FREE_HANDLE(SetupAPI);
|
|
204
|
-
DLL_FREE_HANDLE(AdvAPI32);
|
|
205
|
-
DLL_FREE_HANDLE(Cfgmgr32);
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/*
|
|
209
|
-
* enumerate interfaces for the whole USB class
|
|
210
|
-
*
|
|
211
|
-
* Parameters:
|
|
212
|
-
* dev_info: a pointer to a dev_info list
|
|
213
|
-
* dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed)
|
|
214
|
-
* enumerator: the generic USB class for which to retrieve interface details
|
|
215
|
-
* index: zero based index of the interface in the device info list
|
|
216
|
-
*
|
|
217
|
-
* Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA
|
|
218
|
-
* structure returned and call this function repeatedly using the same guid (with an
|
|
219
|
-
* incremented index starting at zero) until all interfaces have been returned.
|
|
220
|
-
*/
|
|
221
|
-
static bool get_devinfo_data(struct libusb_context *ctx,
|
|
222
|
-
HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, const char *enumerator, unsigned _index)
|
|
223
|
-
{
|
|
224
|
-
if (_index == 0) {
|
|
225
|
-
*dev_info = pSetupDiGetClassDevsA(NULL, enumerator, NULL, DIGCF_PRESENT|DIGCF_ALLCLASSES);
|
|
226
|
-
if (*dev_info == INVALID_HANDLE_VALUE) {
|
|
227
|
-
usbi_err(ctx, "could not obtain device info set for PnP enumerator '%s': %s",
|
|
228
|
-
enumerator, windows_error_str(0));
|
|
229
|
-
return false;
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
|
|
234
|
-
if (!pSetupDiEnumDeviceInfo(*dev_info, _index, dev_info_data)) {
|
|
235
|
-
if (GetLastError() != ERROR_NO_MORE_ITEMS)
|
|
236
|
-
usbi_err(ctx, "could not obtain device info data for PnP enumerator '%s' index %u: %s",
|
|
237
|
-
enumerator, _index, windows_error_str(0));
|
|
238
|
-
|
|
239
|
-
pSetupDiDestroyDeviceInfoList(*dev_info);
|
|
240
|
-
*dev_info = INVALID_HANDLE_VALUE;
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
return true;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/*
|
|
247
|
-
* enumerate interfaces for a specific GUID
|
|
248
|
-
*
|
|
249
|
-
* Parameters:
|
|
250
|
-
* dev_info: a pointer to a dev_info list
|
|
251
|
-
* dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed)
|
|
252
|
-
* guid: the GUID for which to retrieve interface details
|
|
253
|
-
* index: zero based index of the interface in the device info list
|
|
254
|
-
*
|
|
255
|
-
* Note: it is the responsibility of the caller to free the DEVICE_INTERFACE_DETAIL_DATA
|
|
256
|
-
* structure returned and call this function repeatedly using the same guid (with an
|
|
257
|
-
* incremented index starting at zero) until all interfaces have been returned.
|
|
258
|
-
*/
|
|
259
|
-
static int get_interface_details(struct libusb_context *ctx, HDEVINFO dev_info,
|
|
260
|
-
PSP_DEVINFO_DATA dev_info_data, LPCGUID guid, DWORD *_index, char **dev_interface_path)
|
|
261
|
-
{
|
|
262
|
-
SP_DEVICE_INTERFACE_DATA dev_interface_data;
|
|
263
|
-
PSP_DEVICE_INTERFACE_DETAIL_DATA_A dev_interface_details;
|
|
264
|
-
char guid_string[MAX_GUID_STRING_LENGTH];
|
|
265
|
-
DWORD size;
|
|
266
|
-
|
|
267
|
-
#ifndef ENABLE_LOGGING
|
|
268
|
-
UNUSED(*guid_string);
|
|
269
|
-
#endif
|
|
270
|
-
dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
|
|
271
|
-
dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
|
272
|
-
for (;;) {
|
|
273
|
-
if (!pSetupDiEnumDeviceInfo(dev_info, *_index, dev_info_data)) {
|
|
274
|
-
if (GetLastError() != ERROR_NO_MORE_ITEMS) {
|
|
275
|
-
usbi_err(ctx, "Could not obtain device info data for %s index %lu: %s",
|
|
276
|
-
guid_to_string(guid, guid_string), ULONG_CAST(*_index), windows_error_str(0));
|
|
277
|
-
return LIBUSB_ERROR_OTHER;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// No more devices
|
|
281
|
-
return LIBUSB_SUCCESS;
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Always advance the index for the next iteration
|
|
285
|
-
(*_index)++;
|
|
286
|
-
|
|
287
|
-
if (pSetupDiEnumDeviceInterfaces(dev_info, dev_info_data, guid, 0, &dev_interface_data))
|
|
288
|
-
break;
|
|
289
|
-
|
|
290
|
-
if (GetLastError() != ERROR_NO_MORE_ITEMS) {
|
|
291
|
-
usbi_err(ctx, "Could not obtain interface data for %s devInst %lX: %s",
|
|
292
|
-
guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0));
|
|
293
|
-
return LIBUSB_ERROR_OTHER;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// Device does not have an interface matching this GUID, skip
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
// Read interface data (dummy + actual) to access the device path
|
|
300
|
-
if (!pSetupDiGetDeviceInterfaceDetailA(dev_info, &dev_interface_data, NULL, 0, &size, NULL)) {
|
|
301
|
-
// The dummy call should fail with ERROR_INSUFFICIENT_BUFFER
|
|
302
|
-
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
303
|
-
usbi_err(ctx, "could not access interface data (dummy) for %s devInst %lX: %s",
|
|
304
|
-
guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0));
|
|
305
|
-
return LIBUSB_ERROR_OTHER;
|
|
306
|
-
}
|
|
307
|
-
} else {
|
|
308
|
-
usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong");
|
|
309
|
-
return LIBUSB_ERROR_OTHER;
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
dev_interface_details = malloc(size);
|
|
313
|
-
if (dev_interface_details == NULL) {
|
|
314
|
-
usbi_err(ctx, "could not allocate interface data for %s devInst %lX",
|
|
315
|
-
guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst));
|
|
316
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
|
|
320
|
-
if (!pSetupDiGetDeviceInterfaceDetailA(dev_info, &dev_interface_data,
|
|
321
|
-
dev_interface_details, size, NULL, NULL)) {
|
|
322
|
-
usbi_err(ctx, "could not access interface data (actual) for %s devInst %lX: %s",
|
|
323
|
-
guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst), windows_error_str(0));
|
|
324
|
-
free(dev_interface_details);
|
|
325
|
-
return LIBUSB_ERROR_OTHER;
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
*dev_interface_path = normalize_path(dev_interface_details->DevicePath);
|
|
329
|
-
free(dev_interface_details);
|
|
330
|
-
|
|
331
|
-
if (*dev_interface_path == NULL) {
|
|
332
|
-
usbi_err(ctx, "could not allocate interface path for %s devInst %lX",
|
|
333
|
-
guid_to_string(guid, guid_string), ULONG_CAST(dev_info_data->DevInst));
|
|
334
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
return LIBUSB_SUCCESS;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
/* For libusb0 filter */
|
|
341
|
-
static int get_interface_details_filter(struct libusb_context *ctx, HDEVINFO *dev_info,
|
|
342
|
-
DWORD _index, char *filter_path, char **dev_interface_path)
|
|
343
|
-
{
|
|
344
|
-
const GUID *libusb0_guid = &GUID_DEVINTERFACE_LIBUSB0_FILTER;
|
|
345
|
-
SP_DEVICE_INTERFACE_DATA dev_interface_data;
|
|
346
|
-
PSP_DEVICE_INTERFACE_DETAIL_DATA_A dev_interface_details;
|
|
347
|
-
HKEY hkey_dev_interface;
|
|
348
|
-
DWORD size;
|
|
349
|
-
int err = LIBUSB_ERROR_OTHER;
|
|
350
|
-
|
|
351
|
-
if (_index == 0) {
|
|
352
|
-
*dev_info = pSetupDiGetClassDevsA(libusb0_guid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
|
353
|
-
if (*dev_info == INVALID_HANDLE_VALUE) {
|
|
354
|
-
usbi_err(ctx, "could not obtain device info set: %s", windows_error_str(0));
|
|
355
|
-
return LIBUSB_ERROR_OTHER;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
|
360
|
-
if (!pSetupDiEnumDeviceInterfaces(*dev_info, NULL, libusb0_guid, _index, &dev_interface_data)) {
|
|
361
|
-
if (GetLastError() != ERROR_NO_MORE_ITEMS) {
|
|
362
|
-
usbi_err(ctx, "Could not obtain interface data for index %lu: %s",
|
|
363
|
-
ULONG_CAST(_index), windows_error_str(0));
|
|
364
|
-
goto err_exit;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
pSetupDiDestroyDeviceInfoList(*dev_info);
|
|
368
|
-
*dev_info = INVALID_HANDLE_VALUE;
|
|
369
|
-
return LIBUSB_SUCCESS;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Read interface data (dummy + actual) to access the device path
|
|
373
|
-
if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, NULL, 0, &size, NULL)) {
|
|
374
|
-
// The dummy call should fail with ERROR_INSUFFICIENT_BUFFER
|
|
375
|
-
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
|
376
|
-
usbi_err(ctx, "could not access interface data (dummy) for index %lu: %s",
|
|
377
|
-
ULONG_CAST(_index), windows_error_str(0));
|
|
378
|
-
goto err_exit;
|
|
379
|
-
}
|
|
380
|
-
} else {
|
|
381
|
-
usbi_err(ctx, "program assertion failed - http://msdn.microsoft.com/en-us/library/ms792901.aspx is wrong");
|
|
382
|
-
goto err_exit;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
dev_interface_details = malloc(size);
|
|
386
|
-
if (dev_interface_details == NULL) {
|
|
387
|
-
usbi_err(ctx, "could not allocate interface data for index %lu", ULONG_CAST(_index));
|
|
388
|
-
err = LIBUSB_ERROR_NO_MEM;
|
|
389
|
-
goto err_exit;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
dev_interface_details->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
|
|
393
|
-
if (!pSetupDiGetDeviceInterfaceDetailA(*dev_info, &dev_interface_data, dev_interface_details, size, NULL, NULL)) {
|
|
394
|
-
usbi_err(ctx, "could not access interface data (actual) for index %lu: %s",
|
|
395
|
-
ULONG_CAST(_index), windows_error_str(0));
|
|
396
|
-
free(dev_interface_details);
|
|
397
|
-
goto err_exit;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
*dev_interface_path = normalize_path(dev_interface_details->DevicePath);
|
|
401
|
-
free(dev_interface_details);
|
|
402
|
-
|
|
403
|
-
if (*dev_interface_path == NULL) {
|
|
404
|
-
usbi_err(ctx, "could not allocate interface path for index %lu", ULONG_CAST(_index));
|
|
405
|
-
err = LIBUSB_ERROR_NO_MEM;
|
|
406
|
-
goto err_exit;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
// [trobinso] lookup the libusb0 symbolic index.
|
|
410
|
-
hkey_dev_interface = pSetupDiOpenDeviceInterfaceRegKey(*dev_info, &dev_interface_data, 0, KEY_READ);
|
|
411
|
-
if (hkey_dev_interface != INVALID_HANDLE_VALUE) {
|
|
412
|
-
DWORD libusb0_symboliclink_index = 0;
|
|
413
|
-
DWORD value_length = sizeof(DWORD);
|
|
414
|
-
LONG status;
|
|
415
|
-
|
|
416
|
-
status = pRegQueryValueExA(hkey_dev_interface, "LUsb0", NULL, NULL,
|
|
417
|
-
(LPBYTE)&libusb0_symboliclink_index, &value_length);
|
|
418
|
-
if (status == ERROR_SUCCESS) {
|
|
419
|
-
if (libusb0_symboliclink_index < 256) {
|
|
420
|
-
// libusb0.sys is connected to this device instance.
|
|
421
|
-
// If the the device interface guid is {F9F3FF14-AE21-48A0-8A25-8011A7A931D9} then it's a filter.
|
|
422
|
-
sprintf(filter_path, "\\\\.\\libusb0-%04u", (unsigned int)libusb0_symboliclink_index);
|
|
423
|
-
usbi_dbg(ctx, "assigned libusb0 symbolic link %s", filter_path);
|
|
424
|
-
} else {
|
|
425
|
-
// libusb0.sys was connected to this device instance at one time; but not anymore.
|
|
426
|
-
}
|
|
427
|
-
}
|
|
428
|
-
pRegCloseKey(hkey_dev_interface);
|
|
429
|
-
} else {
|
|
430
|
-
usbi_warn(ctx, "could not open device interface registry key for index %lu: %s",
|
|
431
|
-
ULONG_CAST(_index), windows_error_str(0));
|
|
432
|
-
// TODO: should this be an error?
|
|
433
|
-
}
|
|
434
|
-
|
|
435
|
-
return LIBUSB_SUCCESS;
|
|
436
|
-
|
|
437
|
-
err_exit:
|
|
438
|
-
pSetupDiDestroyDeviceInfoList(*dev_info);
|
|
439
|
-
*dev_info = INVALID_HANDLE_VALUE;
|
|
440
|
-
return err;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
/*
|
|
444
|
-
* Returns the first known ancestor of a device
|
|
445
|
-
*/
|
|
446
|
-
static struct libusb_device *get_ancestor(struct libusb_context *ctx,
|
|
447
|
-
DEVINST devinst, PDEVINST _parent_devinst)
|
|
448
|
-
{
|
|
449
|
-
struct libusb_device *dev = NULL;
|
|
450
|
-
DEVINST parent_devinst;
|
|
451
|
-
|
|
452
|
-
while (dev == NULL) {
|
|
453
|
-
if (CM_Get_Parent(&parent_devinst, devinst, 0) != CR_SUCCESS)
|
|
454
|
-
break;
|
|
455
|
-
devinst = parent_devinst;
|
|
456
|
-
dev = usbi_get_device_by_session_id(ctx, (unsigned long)devinst);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
if ((dev != NULL) && (_parent_devinst != NULL))
|
|
460
|
-
*_parent_devinst = devinst;
|
|
461
|
-
|
|
462
|
-
return dev;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
/*
|
|
466
|
-
* Determine which interface the given endpoint address belongs to
|
|
467
|
-
*/
|
|
468
|
-
static int get_interface_by_endpoint(struct libusb_config_descriptor *conf_desc, uint8_t ep)
|
|
469
|
-
{
|
|
470
|
-
const struct libusb_interface *intf;
|
|
471
|
-
const struct libusb_interface_descriptor *intf_desc;
|
|
472
|
-
uint8_t i, k;
|
|
473
|
-
int j;
|
|
474
|
-
|
|
475
|
-
for (i = 0; i < conf_desc->bNumInterfaces; i++) {
|
|
476
|
-
intf = &conf_desc->interface[i];
|
|
477
|
-
for (j = 0; j < intf->num_altsetting; j++) {
|
|
478
|
-
intf_desc = &intf->altsetting[j];
|
|
479
|
-
for (k = 0; k < intf_desc->bNumEndpoints; k++) {
|
|
480
|
-
if (intf_desc->endpoint[k].bEndpointAddress == ep) {
|
|
481
|
-
usbi_dbg(NULL, "found endpoint %02X on interface %d", intf_desc->bInterfaceNumber, i);
|
|
482
|
-
return intf_desc->bInterfaceNumber;
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
|
|
488
|
-
usbi_dbg(NULL, "endpoint %02X not found on any interface", ep);
|
|
489
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
static const struct libusb_interface_descriptor *get_interface_descriptor_by_number(struct libusb_device_handle *dev_handle, struct libusb_config_descriptor *conf_desc, int iface, uint8_t altsetting)
|
|
493
|
-
{
|
|
494
|
-
int i;
|
|
495
|
-
|
|
496
|
-
for (i = 0; i < conf_desc->bNumInterfaces; i++) {
|
|
497
|
-
if (altsetting < conf_desc->interface[i].num_altsetting && conf_desc->interface[i].altsetting[altsetting].bInterfaceNumber == iface) {
|
|
498
|
-
return &conf_desc->interface[i].altsetting[altsetting];
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
usbi_err(HANDLE_CTX(dev_handle), "interface %d with altsetting %d not found for device", iface, (int)altsetting);
|
|
503
|
-
return NULL;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
/*
|
|
507
|
-
* Open a device and associate the HANDLE with the context's I/O completion port
|
|
508
|
-
*/
|
|
509
|
-
static HANDLE windows_open(struct libusb_device_handle *dev_handle, const char *path, DWORD access)
|
|
510
|
-
{
|
|
511
|
-
struct libusb_context *ctx = HANDLE_CTX(dev_handle);
|
|
512
|
-
struct windows_context_priv *priv = usbi_get_context_priv(ctx);
|
|
513
|
-
HANDLE handle;
|
|
514
|
-
|
|
515
|
-
handle = CreateFileA(path, access, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
|
|
516
|
-
if (handle == INVALID_HANDLE_VALUE)
|
|
517
|
-
return handle;
|
|
518
|
-
|
|
519
|
-
if (CreateIoCompletionPort(handle, priv->completion_port, (ULONG_PTR)dev_handle, 0) == NULL) {
|
|
520
|
-
usbi_err(ctx, "failed to associate handle to I/O completion port: %s", windows_error_str(0));
|
|
521
|
-
CloseHandle(handle);
|
|
522
|
-
return INVALID_HANDLE_VALUE;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
return handle;
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
/*
|
|
529
|
-
* Populate the endpoints addresses of the device_priv interface helper structs
|
|
530
|
-
*/
|
|
531
|
-
static int windows_assign_endpoints(struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
|
|
532
|
-
{
|
|
533
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
534
|
-
struct libusb_config_descriptor *conf_desc;
|
|
535
|
-
const struct libusb_interface_descriptor *if_desc;
|
|
536
|
-
int i, r;
|
|
537
|
-
|
|
538
|
-
r = libusb_get_active_config_descriptor(dev_handle->dev, &conf_desc);
|
|
539
|
-
if (r != LIBUSB_SUCCESS) {
|
|
540
|
-
usbi_warn(HANDLE_CTX(dev_handle), "could not read config descriptor: error %d", r);
|
|
541
|
-
return r;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
if_desc = get_interface_descriptor_by_number(dev_handle, conf_desc, iface, altsetting);
|
|
545
|
-
if (if_desc == NULL) {
|
|
546
|
-
r = LIBUSB_ERROR_NOT_FOUND;
|
|
547
|
-
goto end;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
safe_free(priv->usb_interface[iface].endpoint);
|
|
551
|
-
|
|
552
|
-
if (if_desc->bNumEndpoints == 0) {
|
|
553
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "no endpoints found for interface %u", iface);
|
|
554
|
-
} else {
|
|
555
|
-
priv->usb_interface[iface].endpoint = malloc(if_desc->bNumEndpoints);
|
|
556
|
-
if (priv->usb_interface[iface].endpoint == NULL) {
|
|
557
|
-
r = LIBUSB_ERROR_NO_MEM;
|
|
558
|
-
goto end;
|
|
559
|
-
}
|
|
560
|
-
priv->usb_interface[iface].nb_endpoints = if_desc->bNumEndpoints;
|
|
561
|
-
for (i = 0; i < if_desc->bNumEndpoints; i++) {
|
|
562
|
-
priv->usb_interface[iface].endpoint[i] = if_desc->endpoint[i].bEndpointAddress;
|
|
563
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "(re)assigned endpoint %02X to interface %u", priv->usb_interface[iface].endpoint[i], iface);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
// Extra init may be required to configure endpoints
|
|
568
|
-
if (priv->apib->configure_endpoints)
|
|
569
|
-
r = priv->apib->configure_endpoints(SUB_API_NOTSET, dev_handle, iface);
|
|
570
|
-
|
|
571
|
-
if (r == LIBUSB_SUCCESS)
|
|
572
|
-
priv->usb_interface[iface].current_altsetting = altsetting;
|
|
573
|
-
|
|
574
|
-
end:
|
|
575
|
-
libusb_free_config_descriptor(conf_desc);
|
|
576
|
-
return r;
|
|
577
|
-
}
|
|
578
|
-
|
|
579
|
-
// Lookup for a match in the list of API driver names
|
|
580
|
-
// return -1 if not found, driver match number otherwise
|
|
581
|
-
static int get_sub_api(char *driver, int api)
|
|
582
|
-
{
|
|
583
|
-
const char sep_str[2] = {LIST_SEPARATOR, 0};
|
|
584
|
-
char *tok, *tmp_str;
|
|
585
|
-
size_t len = strlen(driver);
|
|
586
|
-
int i;
|
|
587
|
-
|
|
588
|
-
if (len == 0)
|
|
589
|
-
return SUB_API_NOTSET;
|
|
590
|
-
|
|
591
|
-
tmp_str = _strdup(driver);
|
|
592
|
-
if (tmp_str == NULL)
|
|
593
|
-
return SUB_API_NOTSET;
|
|
594
|
-
|
|
595
|
-
tok = strtok(tmp_str, sep_str);
|
|
596
|
-
while (tok != NULL) {
|
|
597
|
-
for (i = 0; i < usb_api_backend[api].nb_driver_names; i++) {
|
|
598
|
-
if (_stricmp(tok, usb_api_backend[api].driver_name_list[i]) == 0) {
|
|
599
|
-
free(tmp_str);
|
|
600
|
-
return i;
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
tok = strtok(NULL, sep_str);
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
free(tmp_str);
|
|
607
|
-
return SUB_API_NOTSET;
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
/*
|
|
611
|
-
* auto-claiming and auto-release helper functions
|
|
612
|
-
*/
|
|
613
|
-
static int auto_claim(struct libusb_transfer *transfer, int *interface_number, int api_type)
|
|
614
|
-
{
|
|
615
|
-
struct winusb_device_handle_priv *handle_priv =
|
|
616
|
-
get_winusb_device_handle_priv(transfer->dev_handle);
|
|
617
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
618
|
-
int current_interface = *interface_number;
|
|
619
|
-
int r = LIBUSB_SUCCESS;
|
|
620
|
-
|
|
621
|
-
switch (api_type) {
|
|
622
|
-
case USB_API_WINUSBX:
|
|
623
|
-
case USB_API_HID:
|
|
624
|
-
break;
|
|
625
|
-
default:
|
|
626
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
usbi_mutex_lock(&autoclaim_lock);
|
|
630
|
-
if (current_interface < 0) { // No serviceable interface was found
|
|
631
|
-
for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) {
|
|
632
|
-
// Must claim an interface of the same API type
|
|
633
|
-
if ((priv->usb_interface[current_interface].apib->id == api_type)
|
|
634
|
-
&& (libusb_claim_interface(transfer->dev_handle, current_interface) == LIBUSB_SUCCESS)) {
|
|
635
|
-
usbi_dbg(TRANSFER_CTX(transfer), "auto-claimed interface %d for control request", current_interface);
|
|
636
|
-
if (handle_priv->autoclaim_count[current_interface] != 0)
|
|
637
|
-
usbi_err(TRANSFER_CTX(transfer), "program assertion failed - autoclaim_count was nonzero");
|
|
638
|
-
handle_priv->autoclaim_count[current_interface]++;
|
|
639
|
-
break;
|
|
640
|
-
}
|
|
641
|
-
}
|
|
642
|
-
if (current_interface == USB_MAXINTERFACES) {
|
|
643
|
-
usbi_err(TRANSFER_CTX(transfer), "could not auto-claim any interface");
|
|
644
|
-
r = LIBUSB_ERROR_NOT_FOUND;
|
|
645
|
-
}
|
|
646
|
-
} else {
|
|
647
|
-
// If we have a valid interface that was autoclaimed, we must increment
|
|
648
|
-
// its autoclaim count so that we can prevent an early release.
|
|
649
|
-
if (handle_priv->autoclaim_count[current_interface] != 0)
|
|
650
|
-
handle_priv->autoclaim_count[current_interface]++;
|
|
651
|
-
}
|
|
652
|
-
usbi_mutex_unlock(&autoclaim_lock);
|
|
653
|
-
|
|
654
|
-
*interface_number = current_interface;
|
|
655
|
-
return r;
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
static void auto_release(struct usbi_transfer *itransfer)
|
|
659
|
-
{
|
|
660
|
-
struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
|
|
661
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
662
|
-
libusb_device_handle *dev_handle = transfer->dev_handle;
|
|
663
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
664
|
-
int r;
|
|
665
|
-
|
|
666
|
-
usbi_mutex_lock(&autoclaim_lock);
|
|
667
|
-
if (handle_priv->autoclaim_count[transfer_priv->interface_number] > 0) {
|
|
668
|
-
handle_priv->autoclaim_count[transfer_priv->interface_number]--;
|
|
669
|
-
if (handle_priv->autoclaim_count[transfer_priv->interface_number] == 0) {
|
|
670
|
-
r = libusb_release_interface(dev_handle, transfer_priv->interface_number);
|
|
671
|
-
if (r == LIBUSB_SUCCESS)
|
|
672
|
-
usbi_dbg(ITRANSFER_CTX(itransfer), "auto-released interface %d", transfer_priv->interface_number);
|
|
673
|
-
else
|
|
674
|
-
usbi_dbg(ITRANSFER_CTX(itransfer), "failed to auto-release interface %d (%s)",
|
|
675
|
-
transfer_priv->interface_number, libusb_error_name((enum libusb_error)r));
|
|
676
|
-
}
|
|
677
|
-
}
|
|
678
|
-
usbi_mutex_unlock(&autoclaim_lock);
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
/*
|
|
682
|
-
* init: libusb backend init function
|
|
683
|
-
*/
|
|
684
|
-
static int winusb_init(struct libusb_context *ctx)
|
|
685
|
-
{
|
|
686
|
-
int i;
|
|
687
|
-
|
|
688
|
-
// Load DLL imports
|
|
689
|
-
if (!init_dlls(ctx)) {
|
|
690
|
-
usbi_err(ctx, "could not resolve DLL functions");
|
|
691
|
-
return LIBUSB_ERROR_OTHER;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
// Initialize the low level APIs (we don't care about errors at this stage)
|
|
695
|
-
for (i = 0; i < USB_API_MAX; i++) {
|
|
696
|
-
if (usb_api_backend[i].init && !usb_api_backend[i].init(ctx))
|
|
697
|
-
usbi_warn(ctx, "error initializing %s backend",
|
|
698
|
-
usb_api_backend[i].designation);
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
// We need a lock for proper auto-release
|
|
702
|
-
usbi_mutex_init(&autoclaim_lock);
|
|
703
|
-
|
|
704
|
-
return LIBUSB_SUCCESS;
|
|
705
|
-
}
|
|
706
|
-
|
|
707
|
-
/*
|
|
708
|
-
* exit: libusb backend deinitialization function
|
|
709
|
-
*/
|
|
710
|
-
static void winusb_exit(struct libusb_context *ctx)
|
|
711
|
-
{
|
|
712
|
-
int i;
|
|
713
|
-
|
|
714
|
-
UNUSED(ctx);
|
|
715
|
-
|
|
716
|
-
usbi_mutex_destroy(&autoclaim_lock);
|
|
717
|
-
|
|
718
|
-
for (i = 0; i < USB_API_MAX; i++) {
|
|
719
|
-
if (usb_api_backend[i].exit)
|
|
720
|
-
usb_api_backend[i].exit();
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
exit_dlls();
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
/*
|
|
727
|
-
* fetch and cache all the config descriptors through I/O
|
|
728
|
-
*/
|
|
729
|
-
static void cache_config_descriptors(struct libusb_device *dev, HANDLE hub_handle)
|
|
730
|
-
{
|
|
731
|
-
struct libusb_context *ctx = DEVICE_CTX(dev);
|
|
732
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
|
|
733
|
-
DWORD size, ret_size;
|
|
734
|
-
uint8_t i, num_configurations;
|
|
735
|
-
|
|
736
|
-
USB_CONFIGURATION_DESCRIPTOR_SHORT cd_buf_short; // dummy request
|
|
737
|
-
PUSB_DESCRIPTOR_REQUEST cd_buf_actual = NULL; // actual request
|
|
738
|
-
PUSB_CONFIGURATION_DESCRIPTOR cd_data;
|
|
739
|
-
|
|
740
|
-
num_configurations = dev->device_descriptor.bNumConfigurations;
|
|
741
|
-
if (num_configurations == 0)
|
|
742
|
-
return;
|
|
743
|
-
|
|
744
|
-
assert(sizeof(USB_DESCRIPTOR_REQUEST) == USB_DESCRIPTOR_REQUEST_SIZE);
|
|
745
|
-
|
|
746
|
-
priv->config_descriptor = calloc(num_configurations, sizeof(PUSB_CONFIGURATION_DESCRIPTOR));
|
|
747
|
-
if (priv->config_descriptor == NULL) {
|
|
748
|
-
usbi_err(ctx, "could not allocate configuration descriptor array for '%s'", priv->dev_id);
|
|
749
|
-
return;
|
|
750
|
-
}
|
|
751
|
-
|
|
752
|
-
for (i = 0; i <= num_configurations; i++) {
|
|
753
|
-
safe_free(cd_buf_actual);
|
|
754
|
-
|
|
755
|
-
if (i == num_configurations)
|
|
756
|
-
break;
|
|
757
|
-
|
|
758
|
-
size = sizeof(cd_buf_short);
|
|
759
|
-
memset(&cd_buf_short.desc, 0, sizeof(cd_buf_short.desc));
|
|
760
|
-
|
|
761
|
-
cd_buf_short.req.ConnectionIndex = (ULONG)dev->port_number;
|
|
762
|
-
cd_buf_short.req.SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
|
|
763
|
-
cd_buf_short.req.SetupPacket.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR;
|
|
764
|
-
cd_buf_short.req.SetupPacket.wValue = (LIBUSB_DT_CONFIG << 8) | i;
|
|
765
|
-
cd_buf_short.req.SetupPacket.wIndex = 0;
|
|
766
|
-
cd_buf_short.req.SetupPacket.wLength = (USHORT)sizeof(USB_CONFIGURATION_DESCRIPTOR);
|
|
767
|
-
|
|
768
|
-
// Dummy call to get the required data size. Initial failures are reported as info rather
|
|
769
|
-
// than error as they can occur for non-penalizing situations, such as with some hubs.
|
|
770
|
-
// coverity[tainted_data_argument]
|
|
771
|
-
if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, &cd_buf_short, size,
|
|
772
|
-
&cd_buf_short, size, &ret_size, NULL)) {
|
|
773
|
-
usbi_info(ctx, "could not access configuration descriptor %u (dummy) for '%s': %s", i, priv->dev_id, windows_error_str(0));
|
|
774
|
-
continue;
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
if ((ret_size != size) || (cd_buf_short.desc.wTotalLength < sizeof(USB_CONFIGURATION_DESCRIPTOR))) {
|
|
778
|
-
usbi_info(ctx, "unexpected configuration descriptor %u size (dummy) for '%s'", i, priv->dev_id);
|
|
779
|
-
continue;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
size = sizeof(USB_DESCRIPTOR_REQUEST) + cd_buf_short.desc.wTotalLength;
|
|
783
|
-
cd_buf_actual = malloc(size);
|
|
784
|
-
if (cd_buf_actual == NULL) {
|
|
785
|
-
usbi_err(ctx, "could not allocate configuration descriptor %u buffer for '%s'", i, priv->dev_id);
|
|
786
|
-
continue;
|
|
787
|
-
}
|
|
788
|
-
|
|
789
|
-
// Actual call
|
|
790
|
-
cd_buf_actual->ConnectionIndex = (ULONG)dev->port_number;
|
|
791
|
-
cd_buf_actual->SetupPacket.bmRequest = LIBUSB_ENDPOINT_IN;
|
|
792
|
-
cd_buf_actual->SetupPacket.bRequest = LIBUSB_REQUEST_GET_DESCRIPTOR;
|
|
793
|
-
cd_buf_actual->SetupPacket.wValue = (LIBUSB_DT_CONFIG << 8) | i;
|
|
794
|
-
cd_buf_actual->SetupPacket.wIndex = 0;
|
|
795
|
-
cd_buf_actual->SetupPacket.wLength = cd_buf_short.desc.wTotalLength;
|
|
796
|
-
|
|
797
|
-
if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, cd_buf_actual, size,
|
|
798
|
-
cd_buf_actual, size, &ret_size, NULL)) {
|
|
799
|
-
usbi_err(ctx, "could not access configuration descriptor %u (actual) for '%s': %s", i, priv->dev_id, windows_error_str(0));
|
|
800
|
-
continue;
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
cd_data = (PUSB_CONFIGURATION_DESCRIPTOR)((UCHAR *)cd_buf_actual + USB_DESCRIPTOR_REQUEST_SIZE);
|
|
804
|
-
|
|
805
|
-
if ((size != ret_size) || (cd_data->wTotalLength != cd_buf_short.desc.wTotalLength)) {
|
|
806
|
-
usbi_err(ctx, "unexpected configuration descriptor %u size (actual) for '%s'", i, priv->dev_id);
|
|
807
|
-
continue;
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
if (cd_data->bDescriptorType != LIBUSB_DT_CONFIG) {
|
|
811
|
-
usbi_err(ctx, "descriptor %u not a configuration descriptor for '%s'", i, priv->dev_id);
|
|
812
|
-
continue;
|
|
813
|
-
}
|
|
814
|
-
|
|
815
|
-
usbi_dbg(ctx, "cached config descriptor %u (bConfigurationValue=%u, %u bytes)",
|
|
816
|
-
i, cd_data->bConfigurationValue, cd_data->wTotalLength);
|
|
817
|
-
|
|
818
|
-
// Cache the descriptor
|
|
819
|
-
priv->config_descriptor[i] = cd_data;
|
|
820
|
-
cd_buf_actual = NULL;
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
#define ROOT_HUB_FS_CONFIG_DESC_LENGTH 0x19
|
|
825
|
-
#define ROOT_HUB_HS_CONFIG_DESC_LENGTH 0x19
|
|
826
|
-
#define ROOT_HUB_SS_CONFIG_DESC_LENGTH 0x1f
|
|
827
|
-
#define CONFIG_DESC_WTOTAL_LENGTH_OFFSET 0x02
|
|
828
|
-
#define CONFIG_DESC_EP_MAX_PACKET_OFFSET 0x16
|
|
829
|
-
#define CONFIG_DESC_EP_BINTERVAL_OFFSET 0x18
|
|
830
|
-
|
|
831
|
-
static const uint8_t root_hub_config_descriptor_template[] = {
|
|
832
|
-
// Configuration Descriptor
|
|
833
|
-
LIBUSB_DT_CONFIG_SIZE, // bLength
|
|
834
|
-
LIBUSB_DT_CONFIG, // bDescriptorType
|
|
835
|
-
0x00, 0x00, // wTotalLength (filled in)
|
|
836
|
-
0x01, // bNumInterfaces
|
|
837
|
-
0x01, // bConfigurationValue
|
|
838
|
-
0x00, // iConfiguration
|
|
839
|
-
0xc0, // bmAttributes (reserved + self-powered)
|
|
840
|
-
0x00, // bMaxPower
|
|
841
|
-
// Interface Descriptor
|
|
842
|
-
LIBUSB_DT_INTERFACE_SIZE, // bLength
|
|
843
|
-
LIBUSB_DT_INTERFACE, // bDescriptorType
|
|
844
|
-
0x00, // bInterfaceNumber
|
|
845
|
-
0x00, // bAlternateSetting
|
|
846
|
-
0x01, // bNumEndpoints
|
|
847
|
-
LIBUSB_CLASS_HUB, // bInterfaceClass
|
|
848
|
-
0x00, // bInterfaceSubClass
|
|
849
|
-
0x00, // bInterfaceProtocol
|
|
850
|
-
0x00, // iInterface
|
|
851
|
-
// Endpoint Descriptor
|
|
852
|
-
LIBUSB_DT_ENDPOINT_SIZE, // bLength
|
|
853
|
-
LIBUSB_DT_ENDPOINT, // bDescriptorType
|
|
854
|
-
0x81, // bEndpointAddress
|
|
855
|
-
0x03, // bmAttributes (Interrupt)
|
|
856
|
-
0x00, 0x00, // wMaxPacketSize (filled in)
|
|
857
|
-
0x00, // bInterval (filled in)
|
|
858
|
-
// SuperSpeed Endpoint Companion Descriptor
|
|
859
|
-
LIBUSB_DT_SS_ENDPOINT_COMPANION_SIZE, // bLength
|
|
860
|
-
LIBUSB_DT_SS_ENDPOINT_COMPANION, // bDescriptorType
|
|
861
|
-
0x00, // bMaxBurst
|
|
862
|
-
0x00, // bmAttributes
|
|
863
|
-
0x02, 0x00 // wBytesPerInterval
|
|
864
|
-
};
|
|
865
|
-
|
|
866
|
-
static int alloc_root_hub_config_desc(struct libusb_device *dev, ULONG num_ports,
|
|
867
|
-
uint8_t config_desc_length, uint8_t ep_interval)
|
|
868
|
-
{
|
|
869
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
|
|
870
|
-
uint8_t *ptr;
|
|
871
|
-
|
|
872
|
-
priv->config_descriptor = malloc(sizeof(*priv->config_descriptor));
|
|
873
|
-
if (priv->config_descriptor == NULL)
|
|
874
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
875
|
-
|
|
876
|
-
// Most config descriptors come from cache_config_descriptors() which obtains the
|
|
877
|
-
// descriptors from the hub using an allocated USB_DESCRIPTOR_REQUEST structure.
|
|
878
|
-
// To avoid an extra malloc + memcpy we just hold on to the USB_DESCRIPTOR_REQUEST
|
|
879
|
-
// structure we already have and back up the pointer in windows_device_priv_release()
|
|
880
|
-
// when freeing the descriptors. To keep a single execution path, we need to offset
|
|
881
|
-
// the pointer here by the same amount.
|
|
882
|
-
ptr = malloc(USB_DESCRIPTOR_REQUEST_SIZE + config_desc_length);
|
|
883
|
-
if (ptr == NULL)
|
|
884
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
885
|
-
|
|
886
|
-
ptr += USB_DESCRIPTOR_REQUEST_SIZE;
|
|
887
|
-
|
|
888
|
-
memcpy(ptr, root_hub_config_descriptor_template, config_desc_length);
|
|
889
|
-
ptr[CONFIG_DESC_WTOTAL_LENGTH_OFFSET] = config_desc_length;
|
|
890
|
-
ptr[CONFIG_DESC_EP_MAX_PACKET_OFFSET] = (uint8_t)((num_ports + 7) / 8);
|
|
891
|
-
ptr[CONFIG_DESC_EP_BINTERVAL_OFFSET] = ep_interval;
|
|
892
|
-
|
|
893
|
-
priv->config_descriptor[0] = (PUSB_CONFIGURATION_DESCRIPTOR)ptr;
|
|
894
|
-
priv->active_config = 1;
|
|
895
|
-
|
|
896
|
-
return 0;
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
static int init_root_hub(struct libusb_device *dev)
|
|
900
|
-
{
|
|
901
|
-
struct libusb_context *ctx = DEVICE_CTX(dev);
|
|
902
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
|
|
903
|
-
USB_NODE_CONNECTION_INFORMATION_EX conn_info;
|
|
904
|
-
USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2;
|
|
905
|
-
USB_NODE_INFORMATION hub_info;
|
|
906
|
-
enum libusb_speed speed = LIBUSB_SPEED_UNKNOWN;
|
|
907
|
-
uint8_t config_desc_length;
|
|
908
|
-
uint8_t ep_interval;
|
|
909
|
-
HANDLE handle;
|
|
910
|
-
ULONG port_number, num_ports;
|
|
911
|
-
DWORD size;
|
|
912
|
-
int r;
|
|
913
|
-
|
|
914
|
-
// Determining the speed of a root hub is painful. Microsoft does not directly report the speed
|
|
915
|
-
// capabilities of the root hub itself, only its ports and/or connected devices. Therefore we
|
|
916
|
-
// are forced to query each individual port of the root hub to try and infer the root hub's
|
|
917
|
-
// speed. Note that we have to query all ports because the presence of a device on that port
|
|
918
|
-
// changes if/how Windows returns any useful speed information.
|
|
919
|
-
handle = CreateFileA(priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
920
|
-
if (handle == INVALID_HANDLE_VALUE) {
|
|
921
|
-
usbi_err(ctx, "could not open root hub %s: %s", priv->path, windows_error_str(0));
|
|
922
|
-
return LIBUSB_ERROR_ACCESS;
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_INFORMATION, NULL, 0, &hub_info, sizeof(hub_info), &size, NULL)) {
|
|
926
|
-
usbi_warn(ctx, "could not get root hub info for '%s': %s", priv->dev_id, windows_error_str(0));
|
|
927
|
-
CloseHandle(handle);
|
|
928
|
-
return LIBUSB_ERROR_ACCESS;
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
num_ports = hub_info.u.HubInformation.HubDescriptor.bNumberOfPorts;
|
|
932
|
-
usbi_dbg(ctx, "root hub '%s' reports %lu ports", priv->dev_id, ULONG_CAST(num_ports));
|
|
933
|
-
|
|
934
|
-
if (windows_version >= WINDOWS_8) {
|
|
935
|
-
// Windows 8 and later is better at reporting the speed capabilities of the root hub,
|
|
936
|
-
// but it is not perfect. If no device is attached to the port being queried, the
|
|
937
|
-
// returned information will only indicate whether that port supports USB 3.0 signalling.
|
|
938
|
-
// That is not enough information to distinguish between SuperSpeed and SuperSpeed Plus.
|
|
939
|
-
for (port_number = 1; port_number <= num_ports; port_number++) {
|
|
940
|
-
conn_info_v2.ConnectionIndex = port_number;
|
|
941
|
-
conn_info_v2.Length = sizeof(conn_info_v2);
|
|
942
|
-
conn_info_v2.SupportedUsbProtocols.Usb300 = 1;
|
|
943
|
-
if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2,
|
|
944
|
-
&conn_info_v2, sizeof(conn_info_v2), &conn_info_v2, sizeof(conn_info_v2), &size, NULL)) {
|
|
945
|
-
usbi_warn(ctx, "could not get node connection information (V2) for root hub '%s' port %lu: %s",
|
|
946
|
-
priv->dev_id, ULONG_CAST(port_number), windows_error_str(0));
|
|
947
|
-
break;
|
|
948
|
-
}
|
|
949
|
-
|
|
950
|
-
if (conn_info_v2.Flags.DeviceIsSuperSpeedPlusCapableOrHigher)
|
|
951
|
-
speed = MAX(speed, LIBUSB_SPEED_SUPER_PLUS);
|
|
952
|
-
else if (conn_info_v2.Flags.DeviceIsSuperSpeedCapableOrHigher || conn_info_v2.SupportedUsbProtocols.Usb300)
|
|
953
|
-
speed = MAX(speed, LIBUSB_SPEED_SUPER);
|
|
954
|
-
else if (conn_info_v2.SupportedUsbProtocols.Usb200)
|
|
955
|
-
speed = MAX(speed, LIBUSB_SPEED_HIGH);
|
|
956
|
-
else
|
|
957
|
-
speed = MAX(speed, LIBUSB_SPEED_FULL);
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
if (speed != LIBUSB_SPEED_UNKNOWN)
|
|
961
|
-
goto make_descriptors;
|
|
962
|
-
}
|
|
963
|
-
|
|
964
|
-
// At this point the speed is still not known, most likely because we are executing on
|
|
965
|
-
// Windows 7 or earlier. The following hackery peeks into the root hub's Device ID and
|
|
966
|
-
// tries to extract speed information from it, based on observed naming conventions.
|
|
967
|
-
// If this does not work, we will query individual ports of the root hub.
|
|
968
|
-
if (strstr(priv->dev_id, "ROOT_HUB31") != NULL)
|
|
969
|
-
speed = LIBUSB_SPEED_SUPER_PLUS;
|
|
970
|
-
else if (strstr(priv->dev_id, "ROOT_HUB30") != NULL)
|
|
971
|
-
speed = LIBUSB_SPEED_SUPER;
|
|
972
|
-
else if (strstr(priv->dev_id, "ROOT_HUB20") != NULL)
|
|
973
|
-
speed = LIBUSB_SPEED_HIGH;
|
|
974
|
-
|
|
975
|
-
if (speed != LIBUSB_SPEED_UNKNOWN)
|
|
976
|
-
goto make_descriptors;
|
|
977
|
-
|
|
978
|
-
// Windows only reports speed information about a connected device. This means that a root
|
|
979
|
-
// hub with no connected devices or devices that are all operating at a speed less than the
|
|
980
|
-
// highest speed that the root hub supports will not give us the correct speed.
|
|
981
|
-
for (port_number = 1; port_number <= num_ports; port_number++) {
|
|
982
|
-
conn_info.ConnectionIndex = port_number;
|
|
983
|
-
if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, sizeof(conn_info),
|
|
984
|
-
&conn_info, sizeof(conn_info), &size, NULL)) {
|
|
985
|
-
usbi_warn(ctx, "could not get node connection information for root hub '%s' port %lu: %s",
|
|
986
|
-
priv->dev_id, ULONG_CAST(port_number), windows_error_str(0));
|
|
987
|
-
continue;
|
|
988
|
-
}
|
|
989
|
-
|
|
990
|
-
if (conn_info.ConnectionStatus != DeviceConnected)
|
|
991
|
-
continue;
|
|
992
|
-
|
|
993
|
-
if (conn_info.Speed == UsbHighSpeed) {
|
|
994
|
-
speed = LIBUSB_SPEED_HIGH;
|
|
995
|
-
break;
|
|
996
|
-
}
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
make_descriptors:
|
|
1000
|
-
CloseHandle(handle);
|
|
1001
|
-
|
|
1002
|
-
dev->device_descriptor.bLength = LIBUSB_DT_DEVICE_SIZE;
|
|
1003
|
-
dev->device_descriptor.bDescriptorType = LIBUSB_DT_DEVICE;
|
|
1004
|
-
dev->device_descriptor.bDeviceClass = LIBUSB_CLASS_HUB;
|
|
1005
|
-
if ((dev->device_descriptor.idVendor == 0) && (dev->device_descriptor.idProduct == 0)) {
|
|
1006
|
-
dev->device_descriptor.idVendor = 0x1d6b; // Linux Foundation
|
|
1007
|
-
dev->device_descriptor.idProduct = (uint16_t)speed;
|
|
1008
|
-
}
|
|
1009
|
-
dev->device_descriptor.bcdDevice = 0x0100;
|
|
1010
|
-
dev->device_descriptor.bNumConfigurations = 1;
|
|
1011
|
-
|
|
1012
|
-
switch (speed) {
|
|
1013
|
-
case LIBUSB_SPEED_SUPER_PLUS:
|
|
1014
|
-
dev->device_descriptor.bcdUSB = 0x0310;
|
|
1015
|
-
config_desc_length = ROOT_HUB_SS_CONFIG_DESC_LENGTH;
|
|
1016
|
-
ep_interval = 0x0c; // 256ms
|
|
1017
|
-
break;
|
|
1018
|
-
case LIBUSB_SPEED_SUPER:
|
|
1019
|
-
dev->device_descriptor.bcdUSB = 0x0300;
|
|
1020
|
-
config_desc_length = ROOT_HUB_SS_CONFIG_DESC_LENGTH;
|
|
1021
|
-
ep_interval = 0x0c; // 256ms
|
|
1022
|
-
break;
|
|
1023
|
-
case LIBUSB_SPEED_HIGH:
|
|
1024
|
-
dev->device_descriptor.bcdUSB = 0x0200;
|
|
1025
|
-
config_desc_length = ROOT_HUB_HS_CONFIG_DESC_LENGTH;
|
|
1026
|
-
ep_interval = 0x0c; // 256ms
|
|
1027
|
-
break;
|
|
1028
|
-
case LIBUSB_SPEED_LOW: // Not used, but keeps compiler happy
|
|
1029
|
-
case LIBUSB_SPEED_UNKNOWN:
|
|
1030
|
-
// This case means absolutely no information about this root hub was determined.
|
|
1031
|
-
// There is not much choice than to be pessimistic and label this as a
|
|
1032
|
-
// full-speed device.
|
|
1033
|
-
speed = LIBUSB_SPEED_FULL;
|
|
1034
|
-
// fallthrough
|
|
1035
|
-
case LIBUSB_SPEED_FULL:
|
|
1036
|
-
dev->device_descriptor.bcdUSB = 0x0110;
|
|
1037
|
-
config_desc_length = ROOT_HUB_FS_CONFIG_DESC_LENGTH;
|
|
1038
|
-
ep_interval = 0xff; // 255ms
|
|
1039
|
-
break;
|
|
1040
|
-
default: // Impossible, buts keeps compiler happy
|
|
1041
|
-
usbi_err(ctx, "program assertion failed - unknown root hub speed");
|
|
1042
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
if (speed >= LIBUSB_SPEED_SUPER) {
|
|
1046
|
-
dev->device_descriptor.bDeviceProtocol = 0x03; // USB 3.0 Hub
|
|
1047
|
-
dev->device_descriptor.bMaxPacketSize0 = 0x09; // 2^9 bytes
|
|
1048
|
-
} else {
|
|
1049
|
-
dev->device_descriptor.bMaxPacketSize0 = 0x40; // 64 bytes
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
dev->speed = speed;
|
|
1053
|
-
|
|
1054
|
-
r = alloc_root_hub_config_desc(dev, num_ports, config_desc_length, ep_interval);
|
|
1055
|
-
if (r)
|
|
1056
|
-
usbi_err(ctx, "could not allocate config descriptor for root hub '%s'", priv->dev_id);
|
|
1057
|
-
|
|
1058
|
-
return r;
|
|
1059
|
-
}
|
|
1060
|
-
|
|
1061
|
-
/*
|
|
1062
|
-
* Populate a libusb device structure
|
|
1063
|
-
*/
|
|
1064
|
-
static int init_device(struct libusb_device *dev, struct libusb_device *parent_dev,
|
|
1065
|
-
uint8_t port_number, DEVINST devinst)
|
|
1066
|
-
{
|
|
1067
|
-
struct libusb_context *ctx = NULL;
|
|
1068
|
-
struct libusb_device *tmp_dev;
|
|
1069
|
-
struct winusb_device_priv *priv, *parent_priv, *tmp_priv;
|
|
1070
|
-
USB_NODE_CONNECTION_INFORMATION_EX conn_info;
|
|
1071
|
-
USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2;
|
|
1072
|
-
HANDLE hub_handle;
|
|
1073
|
-
DWORD size;
|
|
1074
|
-
uint8_t bus_number, depth;
|
|
1075
|
-
int r;
|
|
1076
|
-
|
|
1077
|
-
priv = usbi_get_device_priv(dev);
|
|
1078
|
-
|
|
1079
|
-
// If the device is already initialized, we can stop here
|
|
1080
|
-
if (priv->initialized)
|
|
1081
|
-
return LIBUSB_SUCCESS;
|
|
1082
|
-
|
|
1083
|
-
if (parent_dev != NULL) { // Not a HCD root hub
|
|
1084
|
-
ctx = DEVICE_CTX(dev);
|
|
1085
|
-
parent_priv = usbi_get_device_priv(parent_dev);
|
|
1086
|
-
if (parent_priv->apib->id != USB_API_HUB) {
|
|
1087
|
-
usbi_warn(ctx, "parent for device '%s' is not a hub", priv->dev_id);
|
|
1088
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
// Calculate depth and fetch bus number
|
|
1092
|
-
bus_number = parent_dev->bus_number;
|
|
1093
|
-
if (bus_number == 0) {
|
|
1094
|
-
tmp_dev = get_ancestor(ctx, devinst, &devinst);
|
|
1095
|
-
if (tmp_dev != parent_dev) {
|
|
1096
|
-
usbi_err(ctx, "program assertion failed - first ancestor is not parent");
|
|
1097
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
1098
|
-
}
|
|
1099
|
-
libusb_unref_device(tmp_dev);
|
|
1100
|
-
|
|
1101
|
-
for (depth = 1; bus_number == 0; depth++) {
|
|
1102
|
-
tmp_dev = get_ancestor(ctx, devinst, &devinst);
|
|
1103
|
-
if (tmp_dev == NULL) {
|
|
1104
|
-
usbi_warn(ctx, "ancestor for device '%s' not found at depth %u", priv->dev_id, depth);
|
|
1105
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
1106
|
-
}
|
|
1107
|
-
if (tmp_dev->bus_number != 0) {
|
|
1108
|
-
bus_number = tmp_dev->bus_number;
|
|
1109
|
-
tmp_priv = usbi_get_device_priv(tmp_dev);
|
|
1110
|
-
depth += tmp_priv->depth;
|
|
1111
|
-
}
|
|
1112
|
-
libusb_unref_device(tmp_dev);
|
|
1113
|
-
}
|
|
1114
|
-
} else {
|
|
1115
|
-
depth = parent_priv->depth + 1;
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
if (bus_number == 0) {
|
|
1119
|
-
usbi_err(ctx, "program assertion failed - bus number not found for '%s'", priv->dev_id);
|
|
1120
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
dev->bus_number = bus_number;
|
|
1124
|
-
dev->port_number = port_number;
|
|
1125
|
-
dev->parent_dev = parent_dev;
|
|
1126
|
-
priv->depth = depth;
|
|
1127
|
-
|
|
1128
|
-
hub_handle = CreateFileA(parent_priv->path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
|
1129
|
-
if (hub_handle == INVALID_HANDLE_VALUE) {
|
|
1130
|
-
usbi_warn(ctx, "could not open hub %s: %s", parent_priv->path, windows_error_str(0));
|
|
1131
|
-
return LIBUSB_ERROR_ACCESS;
|
|
1132
|
-
}
|
|
1133
|
-
|
|
1134
|
-
conn_info.ConnectionIndex = (ULONG)port_number;
|
|
1135
|
-
// coverity[tainted_data_argument]
|
|
1136
|
-
|
|
1137
|
-
if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, sizeof(conn_info),
|
|
1138
|
-
&conn_info, sizeof(conn_info), &size, NULL)) {
|
|
1139
|
-
usbi_warn(ctx, "could not get node connection information for device '%s': %s",
|
|
1140
|
-
priv->dev_id, windows_error_str(0));
|
|
1141
|
-
CloseHandle(hub_handle);
|
|
1142
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
|
-
if (conn_info.ConnectionStatus == NoDeviceConnected) {
|
|
1146
|
-
usbi_err(ctx, "device '%s' is no longer connected!", priv->dev_id);
|
|
1147
|
-
CloseHandle(hub_handle);
|
|
1148
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
if ((conn_info.DeviceDescriptor.bLength != LIBUSB_DT_DEVICE_SIZE)
|
|
1152
|
-
|| (conn_info.DeviceDescriptor.bDescriptorType != LIBUSB_DT_DEVICE)) {
|
|
1153
|
-
usbi_err(ctx, "device '%s' has invalid descriptor!", priv->dev_id);
|
|
1154
|
-
CloseHandle(hub_handle);
|
|
1155
|
-
return LIBUSB_ERROR_OTHER;
|
|
1156
|
-
}
|
|
1157
|
-
|
|
1158
|
-
static_assert(sizeof(dev->device_descriptor) == sizeof(conn_info.DeviceDescriptor),
|
|
1159
|
-
"mismatch between libusb and OS device descriptor sizes");
|
|
1160
|
-
memcpy(&dev->device_descriptor, &conn_info.DeviceDescriptor, LIBUSB_DT_DEVICE_SIZE);
|
|
1161
|
-
usbi_localize_device_descriptor(&dev->device_descriptor);
|
|
1162
|
-
|
|
1163
|
-
if (conn_info.CurrentConfigurationValue == 0) {
|
|
1164
|
-
usbi_dbg(ctx, "found %u configurations for device '%s' but device is not configured (i.e. current config: 0), ignoring it",
|
|
1165
|
-
dev->device_descriptor.bNumConfigurations,
|
|
1166
|
-
priv->dev_id);
|
|
1167
|
-
CloseHandle(hub_handle);
|
|
1168
|
-
return LIBUSB_ERROR_OTHER;
|
|
1169
|
-
}
|
|
1170
|
-
|
|
1171
|
-
priv->active_config = conn_info.CurrentConfigurationValue;
|
|
1172
|
-
usbi_dbg(ctx, "found %u configurations (current config: %u) for device '%s'",
|
|
1173
|
-
dev->device_descriptor.bNumConfigurations, priv->active_config, priv->dev_id);
|
|
1174
|
-
|
|
1175
|
-
// Cache as many config descriptors as we can
|
|
1176
|
-
cache_config_descriptors(dev, hub_handle);
|
|
1177
|
-
|
|
1178
|
-
// In their great wisdom, Microsoft decided to BREAK the USB speed report between Windows 7 and Windows 8
|
|
1179
|
-
if (windows_version >= WINDOWS_8) {
|
|
1180
|
-
conn_info_v2.ConnectionIndex = (ULONG)port_number;
|
|
1181
|
-
conn_info_v2.Length = sizeof(USB_NODE_CONNECTION_INFORMATION_EX_V2);
|
|
1182
|
-
conn_info_v2.SupportedUsbProtocols.Usb300 = 1;
|
|
1183
|
-
if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2,
|
|
1184
|
-
&conn_info_v2, sizeof(conn_info_v2), &conn_info_v2, sizeof(conn_info_v2), &size, NULL)) {
|
|
1185
|
-
usbi_warn(ctx, "could not get node connection information (V2) for device '%s': %s",
|
|
1186
|
-
priv->dev_id, windows_error_str(0));
|
|
1187
|
-
} else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedPlusOrHigher) {
|
|
1188
|
-
conn_info.Speed = UsbSuperSpeedPlus;
|
|
1189
|
-
} else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedOrHigher) {
|
|
1190
|
-
conn_info.Speed = UsbSuperSpeed;
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
|
|
1194
|
-
CloseHandle(hub_handle);
|
|
1195
|
-
|
|
1196
|
-
if (conn_info.DeviceAddress > UINT8_MAX)
|
|
1197
|
-
usbi_err(ctx, "program assertion failed - device address overflow");
|
|
1198
|
-
|
|
1199
|
-
dev->device_address = (uint8_t)conn_info.DeviceAddress;
|
|
1200
|
-
|
|
1201
|
-
switch (conn_info.Speed) {
|
|
1202
|
-
case UsbLowSpeed: dev->speed = LIBUSB_SPEED_LOW; break;
|
|
1203
|
-
case UsbFullSpeed: dev->speed = LIBUSB_SPEED_FULL; break;
|
|
1204
|
-
case UsbHighSpeed: dev->speed = LIBUSB_SPEED_HIGH; break;
|
|
1205
|
-
case UsbSuperSpeed: dev->speed = LIBUSB_SPEED_SUPER; break;
|
|
1206
|
-
case UsbSuperSpeedPlus: dev->speed = LIBUSB_SPEED_SUPER_PLUS; break;
|
|
1207
|
-
default:
|
|
1208
|
-
usbi_warn(ctx, "unknown device speed %u", conn_info.Speed);
|
|
1209
|
-
break;
|
|
1210
|
-
}
|
|
1211
|
-
} else {
|
|
1212
|
-
r = init_root_hub(dev);
|
|
1213
|
-
if (r)
|
|
1214
|
-
return r;
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
r = usbi_sanitize_device(dev);
|
|
1218
|
-
if (r)
|
|
1219
|
-
return r;
|
|
1220
|
-
|
|
1221
|
-
priv->initialized = true;
|
|
1222
|
-
|
|
1223
|
-
usbi_dbg(ctx, "(bus: %u, addr: %u, depth: %u, port: %u): '%s'",
|
|
1224
|
-
dev->bus_number, dev->device_address, priv->depth, dev->port_number, priv->dev_id);
|
|
1225
|
-
|
|
1226
|
-
return LIBUSB_SUCCESS;
|
|
1227
|
-
}
|
|
1228
|
-
|
|
1229
|
-
static bool get_dev_port_number(HDEVINFO dev_info, SP_DEVINFO_DATA *dev_info_data, DWORD *port_nr)
|
|
1230
|
-
{
|
|
1231
|
-
char buffer[MAX_KEY_LENGTH];
|
|
1232
|
-
DWORD size;
|
|
1233
|
-
const char *start = NULL;
|
|
1234
|
-
char *end = NULL;
|
|
1235
|
-
long long port;
|
|
1236
|
-
|
|
1237
|
-
// First try SPDRP_LOCATION_INFORMATION, which returns a REG_SZ. The string *may* have a format
|
|
1238
|
-
// similar to "Port_#0002.Hub_#000D", in which case we can extract the port number. However, we
|
|
1239
|
-
// cannot extract the port if the returned string does not follow this format.
|
|
1240
|
-
if (pSetupDiGetDeviceRegistryPropertyA(dev_info, dev_info_data, SPDRP_LOCATION_INFORMATION,
|
|
1241
|
-
NULL, (PBYTE)buffer, sizeof(buffer), NULL)) {
|
|
1242
|
-
// Check for the required format.
|
|
1243
|
-
if (strncmp(buffer, "Port_#", 6) == 0) {
|
|
1244
|
-
start = buffer + 6;
|
|
1245
|
-
// Note that 0 is both strtoll's sentinel return value to indicate failure, as well
|
|
1246
|
-
// as (obviously) the return value for the literal "0". Fortunately we can always treat
|
|
1247
|
-
// 0 as a failure, since Windows USB port numbers are numbered 1..n.
|
|
1248
|
-
port = strtoll(start, &end, 10);
|
|
1249
|
-
if (port <= 0 || port >= ULONG_MAX || end == start || (*end != '.' && *end != '\0')) {
|
|
1250
|
-
return false;
|
|
1251
|
-
}
|
|
1252
|
-
*port_nr = (DWORD)port;
|
|
1253
|
-
return true;
|
|
1254
|
-
}
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
// Next try SPDRP_LOCATION_PATHS, which returns a REG_MULTI_SZ (but we only examine the first
|
|
1258
|
-
// string in it). Each path has a format similar to,
|
|
1259
|
-
// "PCIROOT(B2)#PCI(0300)#PCI(0000)#USBROOT(0)#USB(1)#USB(2)#USBMI(3)", and the port number is
|
|
1260
|
-
// the number within the last "USB(x)" token.
|
|
1261
|
-
if (pSetupDiGetDeviceRegistryPropertyA(dev_info, dev_info_data, SPDRP_LOCATION_PATHS,
|
|
1262
|
-
NULL, (PBYTE)buffer, sizeof(buffer), NULL)) {
|
|
1263
|
-
// Find the last "#USB(x)" substring
|
|
1264
|
-
for (char *token = strrchr(buffer, '#'); token != NULL; token = strrchr(buffer, '#')) {
|
|
1265
|
-
if (strncmp(token, "#USB(", 5) == 0) {
|
|
1266
|
-
start = token + 5;
|
|
1267
|
-
port = strtoll(start, &end, 10);
|
|
1268
|
-
if (port <= 0 || port >= ULONG_MAX || end == start || (*end != ')' && *end != '\0')) {
|
|
1269
|
-
return false;
|
|
1270
|
-
}
|
|
1271
|
-
*port_nr = (DWORD)port;
|
|
1272
|
-
return true;
|
|
1273
|
-
}
|
|
1274
|
-
// Shorten the string and try again.
|
|
1275
|
-
*token = '\0';
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
|
|
1279
|
-
// Lastly, try SPDRP_ADDRESS, which returns a REG_DWORD. The address *may* be the port number,
|
|
1280
|
-
// which is true for the Microsoft driver but may not be true for other drivers. However, we
|
|
1281
|
-
// have no other options here but to accept what it returns.
|
|
1282
|
-
return pSetupDiGetDeviceRegistryPropertyA(dev_info, dev_info_data, SPDRP_ADDRESS,
|
|
1283
|
-
NULL, (PBYTE)port_nr, sizeof(*port_nr), &size) && (size == sizeof(*port_nr));
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
static int enumerate_hcd_root_hub(struct libusb_context *ctx, const char *dev_id,
|
|
1287
|
-
DEVINST devinst)
|
|
1288
|
-
{
|
|
1289
|
-
DEVINST child_devinst;
|
|
1290
|
-
struct libusb_device* dev;
|
|
1291
|
-
|
|
1292
|
-
if (CM_Get_Child(&child_devinst, devinst, 0) != CR_SUCCESS) {
|
|
1293
|
-
usbi_warn(ctx, "could not get child devinst for '%s'", dev_id);
|
|
1294
|
-
return LIBUSB_SUCCESS;
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
dev = usbi_get_device_by_session_id(ctx, (unsigned long)child_devinst);
|
|
1298
|
-
if (dev == NULL) {
|
|
1299
|
-
usbi_warn(ctx, "HCD '%s' child not found", dev_id);
|
|
1300
|
-
return LIBUSB_SUCCESS;
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
if (sscanf(dev_id, "PCI\\VEN_%04hx&DEV_%04hx%*s", &dev->device_descriptor.idVendor, &dev->device_descriptor.idProduct) != 2)
|
|
1304
|
-
usbi_warn(ctx, "could not infer VID/PID of HCD from '%s'", dev_id);
|
|
1305
|
-
libusb_unref_device(dev);
|
|
1306
|
-
return LIBUSB_SUCCESS;
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
// Returns the api type, or 0 if not found/unsupported
|
|
1310
|
-
static void get_api_type(HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data,
|
|
1311
|
-
int *api, int *sub_api)
|
|
1312
|
-
{
|
|
1313
|
-
// Precedence for filter drivers vs driver is in the order of this array
|
|
1314
|
-
struct driver_lookup lookup[3] = {
|
|
1315
|
-
{"\0\0", SPDRP_SERVICE, "driver"},
|
|
1316
|
-
{"\0\0", SPDRP_UPPERFILTERS, "upper filter driver"},
|
|
1317
|
-
{"\0\0", SPDRP_LOWERFILTERS, "lower filter driver"}
|
|
1318
|
-
};
|
|
1319
|
-
DWORD size, reg_type;
|
|
1320
|
-
unsigned k, l;
|
|
1321
|
-
int i, j;
|
|
1322
|
-
|
|
1323
|
-
// Check the service & filter names to know the API we should use
|
|
1324
|
-
for (k = 0; k < 3; k++) {
|
|
1325
|
-
if (pSetupDiGetDeviceRegistryPropertyA(*dev_info, dev_info_data, lookup[k].reg_prop,
|
|
1326
|
-
®_type, (PBYTE)lookup[k].list, MAX_KEY_LENGTH, &size)) {
|
|
1327
|
-
// Turn the REG_SZ SPDRP_SERVICE into REG_MULTI_SZ
|
|
1328
|
-
if (lookup[k].reg_prop == SPDRP_SERVICE)
|
|
1329
|
-
// our buffers are MAX_KEY_LENGTH + 1 so we can overflow if needed
|
|
1330
|
-
lookup[k].list[strlen(lookup[k].list) + 1] = 0;
|
|
1331
|
-
|
|
1332
|
-
// MULTI_SZ is a pain to work with. Turn it into something much more manageable
|
|
1333
|
-
// NB: none of the driver names we check against contain LIST_SEPARATOR,
|
|
1334
|
-
// (currently ';'), so even if an unsupported one does, it's not an issue
|
|
1335
|
-
for (l = 0; (lookup[k].list[l] != 0) || (lookup[k].list[l + 1] != 0); l++) {
|
|
1336
|
-
if (lookup[k].list[l] == 0)
|
|
1337
|
-
lookup[k].list[l] = LIST_SEPARATOR;
|
|
1338
|
-
}
|
|
1339
|
-
usbi_dbg(NULL, "%s(s): %s", lookup[k].designation, lookup[k].list);
|
|
1340
|
-
} else {
|
|
1341
|
-
if (GetLastError() != ERROR_INVALID_DATA)
|
|
1342
|
-
usbi_dbg(NULL, "could not access %s: %s", lookup[k].designation, windows_error_str(0));
|
|
1343
|
-
lookup[k].list[0] = 0;
|
|
1344
|
-
}
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
|
-
for (i = 2; i < USB_API_MAX; i++) {
|
|
1348
|
-
for (k = 0; k < 3; k++) {
|
|
1349
|
-
j = get_sub_api(lookup[k].list, i);
|
|
1350
|
-
if (j >= 0) {
|
|
1351
|
-
usbi_dbg(NULL, "matched %s name against %s", lookup[k].designation,
|
|
1352
|
-
(i != USB_API_WINUSBX) ? usb_api_backend[i].designation : usb_api_backend[i].driver_name_list[j]);
|
|
1353
|
-
*api = i;
|
|
1354
|
-
*sub_api = j;
|
|
1355
|
-
return;
|
|
1356
|
-
}
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
}
|
|
1360
|
-
|
|
1361
|
-
static int set_composite_interface(struct libusb_context *ctx, struct libusb_device *dev,
|
|
1362
|
-
char *dev_interface_path, char *device_id, int api, int sub_api)
|
|
1363
|
-
{
|
|
1364
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
|
|
1365
|
-
int interface_number;
|
|
1366
|
-
const char *mi_str;
|
|
1367
|
-
int iadi, iadintfi;
|
|
1368
|
-
char* endptr;
|
|
1369
|
-
struct libusb_interface_association_descriptor_array *iad_array;
|
|
1370
|
-
const struct libusb_interface_association_descriptor *iad;
|
|
1371
|
-
|
|
1372
|
-
// Because MI_## are not necessarily in sequential order (some composite
|
|
1373
|
-
// devices will have only MI_00 & MI_03 for instance), we retrieve the actual
|
|
1374
|
-
// interface number from the path's MI value
|
|
1375
|
-
mi_str = strstr(device_id, "MI_");
|
|
1376
|
-
|
|
1377
|
-
endptr = NULL;
|
|
1378
|
-
// This initialization, while redundant, is needed to make MSVC happy
|
|
1379
|
-
interface_number = -1;
|
|
1380
|
-
|
|
1381
|
-
if (mi_str != NULL) {
|
|
1382
|
-
interface_number = strtoul(&mi_str[3], &endptr, 16);
|
|
1383
|
-
}
|
|
1384
|
-
|
|
1385
|
-
if (mi_str == NULL || endptr - &mi_str[3] != 2) {
|
|
1386
|
-
usbi_warn(ctx, "failure to read interface number for %s, using default value", device_id);
|
|
1387
|
-
interface_number = 0;
|
|
1388
|
-
}
|
|
1389
|
-
|
|
1390
|
-
if (interface_number >= USB_MAXINTERFACES) {
|
|
1391
|
-
usbi_warn(ctx, "interface %d too large - ignoring interface path %s", interface_number, dev_interface_path);
|
|
1392
|
-
return LIBUSB_ERROR_ACCESS;
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
if (priv->usb_interface[interface_number].path != NULL) {
|
|
1396
|
-
if (api == USB_API_HID) {
|
|
1397
|
-
// HID devices can have multiple collections (COL##) for each MI_## interface
|
|
1398
|
-
usbi_dbg(ctx, "interface[%d] already set - ignoring HID collection: %s",
|
|
1399
|
-
interface_number, device_id);
|
|
1400
|
-
return LIBUSB_ERROR_ACCESS;
|
|
1401
|
-
}
|
|
1402
|
-
// In other cases, just use the latest data
|
|
1403
|
-
safe_free(priv->usb_interface[interface_number].path);
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
usbi_dbg(ctx, "interface[%d] = %s", interface_number, dev_interface_path);
|
|
1407
|
-
priv->usb_interface[interface_number].path = dev_interface_path;
|
|
1408
|
-
priv->usb_interface[interface_number].apib = &usb_api_backend[api];
|
|
1409
|
-
priv->usb_interface[interface_number].sub_api = sub_api;
|
|
1410
|
-
if ((api == USB_API_HID) && (priv->hid == NULL)) {
|
|
1411
|
-
priv->hid = calloc(1, sizeof(struct hid_device_priv));
|
|
1412
|
-
if (priv->hid == NULL)
|
|
1413
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
1414
|
-
}
|
|
1415
|
-
|
|
1416
|
-
// For WinUSBX, set up associations for interfaces grouped by an IAD
|
|
1417
|
-
if ((api == USB_API_WINUSBX) && !libusb_get_active_interface_association_descriptors(dev, &iad_array)) {
|
|
1418
|
-
for (iadi = 0; iadi < iad_array->length; iadi++) {
|
|
1419
|
-
iad = &iad_array->iad[iadi];
|
|
1420
|
-
if (iad->bFirstInterface == interface_number) {
|
|
1421
|
-
priv->usb_interface[interface_number].num_associated_interfaces = iad->bInterfaceCount;
|
|
1422
|
-
priv->usb_interface[interface_number].first_associated_interface = iad->bFirstInterface;
|
|
1423
|
-
for (iadintfi = 1; iadintfi < iad->bInterfaceCount; iadintfi++) {
|
|
1424
|
-
usbi_dbg(ctx, "interface[%d] is associated with interface[%d]",
|
|
1425
|
-
interface_number + iadintfi, interface_number);
|
|
1426
|
-
priv->usb_interface[interface_number + iadintfi].apib = &usb_api_backend[api];
|
|
1427
|
-
priv->usb_interface[interface_number + iadintfi].sub_api = sub_api;
|
|
1428
|
-
priv->usb_interface[interface_number + iadintfi].num_associated_interfaces = iad->bInterfaceCount;
|
|
1429
|
-
priv->usb_interface[interface_number + iadintfi].first_associated_interface = iad->bFirstInterface;
|
|
1430
|
-
}
|
|
1431
|
-
break;
|
|
1432
|
-
}
|
|
1433
|
-
}
|
|
1434
|
-
libusb_free_interface_association_descriptors(iad_array);
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
|
-
return LIBUSB_SUCCESS;
|
|
1438
|
-
}
|
|
1439
|
-
|
|
1440
|
-
static int set_hid_interface(struct libusb_context *ctx, struct libusb_device *dev,
|
|
1441
|
-
char *dev_interface_path)
|
|
1442
|
-
{
|
|
1443
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
|
|
1444
|
-
uint8_t i;
|
|
1445
|
-
|
|
1446
|
-
if (priv->hid == NULL) {
|
|
1447
|
-
usbi_err(ctx, "program assertion failed - parent is not HID");
|
|
1448
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
1449
|
-
} else if (priv->hid->nb_interfaces == USB_MAXINTERFACES) {
|
|
1450
|
-
usbi_err(ctx, "program assertion failed - max USB interfaces reached for HID device");
|
|
1451
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1454
|
-
for (i = 0; i < priv->hid->nb_interfaces; i++) {
|
|
1455
|
-
if ((priv->usb_interface[i].path != NULL) && strcmp(priv->usb_interface[i].path, dev_interface_path) == 0) {
|
|
1456
|
-
usbi_dbg(ctx, "interface[%u] already set to %s", i, dev_interface_path);
|
|
1457
|
-
return LIBUSB_ERROR_ACCESS;
|
|
1458
|
-
}
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
priv->usb_interface[priv->hid->nb_interfaces].path = dev_interface_path;
|
|
1462
|
-
priv->usb_interface[priv->hid->nb_interfaces].apib = &usb_api_backend[USB_API_HID];
|
|
1463
|
-
usbi_dbg(ctx, "interface[%u] = %s", priv->hid->nb_interfaces, dev_interface_path);
|
|
1464
|
-
priv->hid->nb_interfaces++;
|
|
1465
|
-
return LIBUSB_SUCCESS;
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
// get the n-th device interface GUID indexed by guid_number
|
|
1469
|
-
static int get_guid(struct libusb_context *ctx, char *dev_id, HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data,
|
|
1470
|
-
int guid_number, GUID **if_guid)
|
|
1471
|
-
{
|
|
1472
|
-
DWORD size, reg_type;
|
|
1473
|
-
HKEY key;
|
|
1474
|
-
char *guid_string, *new_guid_string;
|
|
1475
|
-
char *guid, *guid_term;
|
|
1476
|
-
LONG s;
|
|
1477
|
-
int pass, guids_left;
|
|
1478
|
-
int err = LIBUSB_SUCCESS;
|
|
1479
|
-
#if !defined(ENABLE_LOGGING)
|
|
1480
|
-
UNUSED(dev_id);
|
|
1481
|
-
#endif
|
|
1482
|
-
|
|
1483
|
-
key = pSetupDiOpenDevRegKey(*dev_info, dev_info_data, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ);
|
|
1484
|
-
if (key == INVALID_HANDLE_VALUE) {
|
|
1485
|
-
usbi_warn(ctx, "Cannot get the additional GUIDs for '%s'", dev_id);
|
|
1486
|
-
return LIBUSB_ERROR_ACCESS;
|
|
1487
|
-
}
|
|
1488
|
-
// Reserve buffer large enough to hold one GUID with two terminating characters
|
|
1489
|
-
size = MAX_GUID_STRING_LENGTH + 1;
|
|
1490
|
-
// Allocate memory for storing the guid_string with two extra terminating characters
|
|
1491
|
-
// This is necessary for parsing the REG_MULTI_SZ type below
|
|
1492
|
-
guid_string = malloc(size + 2);
|
|
1493
|
-
if (guid_string == NULL) {
|
|
1494
|
-
usbi_err(ctx, "failed to alloc guid_string");
|
|
1495
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
// The 1st pass tries to get the guid. If it fails due to ERROR_MORE_DATA
|
|
1499
|
-
// then reallocate enough memory for the 2nd pass
|
|
1500
|
-
for (pass = 0; pass < 2; pass++) {
|
|
1501
|
-
// Look for both DeviceInterfaceGUIDs *and* DeviceInterfaceGUID, in that order
|
|
1502
|
-
// If multiple GUIDs, find the n-th that is indexed by guid_number
|
|
1503
|
-
s = pRegQueryValueExA(key, "DeviceInterfaceGUIDs", NULL, ®_type,
|
|
1504
|
-
(LPBYTE)guid_string, &size);
|
|
1505
|
-
if (s == ERROR_FILE_NOT_FOUND)
|
|
1506
|
-
s = pRegQueryValueExA(key, "DeviceInterfaceGUID", NULL, ®_type,
|
|
1507
|
-
(LPBYTE)guid_string, &size);
|
|
1508
|
-
if (s == ERROR_SUCCESS) {
|
|
1509
|
-
// The GUID was read successfully
|
|
1510
|
-
break;
|
|
1511
|
-
} else if (s == ERROR_FILE_NOT_FOUND) {
|
|
1512
|
-
usbi_dbg(ctx, "no DeviceInterfaceGUID registered for '%s'", dev_id);
|
|
1513
|
-
err = LIBUSB_ERROR_ACCESS;
|
|
1514
|
-
goto exit;
|
|
1515
|
-
} else if (s == ERROR_MORE_DATA) {
|
|
1516
|
-
if (pass == 1) {
|
|
1517
|
-
// Previous pass should have allocated enough memory, but reading failed
|
|
1518
|
-
usbi_warn(ctx, "unexpected error from pRegQueryValueExA for '%s'", dev_id);
|
|
1519
|
-
err = LIBUSB_ERROR_OTHER;
|
|
1520
|
-
goto exit;
|
|
1521
|
-
}
|
|
1522
|
-
new_guid_string = realloc((void *)guid_string, size + 2);
|
|
1523
|
-
if (new_guid_string == NULL) {
|
|
1524
|
-
usbi_err(ctx, "failed to realloc guid string");
|
|
1525
|
-
err = LIBUSB_ERROR_NO_MEM;
|
|
1526
|
-
goto exit;
|
|
1527
|
-
}
|
|
1528
|
-
guid_string = new_guid_string;
|
|
1529
|
-
} else {
|
|
1530
|
-
usbi_warn(ctx, "unexpected error from pRegQueryValueExA for '%s'", dev_id);
|
|
1531
|
-
err = LIBUSB_ERROR_ACCESS;
|
|
1532
|
-
goto exit;
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1535
|
-
|
|
1536
|
-
// https://docs.microsoft.com/en-us/windows/win32/api/winreg/nf-winreg-regqueryvalueexa#remarks
|
|
1537
|
-
// - "string may not have been stored with the proper terminating null characters"
|
|
1538
|
-
// - The following GUIDs should be consider as valid:
|
|
1539
|
-
// "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}\0", "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}",
|
|
1540
|
-
// "{xxx.....xx}\0\0\0", "{xxx.....xx}\0{xxx.....xx}\0{xxx.....xx}\0",
|
|
1541
|
-
// "{xxx.....xx}\0{xxx.....xx}\0{xxx.....xx}", "{xxx.....xx}{xxx.....xx}{xxx.....xx}",
|
|
1542
|
-
// "{xxx.....xx}\0{xxx.....xx}\0{xxx.....xx}\0\0\0\0"
|
|
1543
|
-
if ((reg_type == REG_SZ ) || (reg_type == REG_MULTI_SZ)) {
|
|
1544
|
-
/* Get the n-th GUID indexed by guid_number since the DeviceInterfaceGUIDs may
|
|
1545
|
-
contain more GUIDs */
|
|
1546
|
-
guid = guid_string;
|
|
1547
|
-
// Add two terminating chars for not overrunning the allocated memory while iterating
|
|
1548
|
-
guid[size] = '\0';
|
|
1549
|
-
guid[size + 1] = '\0';
|
|
1550
|
-
// Iterate the GUIDs in the guid string
|
|
1551
|
-
guids_left = guid_number;
|
|
1552
|
-
while (guids_left) {
|
|
1553
|
-
guid = strchr(guid, '}');
|
|
1554
|
-
if (guid == NULL) {
|
|
1555
|
-
usbi_warn(ctx, "no GUID with index %d registered for '%s'", guid_number, dev_id);
|
|
1556
|
-
err = LIBUSB_ERROR_ACCESS;
|
|
1557
|
-
goto exit;
|
|
1558
|
-
}
|
|
1559
|
-
guid++;
|
|
1560
|
-
// Skip the terminating char if available
|
|
1561
|
-
if (*guid == '\0') {
|
|
1562
|
-
guid++;
|
|
1563
|
-
}
|
|
1564
|
-
guids_left--;
|
|
1565
|
-
}
|
|
1566
|
-
// Add terminating char to the string
|
|
1567
|
-
guid_term = strchr(guid, '}');
|
|
1568
|
-
if (guid_term == NULL) {
|
|
1569
|
-
usbi_warn(ctx, "no GUID with index %d registered for '%s'", guid_number, dev_id);
|
|
1570
|
-
err = LIBUSB_ERROR_ACCESS;
|
|
1571
|
-
goto exit;
|
|
1572
|
-
}
|
|
1573
|
-
// Terminate the current guid string to handle the variant without separators
|
|
1574
|
-
guid_term++;
|
|
1575
|
-
*guid_term = '\0';
|
|
1576
|
-
} else {
|
|
1577
|
-
usbi_warn(ctx, "unexpected type of DeviceInterfaceGUID for '%s'", dev_id);
|
|
1578
|
-
err = LIBUSB_ERROR_ACCESS;
|
|
1579
|
-
goto exit;
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
|
-
*if_guid = malloc(sizeof(GUID));
|
|
1583
|
-
if (*if_guid == NULL) {
|
|
1584
|
-
usbi_err(ctx, "failed to alloc if_guid");
|
|
1585
|
-
err = LIBUSB_ERROR_NO_MEM;
|
|
1586
|
-
goto exit;
|
|
1587
|
-
}
|
|
1588
|
-
if (!string_to_guid(guid, *if_guid)) {
|
|
1589
|
-
usbi_warn(ctx, "device '%s' has malformed DeviceInterfaceGUID string '%s', skipping", dev_id, guid);
|
|
1590
|
-
free(*if_guid);
|
|
1591
|
-
*if_guid = NULL;
|
|
1592
|
-
goto exit;
|
|
1593
|
-
}
|
|
1594
|
-
|
|
1595
|
-
exit:
|
|
1596
|
-
pRegCloseKey(key);
|
|
1597
|
-
free(guid_string);
|
|
1598
|
-
return err;
|
|
1599
|
-
}
|
|
1600
|
-
|
|
1601
|
-
/*
|
|
1602
|
-
* get_device_list: libusb backend device enumeration function
|
|
1603
|
-
*/
|
|
1604
|
-
static int winusb_get_device_list(struct libusb_context *ctx, struct discovered_devs **_discdevs)
|
|
1605
|
-
{
|
|
1606
|
-
struct discovered_devs *discdevs;
|
|
1607
|
-
HDEVINFO *dev_info, dev_info_intf, dev_info_enum;
|
|
1608
|
-
SP_DEVINFO_DATA dev_info_data;
|
|
1609
|
-
DWORD _index = 0;
|
|
1610
|
-
GUID hid_guid;
|
|
1611
|
-
int r = LIBUSB_SUCCESS;
|
|
1612
|
-
int api, sub_api;
|
|
1613
|
-
unsigned int pass, pass_type, i, j;
|
|
1614
|
-
char enumerator[16];
|
|
1615
|
-
char dev_id[MAX_PATH_LENGTH];
|
|
1616
|
-
struct libusb_device *dev, *parent_dev;
|
|
1617
|
-
struct winusb_device_priv *priv, *parent_priv;
|
|
1618
|
-
char *dev_interface_path = NULL;
|
|
1619
|
-
unsigned long session_id;
|
|
1620
|
-
DWORD size, port_nr, install_state;
|
|
1621
|
-
uint8_t bus_number = 0;
|
|
1622
|
-
#if defined(ENABLE_LOGGING)
|
|
1623
|
-
char guid_string[MAX_GUID_STRING_LENGTH];
|
|
1624
|
-
#endif
|
|
1625
|
-
GUID *if_guid;
|
|
1626
|
-
#define HUB_PASS 0
|
|
1627
|
-
#define DEV_PASS 1
|
|
1628
|
-
#define HCD_PASS 2
|
|
1629
|
-
#define GEN_PASS 3
|
|
1630
|
-
#define HID_PASS 4
|
|
1631
|
-
#define EXT_PASS 5
|
|
1632
|
-
// Keep a list of guids that will be enumerated
|
|
1633
|
-
#define GUID_SIZE_STEP 8
|
|
1634
|
-
const GUID **guid_list, **new_guid_list;
|
|
1635
|
-
unsigned int guid_size = GUID_SIZE_STEP;
|
|
1636
|
-
unsigned int nb_guids;
|
|
1637
|
-
// Keep a list of PnP enumerator strings that are found
|
|
1638
|
-
const char *usb_enumerator[8] = { "USB" };
|
|
1639
|
-
unsigned int nb_usb_enumerators = 1;
|
|
1640
|
-
unsigned int usb_enum_index = 0;
|
|
1641
|
-
// Keep a list of newly allocated devs to unref
|
|
1642
|
-
#define UNREF_SIZE_STEP 16
|
|
1643
|
-
libusb_device **unref_list, **new_unref_list;
|
|
1644
|
-
unsigned int unref_size = UNREF_SIZE_STEP;
|
|
1645
|
-
unsigned int unref_cur = 0;
|
|
1646
|
-
DWORD hub_port_nr;
|
|
1647
|
-
|
|
1648
|
-
// PASS 0 : enumerate HUBs
|
|
1649
|
-
// PASS 1 : (re)enumerate master devices that have a DEVice interface
|
|
1650
|
-
// PASS 2 : (re)enumerate HCDs (allow for HCD hotplug)
|
|
1651
|
-
// PASS 3 : (re)enumerate GENeric devices (including driverless)
|
|
1652
|
-
// and list additional device interface GUIDs to explore
|
|
1653
|
-
// PASS 4 : (re)enumerate device interface GUIDs (including HID)
|
|
1654
|
-
// and set the device interfaces
|
|
1655
|
-
// PASS 5+: (re)enumerate additional EXTra GUID devices
|
|
1656
|
-
|
|
1657
|
-
// Init the GUID table
|
|
1658
|
-
guid_list = malloc(guid_size * sizeof(void *));
|
|
1659
|
-
if (guid_list == NULL) {
|
|
1660
|
-
usbi_err(ctx, "failed to alloc guid list");
|
|
1661
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
1662
|
-
}
|
|
1663
|
-
|
|
1664
|
-
guid_list[HUB_PASS] = &GUID_DEVINTERFACE_USB_HUB;
|
|
1665
|
-
guid_list[DEV_PASS] = &GUID_DEVINTERFACE_USB_DEVICE;
|
|
1666
|
-
guid_list[HCD_PASS] = &GUID_DEVINTERFACE_USB_HOST_CONTROLLER;
|
|
1667
|
-
guid_list[GEN_PASS] = NULL;
|
|
1668
|
-
if (HidD_GetHidGuid != NULL) {
|
|
1669
|
-
HidD_GetHidGuid(&hid_guid);
|
|
1670
|
-
guid_list[HID_PASS] = &hid_guid;
|
|
1671
|
-
} else {
|
|
1672
|
-
guid_list[HID_PASS] = NULL;
|
|
1673
|
-
}
|
|
1674
|
-
nb_guids = EXT_PASS;
|
|
1675
|
-
|
|
1676
|
-
unref_list = malloc(unref_size * sizeof(void *));
|
|
1677
|
-
if (unref_list == NULL) {
|
|
1678
|
-
usbi_err(ctx, "failed to alloc unref list");
|
|
1679
|
-
free((void *)guid_list);
|
|
1680
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
1681
|
-
}
|
|
1682
|
-
|
|
1683
|
-
dev_info_intf = pSetupDiGetClassDevsA(NULL, NULL, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
|
|
1684
|
-
if (dev_info_intf == INVALID_HANDLE_VALUE) {
|
|
1685
|
-
usbi_err(ctx, "failed to obtain device info list: %s", windows_error_str(0));
|
|
1686
|
-
free(unref_list);
|
|
1687
|
-
free((void *)guid_list);
|
|
1688
|
-
return LIBUSB_ERROR_OTHER;
|
|
1689
|
-
}
|
|
1690
|
-
|
|
1691
|
-
for (pass = 0; ((pass < nb_guids) && (r == LIBUSB_SUCCESS)); pass++) {
|
|
1692
|
-
pass_type = MIN(pass, EXT_PASS);
|
|
1693
|
-
#if defined(ENABLE_LOGGING)
|
|
1694
|
-
const char * const passname[] = {"HUB", "DEV", "HCD", "GEN", "HID", "EXT"};
|
|
1695
|
-
usbi_dbg(ctx, "ENUM pass %s %s", passname[pass_type], guid_to_string(guid_list[pass], guid_string));
|
|
1696
|
-
#endif
|
|
1697
|
-
if ((pass == HID_PASS) && (guid_list[HID_PASS] == NULL))
|
|
1698
|
-
continue;
|
|
1699
|
-
|
|
1700
|
-
dev_info = (pass != GEN_PASS) ? &dev_info_intf : &dev_info_enum;
|
|
1701
|
-
|
|
1702
|
-
for (i = 0; ; i++) {
|
|
1703
|
-
// safe loop: free up any (unprotected) dynamic resource
|
|
1704
|
-
// NB: this is always executed before breaking the loop
|
|
1705
|
-
safe_free(dev_interface_path);
|
|
1706
|
-
priv = parent_priv = NULL;
|
|
1707
|
-
dev = parent_dev = NULL;
|
|
1708
|
-
|
|
1709
|
-
// Safe loop: end of loop conditions
|
|
1710
|
-
if (r != LIBUSB_SUCCESS)
|
|
1711
|
-
break;
|
|
1712
|
-
|
|
1713
|
-
if (pass != GEN_PASS) {
|
|
1714
|
-
// Except for GEN, all passes deal with device interfaces
|
|
1715
|
-
r = get_interface_details(ctx, *dev_info, &dev_info_data, guid_list[pass], &_index, &dev_interface_path);
|
|
1716
|
-
if ((r != LIBUSB_SUCCESS) || (dev_interface_path == NULL)) {
|
|
1717
|
-
_index = 0;
|
|
1718
|
-
break;
|
|
1719
|
-
}
|
|
1720
|
-
} else {
|
|
1721
|
-
// Workaround for a Nec/Renesas USB 3.0 driver bug where root hubs are
|
|
1722
|
-
// being listed under the "NUSB3" PnP Symbolic Name rather than "USB".
|
|
1723
|
-
// The Intel USB 3.0 driver behaves similar, but uses "IUSB3"
|
|
1724
|
-
// The Intel Alpine Ridge USB 3.1 driver uses "IARUSB3"
|
|
1725
|
-
for (; usb_enum_index < nb_usb_enumerators; usb_enum_index++) {
|
|
1726
|
-
if (get_devinfo_data(ctx, dev_info, &dev_info_data, usb_enumerator[usb_enum_index], i))
|
|
1727
|
-
break;
|
|
1728
|
-
i = 0;
|
|
1729
|
-
}
|
|
1730
|
-
if (usb_enum_index == nb_usb_enumerators)
|
|
1731
|
-
break;
|
|
1732
|
-
}
|
|
1733
|
-
|
|
1734
|
-
// Read the Device ID path
|
|
1735
|
-
if (!pSetupDiGetDeviceInstanceIdA(*dev_info, &dev_info_data, dev_id, sizeof(dev_id), NULL)) {
|
|
1736
|
-
usbi_warn(ctx, "could not read the device instance ID for devInst %lX, skipping",
|
|
1737
|
-
ULONG_CAST(dev_info_data.DevInst));
|
|
1738
|
-
continue;
|
|
1739
|
-
}
|
|
1740
|
-
|
|
1741
|
-
usbi_dbg(ctx, "ENUM processing %s", dev_id);
|
|
1742
|
-
|
|
1743
|
-
// Set API to use or get additional data from generic pass
|
|
1744
|
-
api = USB_API_UNSUPPORTED;
|
|
1745
|
-
sub_api = SUB_API_NOTSET;
|
|
1746
|
-
switch (pass_type) {
|
|
1747
|
-
case HCD_PASS:
|
|
1748
|
-
break;
|
|
1749
|
-
case HUB_PASS:
|
|
1750
|
-
api = USB_API_HUB;
|
|
1751
|
-
// Fetch the PnP enumerator class for this hub
|
|
1752
|
-
// This will allow us to enumerate all classes during the GEN pass
|
|
1753
|
-
if (!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME,
|
|
1754
|
-
NULL, (PBYTE)enumerator, sizeof(enumerator), NULL)) {
|
|
1755
|
-
usbi_err(ctx, "could not read enumerator string for device '%s': %s", dev_id, windows_error_str(0));
|
|
1756
|
-
LOOP_BREAK(LIBUSB_ERROR_OTHER);
|
|
1757
|
-
}
|
|
1758
|
-
for (j = 0; j < nb_usb_enumerators; j++) {
|
|
1759
|
-
if (strcmp(usb_enumerator[j], enumerator) == 0)
|
|
1760
|
-
break;
|
|
1761
|
-
}
|
|
1762
|
-
if (j == nb_usb_enumerators) {
|
|
1763
|
-
usbi_dbg(ctx, "found new PnP enumerator string '%s'", enumerator);
|
|
1764
|
-
if (nb_usb_enumerators < ARRAYSIZE(usb_enumerator)) {
|
|
1765
|
-
usb_enumerator[nb_usb_enumerators] = _strdup(enumerator);
|
|
1766
|
-
if (usb_enumerator[nb_usb_enumerators] != NULL) {
|
|
1767
|
-
nb_usb_enumerators++;
|
|
1768
|
-
} else {
|
|
1769
|
-
usbi_err(ctx, "could not allocate enumerator string '%s'", enumerator);
|
|
1770
|
-
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1771
|
-
}
|
|
1772
|
-
} else {
|
|
1773
|
-
usbi_warn(ctx, "too many enumerator strings, some devices may not be accessible");
|
|
1774
|
-
}
|
|
1775
|
-
}
|
|
1776
|
-
break;
|
|
1777
|
-
case GEN_PASS:
|
|
1778
|
-
// We use the GEN pass to detect driverless devices...
|
|
1779
|
-
if (!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_DRIVER,
|
|
1780
|
-
NULL, NULL, 0, NULL) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
|
|
1781
|
-
usbi_info(ctx, "The following device has no driver: '%s'", dev_id);
|
|
1782
|
-
usbi_info(ctx, "libusb will not be able to access it");
|
|
1783
|
-
}
|
|
1784
|
-
// ...and to add the additional device interface GUIDs
|
|
1785
|
-
r = get_guid(ctx, dev_id, dev_info, &dev_info_data, 0, &if_guid);
|
|
1786
|
-
if (r == LIBUSB_SUCCESS && if_guid != NULL) {
|
|
1787
|
-
// Check if we've already seen this GUID
|
|
1788
|
-
for (j = EXT_PASS; j < nb_guids; j++) {
|
|
1789
|
-
if (memcmp(guid_list[j], if_guid, sizeof(*if_guid)) == 0)
|
|
1790
|
-
break;
|
|
1791
|
-
}
|
|
1792
|
-
if (j == nb_guids) {
|
|
1793
|
-
usbi_dbg(ctx, "extra GUID: %s", guid_to_string(if_guid, guid_string));
|
|
1794
|
-
// Extend the guid_list capacity if needed
|
|
1795
|
-
if (nb_guids == guid_size) {
|
|
1796
|
-
new_guid_list = realloc((void *)guid_list, (guid_size + GUID_SIZE_STEP) * sizeof(void *));
|
|
1797
|
-
if (new_guid_list == NULL) {
|
|
1798
|
-
usbi_err(ctx, "failed to realloc guid list");
|
|
1799
|
-
free(if_guid);
|
|
1800
|
-
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1801
|
-
}
|
|
1802
|
-
guid_list = new_guid_list;
|
|
1803
|
-
guid_size += GUID_SIZE_STEP;
|
|
1804
|
-
}
|
|
1805
|
-
guid_list[nb_guids++] = if_guid;
|
|
1806
|
-
} else {
|
|
1807
|
-
// Duplicate, ignore
|
|
1808
|
-
free(if_guid);
|
|
1809
|
-
}
|
|
1810
|
-
} else if (r == LIBUSB_ERROR_ACCESS) {
|
|
1811
|
-
r = LIBUSB_SUCCESS;
|
|
1812
|
-
} else if (r == LIBUSB_ERROR_NO_MEM) {
|
|
1813
|
-
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1814
|
-
} else {
|
|
1815
|
-
if (r != LIBUSB_SUCCESS) {
|
|
1816
|
-
usbi_warn(ctx, "unexpected error during getting DeviceInterfaceGUID for '%s'", dev_id);
|
|
1817
|
-
}
|
|
1818
|
-
}
|
|
1819
|
-
break;
|
|
1820
|
-
case HID_PASS:
|
|
1821
|
-
api = USB_API_HID;
|
|
1822
|
-
break;
|
|
1823
|
-
case DEV_PASS:
|
|
1824
|
-
case EXT_PASS:
|
|
1825
|
-
// Get the API type (after checking that the driver installation is OK)
|
|
1826
|
-
if ((!pSetupDiGetDeviceRegistryPropertyA(*dev_info, &dev_info_data, SPDRP_INSTALL_STATE,
|
|
1827
|
-
NULL, (PBYTE)&install_state, sizeof(install_state), &size)) || (size != sizeof(install_state))) {
|
|
1828
|
-
usbi_warn(ctx, "could not detect installation state of driver for '%s': %s",
|
|
1829
|
-
dev_id, windows_error_str(0));
|
|
1830
|
-
} else if (install_state != 0) {
|
|
1831
|
-
usbi_warn(ctx, "driver for device '%s' is reporting an issue (code: %lu) - skipping",
|
|
1832
|
-
dev_id, ULONG_CAST(install_state));
|
|
1833
|
-
continue;
|
|
1834
|
-
}
|
|
1835
|
-
get_api_type(dev_info, &dev_info_data, &api, &sub_api);
|
|
1836
|
-
break;
|
|
1837
|
-
default:
|
|
1838
|
-
assert(false); // unreachable since all pass types covered explicitly
|
|
1839
|
-
}
|
|
1840
|
-
|
|
1841
|
-
// Find parent device (for the passes that need it)
|
|
1842
|
-
if (pass >= GEN_PASS) {
|
|
1843
|
-
parent_dev = get_ancestor(ctx, dev_info_data.DevInst, NULL);
|
|
1844
|
-
if (parent_dev == NULL) {
|
|
1845
|
-
// Root hubs will not have a parent
|
|
1846
|
-
dev = usbi_get_device_by_session_id(ctx, (unsigned long)dev_info_data.DevInst);
|
|
1847
|
-
if (dev != NULL) {
|
|
1848
|
-
priv = usbi_get_device_priv(dev);
|
|
1849
|
-
if (priv->root_hub)
|
|
1850
|
-
goto track_unref;
|
|
1851
|
-
libusb_unref_device(dev);
|
|
1852
|
-
}
|
|
1853
|
-
|
|
1854
|
-
usbi_dbg(ctx, "unlisted ancestor for '%s' (non USB HID, newly connected, etc.) - ignoring", dev_id);
|
|
1855
|
-
continue;
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1858
|
-
parent_priv = usbi_get_device_priv(parent_dev);
|
|
1859
|
-
// virtual USB devices are also listed during GEN - don't process these yet
|
|
1860
|
-
if ((pass == GEN_PASS) && (parent_priv->apib->id != USB_API_HUB)) {
|
|
1861
|
-
libusb_unref_device(parent_dev);
|
|
1862
|
-
continue;
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
|
|
1866
|
-
// Create new or match existing device, using the devInst as session id
|
|
1867
|
-
if ((pass <= GEN_PASS) && (pass != HCD_PASS)) { // For subsequent passes, we'll lookup the parent
|
|
1868
|
-
// These are the passes that create "new" devices
|
|
1869
|
-
session_id = (unsigned long)dev_info_data.DevInst;
|
|
1870
|
-
dev = usbi_get_device_by_session_id(ctx, session_id);
|
|
1871
|
-
if (dev == NULL) {
|
|
1872
|
-
alloc_device:
|
|
1873
|
-
usbi_dbg(ctx, "allocating new device for session [%lX]", session_id);
|
|
1874
|
-
dev = usbi_alloc_device(ctx, session_id);
|
|
1875
|
-
if (dev == NULL)
|
|
1876
|
-
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1877
|
-
|
|
1878
|
-
priv = winusb_device_priv_init(dev);
|
|
1879
|
-
priv->dev_id = _strdup(dev_id);
|
|
1880
|
-
priv->class_guid = dev_info_data.ClassGuid;
|
|
1881
|
-
if (priv->dev_id == NULL) {
|
|
1882
|
-
libusb_unref_device(dev);
|
|
1883
|
-
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1884
|
-
}
|
|
1885
|
-
} else {
|
|
1886
|
-
usbi_dbg(ctx, "found existing device for session [%lX]", session_id);
|
|
1887
|
-
|
|
1888
|
-
priv = usbi_get_device_priv(dev);
|
|
1889
|
-
if (strcmp(priv->dev_id, dev_id) != 0) {
|
|
1890
|
-
usbi_dbg(ctx, "device instance ID for session [%lX] changed", session_id);
|
|
1891
|
-
usbi_disconnect_device(dev);
|
|
1892
|
-
libusb_unref_device(dev);
|
|
1893
|
-
goto alloc_device;
|
|
1894
|
-
}
|
|
1895
|
-
if (!IsEqualGUID(&priv->class_guid, &dev_info_data.ClassGuid)) {
|
|
1896
|
-
usbi_dbg(ctx, "device class GUID for session [%lX] changed", session_id);
|
|
1897
|
-
usbi_disconnect_device(dev);
|
|
1898
|
-
libusb_unref_device(dev);
|
|
1899
|
-
goto alloc_device;
|
|
1900
|
-
}
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
track_unref:
|
|
1904
|
-
// Keep track of devices that need unref
|
|
1905
|
-
if (unref_cur == unref_size) {
|
|
1906
|
-
new_unref_list = realloc(unref_list, (unref_size + UNREF_SIZE_STEP) * sizeof(void *));
|
|
1907
|
-
if (new_unref_list == NULL) {
|
|
1908
|
-
usbi_err(ctx, "could not realloc list for unref - aborting");
|
|
1909
|
-
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1910
|
-
}
|
|
1911
|
-
unref_list = new_unref_list;
|
|
1912
|
-
unref_size += UNREF_SIZE_STEP;
|
|
1913
|
-
}
|
|
1914
|
-
unref_list[unref_cur++] = dev;
|
|
1915
|
-
}
|
|
1916
|
-
|
|
1917
|
-
// Setup device
|
|
1918
|
-
switch (pass_type) {
|
|
1919
|
-
case HUB_PASS:
|
|
1920
|
-
case DEV_PASS:
|
|
1921
|
-
// If the device has already been setup, don't do it again
|
|
1922
|
-
if (priv->path != NULL)
|
|
1923
|
-
break;
|
|
1924
|
-
// Take care of API initialization
|
|
1925
|
-
priv->path = dev_interface_path;
|
|
1926
|
-
dev_interface_path = NULL;
|
|
1927
|
-
priv->apib = &usb_api_backend[api];
|
|
1928
|
-
priv->sub_api = sub_api;
|
|
1929
|
-
switch (api) {
|
|
1930
|
-
case USB_API_COMPOSITE:
|
|
1931
|
-
break;
|
|
1932
|
-
case USB_API_HUB:
|
|
1933
|
-
parent_dev = get_ancestor(ctx, dev_info_data.DevInst, NULL);
|
|
1934
|
-
if (parent_dev == NULL) {
|
|
1935
|
-
if (!get_dev_port_number(*dev_info, &dev_info_data, &hub_port_nr) || hub_port_nr == 0) {
|
|
1936
|
-
if (bus_number == UINT8_MAX) {
|
|
1937
|
-
usbi_warn(ctx, "program assertion failed - found more than %u buses, skipping the rest", UINT8_MAX);
|
|
1938
|
-
break;
|
|
1939
|
-
}
|
|
1940
|
-
priv->root_hub = true;
|
|
1941
|
-
dev->bus_number = ++bus_number;
|
|
1942
|
-
usbi_dbg(ctx, "assigning Root Hub '%s' bus number %u", dev_id, bus_number);
|
|
1943
|
-
}
|
|
1944
|
-
} else {
|
|
1945
|
-
libusb_unref_device(parent_dev);
|
|
1946
|
-
}
|
|
1947
|
-
break;
|
|
1948
|
-
case USB_API_HID:
|
|
1949
|
-
priv->hid = calloc(1, sizeof(struct hid_device_priv));
|
|
1950
|
-
if (priv->hid == NULL)
|
|
1951
|
-
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1952
|
-
break;
|
|
1953
|
-
default:
|
|
1954
|
-
// For other devices, the first interface is the same as the device
|
|
1955
|
-
priv->usb_interface[0].path = _strdup(priv->path);
|
|
1956
|
-
if (priv->usb_interface[0].path == NULL)
|
|
1957
|
-
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1958
|
-
// The following is needed if we want API calls to work for both simple
|
|
1959
|
-
// and composite devices.
|
|
1960
|
-
for (j = 0; j < USB_MAXINTERFACES; j++)
|
|
1961
|
-
priv->usb_interface[j].apib = &usb_api_backend[api];
|
|
1962
|
-
break;
|
|
1963
|
-
}
|
|
1964
|
-
break;
|
|
1965
|
-
case HCD_PASS:
|
|
1966
|
-
r = enumerate_hcd_root_hub(ctx, dev_id, dev_info_data.DevInst);
|
|
1967
|
-
break;
|
|
1968
|
-
case GEN_PASS:
|
|
1969
|
-
port_nr = 0;
|
|
1970
|
-
if (!get_dev_port_number(*dev_info, &dev_info_data, &port_nr))
|
|
1971
|
-
usbi_warn(ctx, "could not retrieve port number for device '%s': %s", dev_id, windows_error_str(0));
|
|
1972
|
-
r = init_device(dev, parent_dev, (uint8_t)port_nr, dev_info_data.DevInst);
|
|
1973
|
-
if (r == LIBUSB_SUCCESS) {
|
|
1974
|
-
// Append device to the list of discovered devices
|
|
1975
|
-
discdevs = discovered_devs_append(*_discdevs, dev);
|
|
1976
|
-
if (!discdevs)
|
|
1977
|
-
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
|
|
1978
|
-
|
|
1979
|
-
*_discdevs = discdevs;
|
|
1980
|
-
} else {
|
|
1981
|
-
// Failed to initialize a single device doesn't stop us from enumerating all other devices,
|
|
1982
|
-
// but we skip it (don't add to list of discovered devices)
|
|
1983
|
-
usbi_warn(ctx, "failed to initialize device '%s'", priv->dev_id);
|
|
1984
|
-
r = LIBUSB_SUCCESS;
|
|
1985
|
-
}
|
|
1986
|
-
break;
|
|
1987
|
-
case HID_PASS:
|
|
1988
|
-
case EXT_PASS:
|
|
1989
|
-
if (parent_priv->apib->id == USB_API_HID || parent_priv->apib->id == USB_API_COMPOSITE) {
|
|
1990
|
-
if (parent_priv->apib->id == USB_API_HID) {
|
|
1991
|
-
usbi_dbg(ctx, "setting HID interface for [%lX]:", parent_dev->session_data);
|
|
1992
|
-
r = set_hid_interface(ctx, parent_dev, dev_interface_path);
|
|
1993
|
-
} else {
|
|
1994
|
-
usbi_dbg(ctx, "setting composite interface for [%lX]:", parent_dev->session_data);
|
|
1995
|
-
r = set_composite_interface(ctx, parent_dev, dev_interface_path, dev_id, api, sub_api);
|
|
1996
|
-
}
|
|
1997
|
-
switch (r) {
|
|
1998
|
-
case LIBUSB_SUCCESS:
|
|
1999
|
-
dev_interface_path = NULL;
|
|
2000
|
-
break;
|
|
2001
|
-
case LIBUSB_ERROR_ACCESS:
|
|
2002
|
-
// interface has already been set => make sure dev_interface_path is freed then
|
|
2003
|
-
r = LIBUSB_SUCCESS;
|
|
2004
|
-
break;
|
|
2005
|
-
default:
|
|
2006
|
-
LOOP_BREAK(r);
|
|
2007
|
-
break;
|
|
2008
|
-
}
|
|
2009
|
-
}
|
|
2010
|
-
libusb_unref_device(parent_dev);
|
|
2011
|
-
break;
|
|
2012
|
-
default:
|
|
2013
|
-
assert(false); // unreachable since all pass types covered explicitly
|
|
2014
|
-
}
|
|
2015
|
-
}
|
|
2016
|
-
}
|
|
2017
|
-
|
|
2018
|
-
pSetupDiDestroyDeviceInfoList(dev_info_intf);
|
|
2019
|
-
|
|
2020
|
-
// Free any additional GUIDs
|
|
2021
|
-
for (pass = EXT_PASS; pass < nb_guids; pass++)
|
|
2022
|
-
free((void *)guid_list[pass]);
|
|
2023
|
-
free((void *)guid_list);
|
|
2024
|
-
|
|
2025
|
-
// Free any PnP enumerator strings
|
|
2026
|
-
for (i = 1; i < nb_usb_enumerators; i++)
|
|
2027
|
-
free((void *)usb_enumerator[i]);
|
|
2028
|
-
|
|
2029
|
-
// Unref newly allocated devs
|
|
2030
|
-
for (i = 0; i < unref_cur; i++)
|
|
2031
|
-
libusb_unref_device(unref_list[i]);
|
|
2032
|
-
free(unref_list);
|
|
2033
|
-
|
|
2034
|
-
return r;
|
|
2035
|
-
}
|
|
2036
|
-
|
|
2037
|
-
static int winusb_get_config_descriptor(struct libusb_device *dev, uint8_t config_index, void *buffer, size_t len)
|
|
2038
|
-
{
|
|
2039
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
|
|
2040
|
-
PUSB_CONFIGURATION_DESCRIPTOR config_header;
|
|
2041
|
-
|
|
2042
|
-
if ((priv->config_descriptor == NULL) || (priv->config_descriptor[config_index] == NULL))
|
|
2043
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
2044
|
-
|
|
2045
|
-
config_header = priv->config_descriptor[config_index];
|
|
2046
|
-
|
|
2047
|
-
len = MIN(len, config_header->wTotalLength);
|
|
2048
|
-
memcpy(buffer, config_header, len);
|
|
2049
|
-
return (int)len;
|
|
2050
|
-
}
|
|
2051
|
-
|
|
2052
|
-
static int winusb_get_config_descriptor_by_value(struct libusb_device *dev, uint8_t bConfigurationValue,
|
|
2053
|
-
void **buffer)
|
|
2054
|
-
{
|
|
2055
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
|
|
2056
|
-
PUSB_CONFIGURATION_DESCRIPTOR config_header;
|
|
2057
|
-
uint8_t index;
|
|
2058
|
-
|
|
2059
|
-
if (priv->config_descriptor == NULL)
|
|
2060
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
2061
|
-
|
|
2062
|
-
for (index = 0; index < dev->device_descriptor.bNumConfigurations; index++) {
|
|
2063
|
-
config_header = priv->config_descriptor[index];
|
|
2064
|
-
if (config_header == NULL)
|
|
2065
|
-
continue;
|
|
2066
|
-
if (config_header->bConfigurationValue == bConfigurationValue) {
|
|
2067
|
-
*buffer = config_header;
|
|
2068
|
-
return (int)config_header->wTotalLength;
|
|
2069
|
-
}
|
|
2070
|
-
}
|
|
2071
|
-
|
|
2072
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
2073
|
-
}
|
|
2074
|
-
|
|
2075
|
-
/*
|
|
2076
|
-
* return the cached copy of the active config descriptor
|
|
2077
|
-
*/
|
|
2078
|
-
static int winusb_get_active_config_descriptor(struct libusb_device *dev, void *buffer, size_t len)
|
|
2079
|
-
{
|
|
2080
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
|
|
2081
|
-
void *config_desc;
|
|
2082
|
-
int r;
|
|
2083
|
-
|
|
2084
|
-
if (priv->active_config == 0)
|
|
2085
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
2086
|
-
|
|
2087
|
-
r = winusb_get_config_descriptor_by_value(dev, priv->active_config, &config_desc);
|
|
2088
|
-
if (r < 0)
|
|
2089
|
-
return r;
|
|
2090
|
-
|
|
2091
|
-
len = MIN(len, (size_t)r);
|
|
2092
|
-
memcpy(buffer, config_desc, len);
|
|
2093
|
-
return (int)len;
|
|
2094
|
-
}
|
|
2095
|
-
|
|
2096
|
-
static int winusb_open(struct libusb_device_handle *dev_handle)
|
|
2097
|
-
{
|
|
2098
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2099
|
-
|
|
2100
|
-
CHECK_SUPPORTED_API(priv->apib, open);
|
|
2101
|
-
|
|
2102
|
-
return priv->apib->open(SUB_API_NOTSET, dev_handle);
|
|
2103
|
-
}
|
|
2104
|
-
|
|
2105
|
-
static void winusb_close(struct libusb_device_handle *dev_handle)
|
|
2106
|
-
{
|
|
2107
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2108
|
-
|
|
2109
|
-
if (priv->apib->close)
|
|
2110
|
-
priv->apib->close(SUB_API_NOTSET, dev_handle);
|
|
2111
|
-
}
|
|
2112
|
-
|
|
2113
|
-
static int winusb_get_configuration(struct libusb_device_handle *dev_handle, uint8_t *config)
|
|
2114
|
-
{
|
|
2115
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2116
|
-
|
|
2117
|
-
*config = priv->active_config;
|
|
2118
|
-
return LIBUSB_SUCCESS;
|
|
2119
|
-
}
|
|
2120
|
-
|
|
2121
|
-
/*
|
|
2122
|
-
* from http://msdn.microsoft.com/en-us/library/ms793522.aspx: "The port driver
|
|
2123
|
-
* does not currently expose a service that allows higher-level drivers to set
|
|
2124
|
-
* the configuration."
|
|
2125
|
-
*/
|
|
2126
|
-
static int winusb_set_configuration(struct libusb_device_handle *dev_handle, uint8_t config)
|
|
2127
|
-
{
|
|
2128
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2129
|
-
int r = LIBUSB_SUCCESS;
|
|
2130
|
-
|
|
2131
|
-
r = libusb_control_transfer(dev_handle, LIBUSB_ENDPOINT_OUT |
|
|
2132
|
-
LIBUSB_REQUEST_TYPE_STANDARD | LIBUSB_RECIPIENT_DEVICE,
|
|
2133
|
-
LIBUSB_REQUEST_SET_CONFIGURATION, config,
|
|
2134
|
-
0, NULL, 0, 1000);
|
|
2135
|
-
|
|
2136
|
-
if (r == LIBUSB_SUCCESS)
|
|
2137
|
-
priv->active_config = config;
|
|
2138
|
-
|
|
2139
|
-
return r;
|
|
2140
|
-
}
|
|
2141
|
-
|
|
2142
|
-
static int winusb_claim_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
|
|
2143
|
-
{
|
|
2144
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2145
|
-
int r;
|
|
2146
|
-
|
|
2147
|
-
CHECK_SUPPORTED_API(priv->apib, claim_interface);
|
|
2148
|
-
|
|
2149
|
-
safe_free(priv->usb_interface[iface].endpoint);
|
|
2150
|
-
priv->usb_interface[iface].nb_endpoints = 0;
|
|
2151
|
-
|
|
2152
|
-
r = priv->apib->claim_interface(SUB_API_NOTSET, dev_handle, iface);
|
|
2153
|
-
|
|
2154
|
-
if (r == LIBUSB_SUCCESS)
|
|
2155
|
-
r = windows_assign_endpoints(dev_handle, iface, 0);
|
|
2156
|
-
|
|
2157
|
-
return r;
|
|
2158
|
-
}
|
|
2159
|
-
|
|
2160
|
-
static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
|
|
2161
|
-
{
|
|
2162
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2163
|
-
int r;
|
|
2164
|
-
|
|
2165
|
-
CHECK_SUPPORTED_API(priv->apib, set_interface_altsetting);
|
|
2166
|
-
|
|
2167
|
-
safe_free(priv->usb_interface[iface].endpoint);
|
|
2168
|
-
priv->usb_interface[iface].nb_endpoints = 0;
|
|
2169
|
-
|
|
2170
|
-
r = priv->apib->set_interface_altsetting(SUB_API_NOTSET, dev_handle, iface, altsetting);
|
|
2171
|
-
|
|
2172
|
-
if (r == LIBUSB_SUCCESS)
|
|
2173
|
-
r = windows_assign_endpoints(dev_handle, iface, altsetting);
|
|
2174
|
-
|
|
2175
|
-
return r;
|
|
2176
|
-
}
|
|
2177
|
-
|
|
2178
|
-
static int winusb_release_interface(struct libusb_device_handle *dev_handle, uint8_t iface)
|
|
2179
|
-
{
|
|
2180
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2181
|
-
|
|
2182
|
-
CHECK_SUPPORTED_API(priv->apib, release_interface);
|
|
2183
|
-
|
|
2184
|
-
return priv->apib->release_interface(SUB_API_NOTSET, dev_handle, iface);
|
|
2185
|
-
}
|
|
2186
|
-
|
|
2187
|
-
static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
|
|
2188
|
-
{
|
|
2189
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2190
|
-
|
|
2191
|
-
CHECK_SUPPORTED_API(priv->apib, clear_halt);
|
|
2192
|
-
|
|
2193
|
-
return priv->apib->clear_halt(SUB_API_NOTSET, dev_handle, endpoint);
|
|
2194
|
-
}
|
|
2195
|
-
|
|
2196
|
-
static int winusb_reset_device(struct libusb_device_handle *dev_handle)
|
|
2197
|
-
{
|
|
2198
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2199
|
-
|
|
2200
|
-
CHECK_SUPPORTED_API(priv->apib, reset_device);
|
|
2201
|
-
|
|
2202
|
-
return priv->apib->reset_device(SUB_API_NOTSET, dev_handle);
|
|
2203
|
-
}
|
|
2204
|
-
|
|
2205
|
-
static void winusb_destroy_device(struct libusb_device *dev)
|
|
2206
|
-
{
|
|
2207
|
-
winusb_device_priv_release(dev);
|
|
2208
|
-
}
|
|
2209
|
-
|
|
2210
|
-
static void winusb_clear_transfer_priv(struct usbi_transfer *itransfer)
|
|
2211
|
-
{
|
|
2212
|
-
struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
|
|
2213
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
2214
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
2215
|
-
int sub_api = priv->sub_api;
|
|
2216
|
-
|
|
2217
|
-
safe_free(transfer_priv->hid_buffer);
|
|
2218
|
-
|
|
2219
|
-
if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS && sub_api == SUB_API_WINUSB) {
|
|
2220
|
-
if (transfer_priv->isoch_buffer_handle != NULL) {
|
|
2221
|
-
if (WinUSBX[sub_api].UnregisterIsochBuffer(transfer_priv->isoch_buffer_handle)) {
|
|
2222
|
-
transfer_priv->isoch_buffer_handle = NULL;
|
|
2223
|
-
} else {
|
|
2224
|
-
usbi_warn(TRANSFER_CTX(transfer), "failed to unregister WinUSB isoch buffer: %s", windows_error_str(0));
|
|
2225
|
-
}
|
|
2226
|
-
}
|
|
2227
|
-
}
|
|
2228
|
-
|
|
2229
|
-
safe_free(transfer_priv->iso_context);
|
|
2230
|
-
|
|
2231
|
-
// When auto claim is in use, attempt to release the auto-claimed interface
|
|
2232
|
-
auto_release(itransfer);
|
|
2233
|
-
}
|
|
2234
|
-
|
|
2235
|
-
static int winusb_submit_transfer(struct usbi_transfer *itransfer)
|
|
2236
|
-
{
|
|
2237
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
2238
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
2239
|
-
int (*transfer_fn)(int, struct usbi_transfer *);
|
|
2240
|
-
|
|
2241
|
-
switch (transfer->type) {
|
|
2242
|
-
case LIBUSB_TRANSFER_TYPE_CONTROL:
|
|
2243
|
-
transfer_fn = priv->apib->submit_control_transfer;
|
|
2244
|
-
break;
|
|
2245
|
-
case LIBUSB_TRANSFER_TYPE_BULK:
|
|
2246
|
-
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
|
|
2247
|
-
transfer_fn = priv->apib->submit_bulk_transfer;
|
|
2248
|
-
break;
|
|
2249
|
-
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
|
|
2250
|
-
transfer_fn = priv->apib->submit_iso_transfer;
|
|
2251
|
-
break;
|
|
2252
|
-
default:
|
|
2253
|
-
// Should not get here since windows_submit_transfer() validates
|
|
2254
|
-
// the transfer->type field
|
|
2255
|
-
usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
|
|
2256
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
2257
|
-
}
|
|
2258
|
-
|
|
2259
|
-
if (transfer_fn == NULL) {
|
|
2260
|
-
usbi_warn(TRANSFER_CTX(transfer),
|
|
2261
|
-
"unsupported transfer type %d (unrecognized device driver)",
|
|
2262
|
-
transfer->type);
|
|
2263
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
2264
|
-
}
|
|
2265
|
-
|
|
2266
|
-
return transfer_fn(SUB_API_NOTSET, itransfer);
|
|
2267
|
-
}
|
|
2268
|
-
|
|
2269
|
-
static int winusb_cancel_transfer(struct usbi_transfer *itransfer)
|
|
2270
|
-
{
|
|
2271
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
2272
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
2273
|
-
|
|
2274
|
-
CHECK_SUPPORTED_API(priv->apib, cancel_transfer);
|
|
2275
|
-
|
|
2276
|
-
return priv->apib->cancel_transfer(SUB_API_NOTSET, itransfer);
|
|
2277
|
-
}
|
|
2278
|
-
|
|
2279
|
-
static enum libusb_transfer_status winusb_copy_transfer_data(struct usbi_transfer *itransfer, DWORD length)
|
|
2280
|
-
{
|
|
2281
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
2282
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
2283
|
-
|
|
2284
|
-
if (priv->apib->copy_transfer_data == NULL) {
|
|
2285
|
-
usbi_err(TRANSFER_CTX(transfer), "program assertion failed - no function to copy transfer data");
|
|
2286
|
-
return LIBUSB_TRANSFER_ERROR;
|
|
2287
|
-
}
|
|
2288
|
-
|
|
2289
|
-
return priv->apib->copy_transfer_data(SUB_API_NOTSET, itransfer, length);
|
|
2290
|
-
}
|
|
2291
|
-
|
|
2292
|
-
// NB: MSVC6 does not support named initializers.
|
|
2293
|
-
const struct windows_backend winusb_backend = {
|
|
2294
|
-
winusb_init,
|
|
2295
|
-
winusb_exit,
|
|
2296
|
-
winusb_get_device_list,
|
|
2297
|
-
winusb_open,
|
|
2298
|
-
winusb_close,
|
|
2299
|
-
winusb_get_active_config_descriptor,
|
|
2300
|
-
winusb_get_config_descriptor,
|
|
2301
|
-
winusb_get_config_descriptor_by_value,
|
|
2302
|
-
winusb_get_configuration,
|
|
2303
|
-
winusb_set_configuration,
|
|
2304
|
-
winusb_claim_interface,
|
|
2305
|
-
winusb_release_interface,
|
|
2306
|
-
winusb_set_interface_altsetting,
|
|
2307
|
-
winusb_clear_halt,
|
|
2308
|
-
winusb_reset_device,
|
|
2309
|
-
winusb_destroy_device,
|
|
2310
|
-
winusb_submit_transfer,
|
|
2311
|
-
winusb_cancel_transfer,
|
|
2312
|
-
winusb_clear_transfer_priv,
|
|
2313
|
-
winusb_copy_transfer_data,
|
|
2314
|
-
};
|
|
2315
|
-
|
|
2316
|
-
/*
|
|
2317
|
-
* USB API backends
|
|
2318
|
-
*/
|
|
2319
|
-
|
|
2320
|
-
static const char * const composite_driver_names[] = {
|
|
2321
|
-
"USBCCGP", // (Windows built-in) USB Composite Device
|
|
2322
|
-
"dg_ssudbus" // SAMSUNG Mobile USB Composite Device
|
|
2323
|
-
};
|
|
2324
|
-
static const char * const winusbx_driver_names[] = {"libusbK", "libusb0", "WinUSB"};
|
|
2325
|
-
static const char * const hid_driver_names[] = {"HIDUSB", "MOUHID", "KBDHID"};
|
|
2326
|
-
const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
|
|
2327
|
-
{
|
|
2328
|
-
USB_API_UNSUPPORTED,
|
|
2329
|
-
"Unsupported API",
|
|
2330
|
-
NULL, /* driver_name_list */
|
|
2331
|
-
0, /* nb_driver_names */
|
|
2332
|
-
NULL, /* init */
|
|
2333
|
-
NULL, /* exit */
|
|
2334
|
-
NULL, /* open */
|
|
2335
|
-
NULL, /* close */
|
|
2336
|
-
NULL, /* configure_endpoints */
|
|
2337
|
-
NULL, /* claim_interface */
|
|
2338
|
-
NULL, /* set_interface_altsetting */
|
|
2339
|
-
NULL, /* release_interface */
|
|
2340
|
-
NULL, /* clear_halt */
|
|
2341
|
-
NULL, /* reset_device */
|
|
2342
|
-
NULL, /* submit_bulk_transfer */
|
|
2343
|
-
NULL, /* submit_iso_transfer */
|
|
2344
|
-
NULL, /* submit_control_transfer */
|
|
2345
|
-
NULL, /* cancel_transfer */
|
|
2346
|
-
NULL, /* copy_transfer_data */
|
|
2347
|
-
},
|
|
2348
|
-
{
|
|
2349
|
-
USB_API_HUB,
|
|
2350
|
-
"HUB API",
|
|
2351
|
-
NULL, /* driver_name_list */
|
|
2352
|
-
0, /* nb_driver_names */
|
|
2353
|
-
NULL, /* init */
|
|
2354
|
-
NULL, /* exit */
|
|
2355
|
-
NULL, /* open */
|
|
2356
|
-
NULL, /* close */
|
|
2357
|
-
NULL, /* configure_endpoints */
|
|
2358
|
-
NULL, /* claim_interface */
|
|
2359
|
-
NULL, /* set_interface_altsetting */
|
|
2360
|
-
NULL, /* release_interface */
|
|
2361
|
-
NULL, /* clear_halt */
|
|
2362
|
-
NULL, /* reset_device */
|
|
2363
|
-
NULL, /* submit_bulk_transfer */
|
|
2364
|
-
NULL, /* submit_iso_transfer */
|
|
2365
|
-
NULL, /* submit_control_transfer */
|
|
2366
|
-
NULL, /* cancel_transfer */
|
|
2367
|
-
NULL, /* copy_transfer_data */
|
|
2368
|
-
},
|
|
2369
|
-
{
|
|
2370
|
-
USB_API_COMPOSITE,
|
|
2371
|
-
"Composite API",
|
|
2372
|
-
composite_driver_names,
|
|
2373
|
-
ARRAYSIZE(composite_driver_names),
|
|
2374
|
-
NULL, /* init */
|
|
2375
|
-
NULL, /* exit */
|
|
2376
|
-
composite_open,
|
|
2377
|
-
composite_close,
|
|
2378
|
-
NULL, /* configure_endpoints */
|
|
2379
|
-
composite_claim_interface,
|
|
2380
|
-
composite_set_interface_altsetting,
|
|
2381
|
-
composite_release_interface,
|
|
2382
|
-
composite_clear_halt,
|
|
2383
|
-
composite_reset_device,
|
|
2384
|
-
composite_submit_bulk_transfer,
|
|
2385
|
-
composite_submit_iso_transfer,
|
|
2386
|
-
composite_submit_control_transfer,
|
|
2387
|
-
composite_cancel_transfer,
|
|
2388
|
-
composite_copy_transfer_data,
|
|
2389
|
-
},
|
|
2390
|
-
{
|
|
2391
|
-
USB_API_WINUSBX,
|
|
2392
|
-
"WinUSB-like APIs",
|
|
2393
|
-
winusbx_driver_names,
|
|
2394
|
-
ARRAYSIZE(winusbx_driver_names),
|
|
2395
|
-
winusbx_init,
|
|
2396
|
-
winusbx_exit,
|
|
2397
|
-
winusbx_open,
|
|
2398
|
-
winusbx_close,
|
|
2399
|
-
winusbx_configure_endpoints,
|
|
2400
|
-
winusbx_claim_interface,
|
|
2401
|
-
winusbx_set_interface_altsetting,
|
|
2402
|
-
winusbx_release_interface,
|
|
2403
|
-
winusbx_clear_halt,
|
|
2404
|
-
winusbx_reset_device,
|
|
2405
|
-
winusbx_submit_bulk_transfer,
|
|
2406
|
-
winusbx_submit_iso_transfer,
|
|
2407
|
-
winusbx_submit_control_transfer,
|
|
2408
|
-
winusbx_cancel_transfer,
|
|
2409
|
-
winusbx_copy_transfer_data,
|
|
2410
|
-
},
|
|
2411
|
-
{
|
|
2412
|
-
USB_API_HID,
|
|
2413
|
-
"HID API",
|
|
2414
|
-
hid_driver_names,
|
|
2415
|
-
ARRAYSIZE(hid_driver_names),
|
|
2416
|
-
hid_init,
|
|
2417
|
-
hid_exit,
|
|
2418
|
-
hid_open,
|
|
2419
|
-
hid_close,
|
|
2420
|
-
NULL, /* configure_endpoints */
|
|
2421
|
-
hid_claim_interface,
|
|
2422
|
-
hid_set_interface_altsetting,
|
|
2423
|
-
hid_release_interface,
|
|
2424
|
-
hid_clear_halt,
|
|
2425
|
-
hid_reset_device,
|
|
2426
|
-
hid_submit_bulk_transfer,
|
|
2427
|
-
NULL, /* submit_iso_transfer */
|
|
2428
|
-
hid_submit_control_transfer,
|
|
2429
|
-
NULL, /* cancel_transfer */
|
|
2430
|
-
hid_copy_transfer_data,
|
|
2431
|
-
},
|
|
2432
|
-
};
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
/*
|
|
2436
|
-
* WinUSB-like (WinUSB, libusb0/libusbK through libusbk DLL) API functions
|
|
2437
|
-
*/
|
|
2438
|
-
#define WinUSB_Set(h, fn, required) \
|
|
2439
|
-
do { \
|
|
2440
|
-
WinUSBX[SUB_API_WINUSB].fn = (WinUsb_##fn##_t)GetProcAddress(h, "WinUsb_" #fn); \
|
|
2441
|
-
if (required && (WinUSBX[SUB_API_WINUSB].fn == NULL)) { \
|
|
2442
|
-
usbi_err(ctx, "GetProcAddress() failed for WinUsb_%s", #fn); \
|
|
2443
|
-
goto cleanup_winusb; \
|
|
2444
|
-
} \
|
|
2445
|
-
} while (0)
|
|
2446
|
-
|
|
2447
|
-
#define libusbK_Set(sub_api, fn, required) \
|
|
2448
|
-
do { \
|
|
2449
|
-
pLibK_GetProcAddress((PVOID *)&WinUSBX[sub_api].fn, sub_api, KUSB_FNID_##fn); \
|
|
2450
|
-
if (required && (WinUSBX[sub_api].fn == NULL)) { \
|
|
2451
|
-
usbi_err(ctx, "LibK_GetProcAddress() failed for LibK_%s", #fn); \
|
|
2452
|
-
goto cleanup_libusbk; \
|
|
2453
|
-
} \
|
|
2454
|
-
} while (0)
|
|
2455
|
-
|
|
2456
|
-
static bool winusbx_init(struct libusb_context *ctx)
|
|
2457
|
-
{
|
|
2458
|
-
HMODULE hWinUSB, hlibusbK;
|
|
2459
|
-
|
|
2460
|
-
hWinUSB = load_system_library(ctx, "WinUSB");
|
|
2461
|
-
if (hWinUSB != NULL) {
|
|
2462
|
-
WinUSB_Set(hWinUSB, AbortPipe, true);
|
|
2463
|
-
WinUSB_Set(hWinUSB, ControlTransfer, true);
|
|
2464
|
-
WinUSB_Set(hWinUSB, FlushPipe, true);
|
|
2465
|
-
WinUSB_Set(hWinUSB, Free, true);
|
|
2466
|
-
WinUSB_Set(hWinUSB, GetAssociatedInterface, true);
|
|
2467
|
-
WinUSB_Set(hWinUSB, Initialize, true);
|
|
2468
|
-
WinUSB_Set(hWinUSB, ReadPipe, true);
|
|
2469
|
-
WinUSB_Set(hWinUSB, ResetPipe, true);
|
|
2470
|
-
WinUSB_Set(hWinUSB, SetCurrentAlternateSetting, true);
|
|
2471
|
-
WinUSB_Set(hWinUSB, SetPipePolicy, true);
|
|
2472
|
-
WinUSB_Set(hWinUSB, GetPipePolicy, true);
|
|
2473
|
-
WinUSB_Set(hWinUSB, WritePipe, true);
|
|
2474
|
-
|
|
2475
|
-
// Check for isochronous transfers support (available starting with Windows 8.1)
|
|
2476
|
-
WinUSB_Set(hWinUSB, ReadIsochPipeAsap, false);
|
|
2477
|
-
if (WinUSBX[SUB_API_WINUSB].ReadIsochPipeAsap != NULL) {
|
|
2478
|
-
WinUSB_Set(hWinUSB, QueryPipeEx, true);
|
|
2479
|
-
WinUSB_Set(hWinUSB, RegisterIsochBuffer, true);
|
|
2480
|
-
WinUSB_Set(hWinUSB, UnregisterIsochBuffer, true);
|
|
2481
|
-
WinUSB_Set(hWinUSB, WriteIsochPipeAsap, true);
|
|
2482
|
-
}
|
|
2483
|
-
|
|
2484
|
-
WinUSBX[SUB_API_WINUSB].hDll = hWinUSB;
|
|
2485
|
-
|
|
2486
|
-
usbi_info(ctx, "WinUSB DLL available (%s isoch support)",
|
|
2487
|
-
(WinUSBX[SUB_API_WINUSB].ReadIsochPipeAsap != NULL) ? "with" : "without");
|
|
2488
|
-
|
|
2489
|
-
cleanup_winusb:
|
|
2490
|
-
if (WinUSBX[SUB_API_WINUSB].hDll == NULL) {
|
|
2491
|
-
usbi_err(ctx, "failed to initialize WinUSB");
|
|
2492
|
-
memset(&WinUSBX[SUB_API_WINUSB], 0, sizeof(WinUSBX[SUB_API_WINUSB]));
|
|
2493
|
-
FreeLibrary(hWinUSB);
|
|
2494
|
-
hWinUSB = NULL;
|
|
2495
|
-
}
|
|
2496
|
-
} else {
|
|
2497
|
-
usbi_info(ctx, "WinUSB DLL is not available");
|
|
2498
|
-
}
|
|
2499
|
-
|
|
2500
|
-
hlibusbK = load_system_library(ctx, "libusbK");
|
|
2501
|
-
if (hlibusbK != NULL) {
|
|
2502
|
-
LibK_GetVersion_t pLibK_GetVersion;
|
|
2503
|
-
LibK_GetProcAddress_t pLibK_GetProcAddress;
|
|
2504
|
-
int sub_api = 0;
|
|
2505
|
-
|
|
2506
|
-
pLibK_GetVersion = (LibK_GetVersion_t)GetProcAddress(hlibusbK, "LibK_GetVersion");
|
|
2507
|
-
if (pLibK_GetVersion != NULL) {
|
|
2508
|
-
KLIB_VERSION LibK_Version;
|
|
2509
|
-
|
|
2510
|
-
pLibK_GetVersion(&LibK_Version);
|
|
2511
|
-
usbi_dbg(ctx, "libusbK DLL found, version: %d.%d.%d.%d", LibK_Version.Major, LibK_Version.Minor,
|
|
2512
|
-
LibK_Version.Micro, LibK_Version.Nano);
|
|
2513
|
-
} else {
|
|
2514
|
-
usbi_dbg(ctx, "libusbK DLL found, version unknown");
|
|
2515
|
-
}
|
|
2516
|
-
|
|
2517
|
-
pLibK_GetProcAddress = (LibK_GetProcAddress_t)GetProcAddress(hlibusbK, "LibK_GetProcAddress");
|
|
2518
|
-
if (pLibK_GetProcAddress == NULL) {
|
|
2519
|
-
usbi_err(ctx, "LibK_GetProcAddress() not found in libusbK DLL");
|
|
2520
|
-
goto cleanup_libusbk;
|
|
2521
|
-
}
|
|
2522
|
-
|
|
2523
|
-
// NB: The below for loop works because the sub_api value for WinUSB
|
|
2524
|
-
// is a higher value than that of libusbK and libusb0
|
|
2525
|
-
for (; sub_api < SUB_API_WINUSB; sub_api++) {
|
|
2526
|
-
libusbK_Set(sub_api, AbortPipe, true);
|
|
2527
|
-
libusbK_Set(sub_api, ControlTransfer, true);
|
|
2528
|
-
libusbK_Set(sub_api, FlushPipe, true);
|
|
2529
|
-
libusbK_Set(sub_api, Free, true);
|
|
2530
|
-
libusbK_Set(sub_api, GetAssociatedInterface, true);
|
|
2531
|
-
libusbK_Set(sub_api, Initialize, true);
|
|
2532
|
-
libusbK_Set(sub_api, ReadPipe, true);
|
|
2533
|
-
libusbK_Set(sub_api, ResetPipe, true);
|
|
2534
|
-
libusbK_Set(sub_api, SetCurrentAlternateSetting, true);
|
|
2535
|
-
libusbK_Set(sub_api, SetPipePolicy, true);
|
|
2536
|
-
libusbK_Set(sub_api, WritePipe, true);
|
|
2537
|
-
|
|
2538
|
-
// Optional isochronous support
|
|
2539
|
-
libusbK_Set(sub_api, IsoReadPipe, false);
|
|
2540
|
-
if (WinUSBX[sub_api].IsoReadPipe != NULL)
|
|
2541
|
-
libusbK_Set(sub_api, IsoWritePipe, true);
|
|
2542
|
-
|
|
2543
|
-
// Optional device reset support
|
|
2544
|
-
libusbK_Set(sub_api, ResetDevice, false);
|
|
2545
|
-
|
|
2546
|
-
WinUSBX[sub_api].hDll = hlibusbK;
|
|
2547
|
-
}
|
|
2548
|
-
|
|
2549
|
-
cleanup_libusbk:
|
|
2550
|
-
if (sub_api < SUB_API_WINUSB) {
|
|
2551
|
-
usbi_err(ctx, "failed to initialize libusbK");
|
|
2552
|
-
while (sub_api >= 0) {
|
|
2553
|
-
memset(&WinUSBX[sub_api], 0, sizeof(WinUSBX[sub_api]));
|
|
2554
|
-
sub_api--;
|
|
2555
|
-
}
|
|
2556
|
-
FreeLibrary(hlibusbK);
|
|
2557
|
-
hlibusbK = NULL;
|
|
2558
|
-
}
|
|
2559
|
-
} else {
|
|
2560
|
-
usbi_info(ctx, "libusbK DLL is not available");
|
|
2561
|
-
}
|
|
2562
|
-
|
|
2563
|
-
if ((hWinUSB == NULL) && (hlibusbK == NULL)) {
|
|
2564
|
-
usbi_warn(ctx, "neither WinUSB nor libusbK DLLs were found, "
|
|
2565
|
-
"you will not be able to access devices outside of enumeration");
|
|
2566
|
-
return false;
|
|
2567
|
-
}
|
|
2568
|
-
|
|
2569
|
-
return true;
|
|
2570
|
-
}
|
|
2571
|
-
|
|
2572
|
-
static void winusbx_exit(void)
|
|
2573
|
-
{
|
|
2574
|
-
bool loaded = false;
|
|
2575
|
-
HMODULE hDll;
|
|
2576
|
-
|
|
2577
|
-
hDll = WinUSBX[SUB_API_LIBUSBK].hDll;
|
|
2578
|
-
if (hDll != NULL) {
|
|
2579
|
-
FreeLibrary(hDll);
|
|
2580
|
-
loaded = true;
|
|
2581
|
-
}
|
|
2582
|
-
|
|
2583
|
-
hDll = WinUSBX[SUB_API_WINUSB].hDll;
|
|
2584
|
-
if (hDll != NULL) {
|
|
2585
|
-
FreeLibrary(hDll);
|
|
2586
|
-
loaded = true;
|
|
2587
|
-
}
|
|
2588
|
-
|
|
2589
|
-
// Reset the WinUSBX API structures if something was loaded
|
|
2590
|
-
if (loaded)
|
|
2591
|
-
memset(&WinUSBX, 0, sizeof(WinUSBX));
|
|
2592
|
-
}
|
|
2593
|
-
|
|
2594
|
-
// NB: open and close must ensure that they only handle interface of
|
|
2595
|
-
// the right API type, as these functions can be called wholesale from
|
|
2596
|
-
// composite_open(), with interfaces belonging to different APIs
|
|
2597
|
-
static int winusbx_open(int sub_api, struct libusb_device_handle *dev_handle)
|
|
2598
|
-
{
|
|
2599
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2600
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
2601
|
-
HANDLE file_handle;
|
|
2602
|
-
int i;
|
|
2603
|
-
|
|
2604
|
-
CHECK_WINUSBX_AVAILABLE(sub_api);
|
|
2605
|
-
|
|
2606
|
-
// WinUSB requires a separate handle for each interface
|
|
2607
|
-
for (i = 0; i < USB_MAXINTERFACES; i++) {
|
|
2608
|
-
if ((priv->usb_interface[i].path != NULL)
|
|
2609
|
-
&& (priv->usb_interface[i].apib->id == USB_API_WINUSBX)) {
|
|
2610
|
-
file_handle = windows_open(dev_handle, priv->usb_interface[i].path, GENERIC_READ | GENERIC_WRITE);
|
|
2611
|
-
if (file_handle == INVALID_HANDLE_VALUE) {
|
|
2612
|
-
usbi_err(HANDLE_CTX(dev_handle), "could not open device %s (interface %d): %s", priv->usb_interface[i].path, i, windows_error_str(0));
|
|
2613
|
-
switch (GetLastError()) {
|
|
2614
|
-
case ERROR_FILE_NOT_FOUND: // The device was disconnected
|
|
2615
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
2616
|
-
case ERROR_ACCESS_DENIED:
|
|
2617
|
-
return LIBUSB_ERROR_ACCESS;
|
|
2618
|
-
default:
|
|
2619
|
-
return LIBUSB_ERROR_IO;
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
|
|
2623
|
-
handle_priv->interface_handle[i].dev_handle = file_handle;
|
|
2624
|
-
}
|
|
2625
|
-
}
|
|
2626
|
-
|
|
2627
|
-
return LIBUSB_SUCCESS;
|
|
2628
|
-
}
|
|
2629
|
-
|
|
2630
|
-
static void winusbx_close(int sub_api, struct libusb_device_handle *dev_handle)
|
|
2631
|
-
{
|
|
2632
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
2633
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2634
|
-
HANDLE handle;
|
|
2635
|
-
int i, ai;
|
|
2636
|
-
|
|
2637
|
-
if (sub_api == SUB_API_NOTSET)
|
|
2638
|
-
sub_api = priv->sub_api;
|
|
2639
|
-
|
|
2640
|
-
if (WinUSBX[sub_api].hDll == NULL)
|
|
2641
|
-
return;
|
|
2642
|
-
|
|
2643
|
-
if (priv->apib->id == USB_API_COMPOSITE) {
|
|
2644
|
-
// If this is a composite device, just free and close any WinUSB-like
|
|
2645
|
-
// interfaces that are not part of an associated group
|
|
2646
|
-
// (each is independent and not associated with another).
|
|
2647
|
-
// For associated interface groupings, free interfaces that
|
|
2648
|
-
// are NOT the first within that group (i.e. not bFirstInterface),
|
|
2649
|
-
// then free & close bFirstInterface last.
|
|
2650
|
-
for (i = 0; i < USB_MAXINTERFACES; i++) {
|
|
2651
|
-
if (priv->usb_interface[i].apib->id == USB_API_WINUSBX) {
|
|
2652
|
-
if (priv->usb_interface[i].num_associated_interfaces == 0) {
|
|
2653
|
-
handle = handle_priv->interface_handle[i].api_handle;
|
|
2654
|
-
if (HANDLE_VALID(handle))
|
|
2655
|
-
WinUSBX[sub_api].Free(handle);
|
|
2656
|
-
|
|
2657
|
-
handle = handle_priv->interface_handle[i].dev_handle;
|
|
2658
|
-
if (HANDLE_VALID(handle))
|
|
2659
|
-
CloseHandle(handle);
|
|
2660
|
-
} else {
|
|
2661
|
-
if (i==priv->usb_interface[i].first_associated_interface) {
|
|
2662
|
-
//first free all handles for all *other* associated interfaces
|
|
2663
|
-
for (ai = 1; ai < priv->usb_interface[i].num_associated_interfaces; ai++) {
|
|
2664
|
-
handle = handle_priv->interface_handle[i + ai].api_handle;
|
|
2665
|
-
if (HANDLE_VALID(handle))
|
|
2666
|
-
WinUSBX[sub_api].Free(handle);
|
|
2667
|
-
}
|
|
2668
|
-
|
|
2669
|
-
//free & close bFirstInterface
|
|
2670
|
-
handle = handle_priv->interface_handle[i].api_handle;
|
|
2671
|
-
if (HANDLE_VALID(handle))
|
|
2672
|
-
WinUSBX[sub_api].Free(handle);
|
|
2673
|
-
|
|
2674
|
-
handle = handle_priv->interface_handle[i].dev_handle;
|
|
2675
|
-
if (HANDLE_VALID(handle))
|
|
2676
|
-
CloseHandle(handle);
|
|
2677
|
-
}
|
|
2678
|
-
}
|
|
2679
|
-
}
|
|
2680
|
-
}
|
|
2681
|
-
} else {
|
|
2682
|
-
// If this is a WinUSB device, free all interfaces above interface 0,
|
|
2683
|
-
// then free and close interface 0 last
|
|
2684
|
-
for (i = 1; i < USB_MAXINTERFACES; i++) {
|
|
2685
|
-
handle = handle_priv->interface_handle[i].api_handle;
|
|
2686
|
-
if (HANDLE_VALID(handle))
|
|
2687
|
-
WinUSBX[sub_api].Free(handle);
|
|
2688
|
-
}
|
|
2689
|
-
handle = handle_priv->interface_handle[0].api_handle;
|
|
2690
|
-
if (HANDLE_VALID(handle))
|
|
2691
|
-
WinUSBX[sub_api].Free(handle);
|
|
2692
|
-
|
|
2693
|
-
handle = handle_priv->interface_handle[0].dev_handle;
|
|
2694
|
-
if (HANDLE_VALID(handle))
|
|
2695
|
-
CloseHandle(handle);
|
|
2696
|
-
}
|
|
2697
|
-
}
|
|
2698
|
-
|
|
2699
|
-
static int winusbx_configure_endpoints(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
|
|
2700
|
-
{
|
|
2701
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
2702
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2703
|
-
HANDLE winusb_handle = handle_priv->interface_handle[iface].api_handle;
|
|
2704
|
-
UCHAR policy;
|
|
2705
|
-
ULONG timeout = 0;
|
|
2706
|
-
uint8_t endpoint_address;
|
|
2707
|
-
int i;
|
|
2708
|
-
|
|
2709
|
-
CHECK_WINUSBX_AVAILABLE(sub_api);
|
|
2710
|
-
|
|
2711
|
-
// With handle and endpoints set (in parent), we can setup the default pipe properties
|
|
2712
|
-
// see http://download.microsoft.com/download/D/1/D/D1DD7745-426B-4CC3-A269-ABBBE427C0EF/DVC-T705_DDC08.pptx
|
|
2713
|
-
for (i = -1; i < priv->usb_interface[iface].nb_endpoints; i++) {
|
|
2714
|
-
endpoint_address = (i == -1) ? 0 : priv->usb_interface[iface].endpoint[i];
|
|
2715
|
-
if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
|
|
2716
|
-
PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout))
|
|
2717
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "failed to set PIPE_TRANSFER_TIMEOUT for control endpoint %02X", endpoint_address);
|
|
2718
|
-
|
|
2719
|
-
if ((i == -1) || (sub_api == SUB_API_LIBUSB0))
|
|
2720
|
-
continue; // Other policies don't apply to control endpoint or libusb0
|
|
2721
|
-
|
|
2722
|
-
policy = false;
|
|
2723
|
-
handle_priv->interface_handle[iface].zlp[endpoint_address] = WINUSB_ZLP_UNSET;
|
|
2724
|
-
if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
|
|
2725
|
-
SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy))
|
|
2726
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "failed to disable SHORT_PACKET_TERMINATE for endpoint %02X", endpoint_address);
|
|
2727
|
-
|
|
2728
|
-
if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
|
|
2729
|
-
IGNORE_SHORT_PACKETS, sizeof(UCHAR), &policy))
|
|
2730
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "failed to disable IGNORE_SHORT_PACKETS for endpoint %02X", endpoint_address);
|
|
2731
|
-
|
|
2732
|
-
policy = true;
|
|
2733
|
-
/* ALLOW_PARTIAL_READS must be enabled due to likely libusbK bug. See:
|
|
2734
|
-
https://sourceforge.net/mailarchive/message.php?msg_id=29736015 */
|
|
2735
|
-
if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
|
|
2736
|
-
ALLOW_PARTIAL_READS, sizeof(UCHAR), &policy))
|
|
2737
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "failed to enable ALLOW_PARTIAL_READS for endpoint %02X", endpoint_address);
|
|
2738
|
-
|
|
2739
|
-
if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
|
|
2740
|
-
AUTO_CLEAR_STALL, sizeof(UCHAR), &policy))
|
|
2741
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "failed to enable AUTO_CLEAR_STALL for endpoint %02X", endpoint_address);
|
|
2742
|
-
|
|
2743
|
-
if (sub_api == SUB_API_LIBUSBK) {
|
|
2744
|
-
if (!WinUSBX[sub_api].SetPipePolicy(winusb_handle, endpoint_address,
|
|
2745
|
-
ISO_ALWAYS_START_ASAP, sizeof(UCHAR), &policy))
|
|
2746
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "failed to enable ISO_ALWAYS_START_ASAP for endpoint %02X", endpoint_address);
|
|
2747
|
-
}
|
|
2748
|
-
}
|
|
2749
|
-
|
|
2750
|
-
return LIBUSB_SUCCESS;
|
|
2751
|
-
}
|
|
2752
|
-
|
|
2753
|
-
static int winusbx_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
|
|
2754
|
-
{
|
|
2755
|
-
struct libusb_context *ctx = HANDLE_CTX(dev_handle);
|
|
2756
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
2757
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2758
|
-
bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE);
|
|
2759
|
-
bool is_associated_interface = (priv->usb_interface[iface].num_associated_interfaces != 0);
|
|
2760
|
-
HDEVINFO dev_info;
|
|
2761
|
-
char *dev_interface_path = NULL;
|
|
2762
|
-
char *dev_interface_path_guid_start;
|
|
2763
|
-
char filter_path[] = "\\\\.\\libusb0-0000";
|
|
2764
|
-
bool found_filter = false;
|
|
2765
|
-
HANDLE file_handle, winusb_handle;
|
|
2766
|
-
DWORD err, _index;
|
|
2767
|
-
int r;
|
|
2768
|
-
uint8_t initialized_iface;
|
|
2769
|
-
|
|
2770
|
-
CHECK_WINUSBX_AVAILABLE(sub_api);
|
|
2771
|
-
|
|
2772
|
-
// If the device is composite, but using the default Windows composite parent driver (usbccgp)
|
|
2773
|
-
// or if it's the first WinUSB-like interface, we get a handle through Initialize().
|
|
2774
|
-
// If it's an associated interface, and is the first one (iface==bFirstInterface), we also
|
|
2775
|
-
// want to get the handle through Initialize(). If it's an associated interface, and NOT
|
|
2776
|
-
// the first one, we want to direct control to the 'else' where the handle will be obtained
|
|
2777
|
-
// via GetAssociatedInterface().
|
|
2778
|
-
if (((is_using_usbccgp) || (iface == 0)) &&
|
|
2779
|
-
(!is_associated_interface || (iface==priv->usb_interface[iface].first_associated_interface))) {
|
|
2780
|
-
// composite device (independent interfaces) or interface 0
|
|
2781
|
-
file_handle = handle_priv->interface_handle[iface].dev_handle;
|
|
2782
|
-
if (!HANDLE_VALID(file_handle))
|
|
2783
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
2784
|
-
|
|
2785
|
-
if (!WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
|
|
2786
|
-
handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
|
|
2787
|
-
err = GetLastError();
|
|
2788
|
-
switch (err) {
|
|
2789
|
-
case ERROR_BAD_COMMAND:
|
|
2790
|
-
// The device was disconnected
|
|
2791
|
-
usbi_err(ctx, "could not access interface %u: %s", iface, windows_error_str(0));
|
|
2792
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
2793
|
-
default:
|
|
2794
|
-
// it may be that we're using the libusb0 filter driver.
|
|
2795
|
-
// TODO: can we move this whole business into the K/0 DLL?
|
|
2796
|
-
r = LIBUSB_SUCCESS;
|
|
2797
|
-
for (_index = 0; ; _index++) {
|
|
2798
|
-
safe_free(dev_interface_path);
|
|
2799
|
-
|
|
2800
|
-
if (found_filter)
|
|
2801
|
-
break;
|
|
2802
|
-
|
|
2803
|
-
r = get_interface_details_filter(ctx, &dev_info, _index, filter_path, &dev_interface_path);
|
|
2804
|
-
if ((r != LIBUSB_SUCCESS) || (dev_interface_path == NULL))
|
|
2805
|
-
break;
|
|
2806
|
-
|
|
2807
|
-
// ignore GUID part
|
|
2808
|
-
dev_interface_path_guid_start = strchr(dev_interface_path, '{');
|
|
2809
|
-
if (dev_interface_path_guid_start == NULL)
|
|
2810
|
-
continue;
|
|
2811
|
-
*dev_interface_path_guid_start = '\0';
|
|
2812
|
-
|
|
2813
|
-
if (strncmp(dev_interface_path, priv->usb_interface[iface].path, strlen(dev_interface_path)) == 0) {
|
|
2814
|
-
file_handle = windows_open(dev_handle, filter_path, GENERIC_READ | GENERIC_WRITE);
|
|
2815
|
-
if (file_handle != INVALID_HANDLE_VALUE) {
|
|
2816
|
-
if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
|
|
2817
|
-
// Replace the existing file handle with the working one
|
|
2818
|
-
CloseHandle(handle_priv->interface_handle[iface].dev_handle);
|
|
2819
|
-
handle_priv->interface_handle[iface].dev_handle = file_handle;
|
|
2820
|
-
found_filter = true;
|
|
2821
|
-
} else {
|
|
2822
|
-
usbi_err(ctx, "could not initialize filter driver for %s", filter_path);
|
|
2823
|
-
CloseHandle(file_handle);
|
|
2824
|
-
}
|
|
2825
|
-
} else {
|
|
2826
|
-
usbi_err(ctx, "could not open device %s: %s", filter_path, windows_error_str(0));
|
|
2827
|
-
}
|
|
2828
|
-
}
|
|
2829
|
-
}
|
|
2830
|
-
if (r != LIBUSB_SUCCESS)
|
|
2831
|
-
return r;
|
|
2832
|
-
if (!found_filter) {
|
|
2833
|
-
usbi_err(ctx, "could not access interface %u: %s", iface, windows_error_str(err));
|
|
2834
|
-
return LIBUSB_ERROR_ACCESS;
|
|
2835
|
-
}
|
|
2836
|
-
}
|
|
2837
|
-
}
|
|
2838
|
-
handle_priv->interface_handle[iface].api_handle = winusb_handle;
|
|
2839
|
-
} else {
|
|
2840
|
-
if (is_associated_interface) {
|
|
2841
|
-
initialized_iface = priv->usb_interface[iface].first_associated_interface;
|
|
2842
|
-
if (iface <= initialized_iface) {
|
|
2843
|
-
usbi_err(ctx, "invalid associated index. iface=%u, initialized iface=%u", iface, initialized_iface);
|
|
2844
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
2845
|
-
}
|
|
2846
|
-
} else {
|
|
2847
|
-
initialized_iface = 0;
|
|
2848
|
-
}
|
|
2849
|
-
|
|
2850
|
-
// For all other interfaces, use GetAssociatedInterface()
|
|
2851
|
-
winusb_handle = handle_priv->interface_handle[initialized_iface].api_handle;
|
|
2852
|
-
// It is a requirement for multiple interface devices on Windows that, to you
|
|
2853
|
-
// must first claim the first interface before you claim the others
|
|
2854
|
-
if (!HANDLE_VALID(winusb_handle)) {
|
|
2855
|
-
file_handle = handle_priv->interface_handle[initialized_iface].dev_handle;
|
|
2856
|
-
if (WinUSBX[sub_api].Initialize(file_handle, &winusb_handle)) {
|
|
2857
|
-
handle_priv->interface_handle[initialized_iface].api_handle = winusb_handle;
|
|
2858
|
-
usbi_warn(ctx, "auto-claimed interface %u (required to claim %u with WinUSB)", initialized_iface, iface);
|
|
2859
|
-
} else {
|
|
2860
|
-
usbi_warn(ctx, "failed to auto-claim interface %u (required to claim %u with WinUSB): %s",
|
|
2861
|
-
initialized_iface, iface, windows_error_str(0));
|
|
2862
|
-
return LIBUSB_ERROR_ACCESS;
|
|
2863
|
-
}
|
|
2864
|
-
}
|
|
2865
|
-
if (!WinUSBX[sub_api].GetAssociatedInterface(winusb_handle, (UCHAR)(iface - 1 - initialized_iface),
|
|
2866
|
-
&handle_priv->interface_handle[iface].api_handle)) {
|
|
2867
|
-
handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
|
|
2868
|
-
switch (GetLastError()) {
|
|
2869
|
-
case ERROR_NO_MORE_ITEMS: // invalid iface
|
|
2870
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
2871
|
-
case ERROR_BAD_COMMAND: // The device was disconnected
|
|
2872
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
2873
|
-
case ERROR_ALREADY_EXISTS: // already claimed
|
|
2874
|
-
return LIBUSB_ERROR_BUSY;
|
|
2875
|
-
default:
|
|
2876
|
-
usbi_err(ctx, "could not claim interface %u: %s", iface, windows_error_str(0));
|
|
2877
|
-
return LIBUSB_ERROR_ACCESS;
|
|
2878
|
-
}
|
|
2879
|
-
}
|
|
2880
|
-
handle_priv->interface_handle[iface].dev_handle = handle_priv->interface_handle[initialized_iface].dev_handle;
|
|
2881
|
-
}
|
|
2882
|
-
usbi_dbg(ctx, "claimed interface %u", iface);
|
|
2883
|
-
handle_priv->active_interface = iface;
|
|
2884
|
-
|
|
2885
|
-
return LIBUSB_SUCCESS;
|
|
2886
|
-
}
|
|
2887
|
-
|
|
2888
|
-
static int winusbx_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
|
|
2889
|
-
{
|
|
2890
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
2891
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2892
|
-
HANDLE winusb_handle;
|
|
2893
|
-
|
|
2894
|
-
CHECK_WINUSBX_AVAILABLE(sub_api);
|
|
2895
|
-
|
|
2896
|
-
winusb_handle = handle_priv->interface_handle[iface].api_handle;
|
|
2897
|
-
if (!HANDLE_VALID(winusb_handle))
|
|
2898
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
2899
|
-
|
|
2900
|
-
WinUSBX[sub_api].Free(winusb_handle);
|
|
2901
|
-
handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
|
|
2902
|
-
|
|
2903
|
-
return LIBUSB_SUCCESS;
|
|
2904
|
-
}
|
|
2905
|
-
|
|
2906
|
-
/*
|
|
2907
|
-
* Return the first valid interface (of the same API type), for control transfers
|
|
2908
|
-
*/
|
|
2909
|
-
static int get_valid_interface(struct libusb_device_handle *dev_handle, int api_id)
|
|
2910
|
-
{
|
|
2911
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
2912
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2913
|
-
int i;
|
|
2914
|
-
|
|
2915
|
-
if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) {
|
|
2916
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "unsupported API ID");
|
|
2917
|
-
return -1;
|
|
2918
|
-
}
|
|
2919
|
-
|
|
2920
|
-
for (i = 0; i < USB_MAXINTERFACES; i++) {
|
|
2921
|
-
if (HANDLE_VALID(handle_priv->interface_handle[i].dev_handle)
|
|
2922
|
-
&& HANDLE_VALID(handle_priv->interface_handle[i].api_handle)
|
|
2923
|
-
&& (priv->usb_interface[i].apib->id == api_id))
|
|
2924
|
-
return i;
|
|
2925
|
-
}
|
|
2926
|
-
|
|
2927
|
-
return -1;
|
|
2928
|
-
}
|
|
2929
|
-
|
|
2930
|
-
/*
|
|
2931
|
-
* Check a specific interface is valid (of the same API type), for control transfers
|
|
2932
|
-
*/
|
|
2933
|
-
static int check_valid_interface(struct libusb_device_handle *dev_handle, unsigned short interface, int api_id)
|
|
2934
|
-
{
|
|
2935
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
2936
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
2937
|
-
|
|
2938
|
-
if (interface >= USB_MAXINTERFACES)
|
|
2939
|
-
return -1;
|
|
2940
|
-
|
|
2941
|
-
if ((api_id < USB_API_WINUSBX) || (api_id > USB_API_HID)) {
|
|
2942
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "unsupported API ID");
|
|
2943
|
-
return -1;
|
|
2944
|
-
}
|
|
2945
|
-
|
|
2946
|
-
// try the requested interface
|
|
2947
|
-
if (HANDLE_VALID(handle_priv->interface_handle[interface].dev_handle)
|
|
2948
|
-
&& HANDLE_VALID(handle_priv->interface_handle[interface].api_handle)
|
|
2949
|
-
&& (priv->usb_interface[interface].apib->id == api_id))
|
|
2950
|
-
return interface;
|
|
2951
|
-
|
|
2952
|
-
return -1;
|
|
2953
|
-
}
|
|
2954
|
-
|
|
2955
|
-
/*
|
|
2956
|
-
* Lookup interface by endpoint address. -1 if not found
|
|
2957
|
-
*/
|
|
2958
|
-
static int interface_by_endpoint(struct winusb_device_priv *priv,
|
|
2959
|
-
struct winusb_device_handle_priv *handle_priv, uint8_t endpoint_address)
|
|
2960
|
-
{
|
|
2961
|
-
int i, j;
|
|
2962
|
-
|
|
2963
|
-
for (i = 0; i < USB_MAXINTERFACES; i++) {
|
|
2964
|
-
if (!HANDLE_VALID(handle_priv->interface_handle[i].api_handle))
|
|
2965
|
-
continue;
|
|
2966
|
-
if (priv->usb_interface[i].endpoint == NULL)
|
|
2967
|
-
continue;
|
|
2968
|
-
for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) {
|
|
2969
|
-
if (priv->usb_interface[i].endpoint[j] == endpoint_address)
|
|
2970
|
-
return i;
|
|
2971
|
-
}
|
|
2972
|
-
}
|
|
2973
|
-
|
|
2974
|
-
return -1;
|
|
2975
|
-
}
|
|
2976
|
-
|
|
2977
|
-
static int winusbx_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
|
|
2978
|
-
{
|
|
2979
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
2980
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
2981
|
-
struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
|
|
2982
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
|
|
2983
|
-
PWINUSB_SETUP_PACKET setup = (PWINUSB_SETUP_PACKET)transfer->buffer;
|
|
2984
|
-
ULONG size, transferred;
|
|
2985
|
-
HANDLE winusb_handle;
|
|
2986
|
-
OVERLAPPED *overlapped;
|
|
2987
|
-
int current_interface;
|
|
2988
|
-
|
|
2989
|
-
CHECK_WINUSBX_AVAILABLE(sub_api);
|
|
2990
|
-
|
|
2991
|
-
size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
|
|
2992
|
-
|
|
2993
|
-
// Windows places upper limits on the control transfer size
|
|
2994
|
-
// See: https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-bandwidth-allocation#maximum-transfer-size
|
|
2995
|
-
if (size > MAX_CTRL_BUFFER_LENGTH)
|
|
2996
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
2997
|
-
|
|
2998
|
-
if ((setup->RequestType & 0x1F) == LIBUSB_RECIPIENT_INTERFACE)
|
|
2999
|
-
current_interface = check_valid_interface(transfer->dev_handle, setup->Index & 0xff, USB_API_WINUSBX);
|
|
3000
|
-
else
|
|
3001
|
-
current_interface = get_valid_interface(transfer->dev_handle, USB_API_WINUSBX);
|
|
3002
|
-
if (current_interface < 0) {
|
|
3003
|
-
if (auto_claim(transfer, ¤t_interface, USB_API_WINUSBX) != LIBUSB_SUCCESS)
|
|
3004
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
3005
|
-
}
|
|
3006
|
-
|
|
3007
|
-
usbi_dbg(ITRANSFER_CTX(itransfer), "will use interface %d", current_interface);
|
|
3008
|
-
|
|
3009
|
-
transfer_priv->interface_number = (uint8_t)current_interface;
|
|
3010
|
-
winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
|
|
3011
|
-
set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle);
|
|
3012
|
-
overlapped = get_transfer_priv_overlapped(itransfer);
|
|
3013
|
-
|
|
3014
|
-
// Sending of set configuration control requests from WinUSB creates issues, except when using libusb0.sys
|
|
3015
|
-
if (sub_api != SUB_API_LIBUSB0
|
|
3016
|
-
&& (LIBUSB_REQ_TYPE(setup->RequestType) == LIBUSB_REQUEST_TYPE_STANDARD)
|
|
3017
|
-
&& (setup->Request == LIBUSB_REQUEST_SET_CONFIGURATION)) {
|
|
3018
|
-
if (setup->Value != priv->active_config) {
|
|
3019
|
-
usbi_warn(TRANSFER_CTX(transfer), "cannot set configuration other than the default one");
|
|
3020
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
3021
|
-
}
|
|
3022
|
-
windows_force_sync_completion(itransfer, 0);
|
|
3023
|
-
} else {
|
|
3024
|
-
if (!WinUSBX[sub_api].ControlTransfer(winusb_handle, *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, &transferred, overlapped)) {
|
|
3025
|
-
if (GetLastError() != ERROR_IO_PENDING) {
|
|
3026
|
-
usbi_warn(TRANSFER_CTX(transfer), "ControlTransfer failed: %s", windows_error_str(0));
|
|
3027
|
-
return LIBUSB_ERROR_IO;
|
|
3028
|
-
}
|
|
3029
|
-
} else {
|
|
3030
|
-
windows_force_sync_completion(itransfer, transferred);
|
|
3031
|
-
}
|
|
3032
|
-
}
|
|
3033
|
-
|
|
3034
|
-
return LIBUSB_SUCCESS;
|
|
3035
|
-
}
|
|
3036
|
-
|
|
3037
|
-
static int winusbx_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
|
|
3038
|
-
{
|
|
3039
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
3040
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
3041
|
-
HANDLE winusb_handle;
|
|
3042
|
-
|
|
3043
|
-
CHECK_WINUSBX_AVAILABLE(sub_api);
|
|
3044
|
-
|
|
3045
|
-
winusb_handle = handle_priv->interface_handle[iface].api_handle;
|
|
3046
|
-
if (!HANDLE_VALID(winusb_handle)) {
|
|
3047
|
-
usbi_err(HANDLE_CTX(dev_handle), "interface must be claimed first");
|
|
3048
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
3049
|
-
}
|
|
3050
|
-
|
|
3051
|
-
if (!WinUSBX[sub_api].SetCurrentAlternateSetting(winusb_handle, altsetting)) {
|
|
3052
|
-
usbi_err(HANDLE_CTX(dev_handle), "SetCurrentAlternateSetting failed: %s", windows_error_str(0));
|
|
3053
|
-
return LIBUSB_ERROR_IO;
|
|
3054
|
-
}
|
|
3055
|
-
|
|
3056
|
-
return LIBUSB_SUCCESS;
|
|
3057
|
-
}
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
static void WINAPI winusbx_native_iso_transfer_continue_stream_callback(struct libusb_transfer *transfer)
|
|
3061
|
-
{
|
|
3062
|
-
// If this callback is invoked, this means that we attempted to set ContinueStream
|
|
3063
|
-
// to TRUE when calling Read/WriteIsochPipeAsap in winusbx_submit_iso_transfer().
|
|
3064
|
-
// The role of this callback is to fallback to ContinueStream = FALSE if the transfer
|
|
3065
|
-
// did not succeed.
|
|
3066
|
-
|
|
3067
|
-
struct winusb_transfer_priv *transfer_priv =
|
|
3068
|
-
get_winusb_transfer_priv(LIBUSB_TRANSFER_TO_USBI_TRANSFER(transfer));
|
|
3069
|
-
bool fallback = (transfer->status != LIBUSB_TRANSFER_COMPLETED);
|
|
3070
|
-
int idx;
|
|
3071
|
-
|
|
3072
|
-
// Restore the user callback
|
|
3073
|
-
transfer->callback = transfer_priv->iso_user_callback;
|
|
3074
|
-
|
|
3075
|
-
for (idx = 0; idx < transfer->num_iso_packets && !fallback; idx++) {
|
|
3076
|
-
if (transfer->iso_packet_desc[idx].status != LIBUSB_TRANSFER_COMPLETED)
|
|
3077
|
-
fallback = true;
|
|
3078
|
-
}
|
|
3079
|
-
|
|
3080
|
-
if (!fallback) {
|
|
3081
|
-
// If the transfer was successful, we restore the user callback and call it.
|
|
3082
|
-
if (transfer->callback)
|
|
3083
|
-
transfer->callback(transfer);
|
|
3084
|
-
} else {
|
|
3085
|
-
// If the transfer wasn't successful we reschedule the transfer while forcing it
|
|
3086
|
-
// not to continue the stream. This might results in a 5-ms delay.
|
|
3087
|
-
transfer_priv->iso_break_stream = TRUE;
|
|
3088
|
-
libusb_submit_transfer(transfer);
|
|
3089
|
-
}
|
|
3090
|
-
}
|
|
3091
|
-
static int winusbx_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer)
|
|
3092
|
-
{
|
|
3093
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
3094
|
-
struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
|
|
3095
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
|
|
3096
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
3097
|
-
HANDLE winusb_handle;
|
|
3098
|
-
OVERLAPPED *overlapped;
|
|
3099
|
-
BOOL ret;
|
|
3100
|
-
int current_interface;
|
|
3101
|
-
|
|
3102
|
-
CHECK_WINUSBX_AVAILABLE(sub_api);
|
|
3103
|
-
|
|
3104
|
-
current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
|
|
3105
|
-
if (current_interface < 0) {
|
|
3106
|
-
usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
|
|
3107
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
3108
|
-
}
|
|
3109
|
-
|
|
3110
|
-
usbi_dbg(TRANSFER_CTX(transfer), "matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
|
|
3111
|
-
|
|
3112
|
-
transfer_priv->interface_number = (uint8_t)current_interface;
|
|
3113
|
-
winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
|
|
3114
|
-
set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle);
|
|
3115
|
-
overlapped = get_transfer_priv_overlapped(itransfer);
|
|
3116
|
-
|
|
3117
|
-
if ((sub_api == SUB_API_LIBUSBK) || (sub_api == SUB_API_LIBUSB0)) {
|
|
3118
|
-
int i;
|
|
3119
|
-
UINT offset;
|
|
3120
|
-
size_t iso_ctx_size;
|
|
3121
|
-
PKISO_CONTEXT iso_context;
|
|
3122
|
-
|
|
3123
|
-
if (WinUSBX[sub_api].IsoReadPipe == NULL) {
|
|
3124
|
-
usbi_warn(TRANSFER_CTX(transfer), "libusbK DLL does not support isoch transfers");
|
|
3125
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
3126
|
-
}
|
|
3127
|
-
|
|
3128
|
-
iso_ctx_size = sizeof(KISO_CONTEXT) + (transfer->num_iso_packets * sizeof(KISO_PACKET));
|
|
3129
|
-
transfer_priv->iso_context = iso_context = calloc(1, iso_ctx_size);
|
|
3130
|
-
if (transfer_priv->iso_context == NULL)
|
|
3131
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
3132
|
-
|
|
3133
|
-
// start ASAP
|
|
3134
|
-
iso_context->StartFrame = 0;
|
|
3135
|
-
iso_context->NumberOfPackets = (SHORT)transfer->num_iso_packets;
|
|
3136
|
-
|
|
3137
|
-
// convert the transfer packet lengths to iso_packet offsets
|
|
3138
|
-
offset = 0;
|
|
3139
|
-
for (i = 0; i < transfer->num_iso_packets; i++) {
|
|
3140
|
-
iso_context->IsoPackets[i].offset = offset;
|
|
3141
|
-
offset += transfer->iso_packet_desc[i].length;
|
|
3142
|
-
}
|
|
3143
|
-
|
|
3144
|
-
if (IS_XFERIN(transfer)) {
|
|
3145
|
-
usbi_dbg(TRANSFER_CTX(transfer), "reading %d iso packets", transfer->num_iso_packets);
|
|
3146
|
-
ret = WinUSBX[sub_api].IsoReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context);
|
|
3147
|
-
} else {
|
|
3148
|
-
usbi_dbg(TRANSFER_CTX(transfer), "writing %d iso packets", transfer->num_iso_packets);
|
|
3149
|
-
ret = WinUSBX[sub_api].IsoWritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, overlapped, iso_context);
|
|
3150
|
-
}
|
|
3151
|
-
|
|
3152
|
-
if (!ret && GetLastError() != ERROR_IO_PENDING) {
|
|
3153
|
-
usbi_err(TRANSFER_CTX(transfer), "IsoReadPipe/IsoWritePipe failed: %s", windows_error_str(0));
|
|
3154
|
-
return LIBUSB_ERROR_IO;
|
|
3155
|
-
}
|
|
3156
|
-
|
|
3157
|
-
return LIBUSB_SUCCESS;
|
|
3158
|
-
} else if (sub_api == SUB_API_WINUSB) {
|
|
3159
|
-
WINUSB_PIPE_INFORMATION_EX pipe_info_ex = { 0 };
|
|
3160
|
-
WINUSB_ISOCH_BUFFER_HANDLE buffer_handle;
|
|
3161
|
-
ULONG iso_transfer_size_multiple;
|
|
3162
|
-
int out_transfer_length = 0;
|
|
3163
|
-
int idx;
|
|
3164
|
-
|
|
3165
|
-
// Depending on the version of Microsoft WinUSB, isochronous transfers may not be supported.
|
|
3166
|
-
if (WinUSBX[sub_api].ReadIsochPipeAsap == NULL) {
|
|
3167
|
-
usbi_warn(TRANSFER_CTX(transfer), "WinUSB DLL does not support isoch transfers");
|
|
3168
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
3169
|
-
}
|
|
3170
|
-
|
|
3171
|
-
if (sizeof(struct libusb_iso_packet_descriptor) != sizeof(USBD_ISO_PACKET_DESCRIPTOR)) {
|
|
3172
|
-
usbi_err(TRANSFER_CTX(transfer), "size of WinUsb and libusb isoch packet descriptors don't match");
|
|
3173
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
3174
|
-
}
|
|
3175
|
-
|
|
3176
|
-
// Query the pipe extended information to find the pipe index corresponding to the endpoint.
|
|
3177
|
-
for (idx = 0; idx < priv->usb_interface[current_interface].nb_endpoints; ++idx) {
|
|
3178
|
-
ret = WinUSBX[sub_api].QueryPipeEx(winusb_handle, (UINT8)priv->usb_interface[current_interface].current_altsetting, (UCHAR)idx, &pipe_info_ex);
|
|
3179
|
-
if (!ret) {
|
|
3180
|
-
usbi_err(TRANSFER_CTX(transfer), "couldn't query interface settings for USB pipe with index %d. Error: %s", idx, windows_error_str(0));
|
|
3181
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
3182
|
-
}
|
|
3183
|
-
|
|
3184
|
-
if (pipe_info_ex.PipeId == transfer->endpoint && pipe_info_ex.PipeType == UsbdPipeTypeIsochronous)
|
|
3185
|
-
break;
|
|
3186
|
-
}
|
|
3187
|
-
|
|
3188
|
-
// Make sure we found the index.
|
|
3189
|
-
if (idx == priv->usb_interface[current_interface].nb_endpoints) {
|
|
3190
|
-
usbi_err(TRANSFER_CTX(transfer), "couldn't find isoch endpoint 0x%02x", transfer->endpoint);
|
|
3191
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
3192
|
-
}
|
|
3193
|
-
|
|
3194
|
-
if (IS_XFERIN(transfer)) {
|
|
3195
|
-
int interval = pipe_info_ex.Interval;
|
|
3196
|
-
|
|
3197
|
-
// For high-speed and SuperSpeed device, the interval is 2**(bInterval-1).
|
|
3198
|
-
if (transfer->dev_handle->dev->speed >= LIBUSB_SPEED_HIGH)
|
|
3199
|
-
interval = (1 << (pipe_info_ex.Interval - 1));
|
|
3200
|
-
|
|
3201
|
-
// WinUSB only supports isoch transfers spanning a full USB frames. Later, we might be smarter about this
|
|
3202
|
-
// and allocate a temporary buffer. However, this is harder than it seems as its destruction would depend on overlapped
|
|
3203
|
-
// IO...
|
|
3204
|
-
if (transfer->dev_handle->dev->speed >= LIBUSB_SPEED_HIGH) // Microframes (125us)
|
|
3205
|
-
iso_transfer_size_multiple = (pipe_info_ex.MaximumBytesPerInterval * 8) / interval;
|
|
3206
|
-
else // Normal Frames (1ms)
|
|
3207
|
-
iso_transfer_size_multiple = pipe_info_ex.MaximumBytesPerInterval / interval;
|
|
3208
|
-
|
|
3209
|
-
if (transfer->length % iso_transfer_size_multiple != 0) {
|
|
3210
|
-
usbi_err(TRANSFER_CTX(transfer), "length of isoch buffer must be a multiple of the MaximumBytesPerInterval * 8 / Interval");
|
|
3211
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3212
|
-
}
|
|
3213
|
-
} else {
|
|
3214
|
-
// If this is an OUT transfer, we make sure the isoch packets are contiguous as this isn't supported otherwise.
|
|
3215
|
-
bool size_should_be_zero = false;
|
|
3216
|
-
|
|
3217
|
-
for (idx = 0; idx < transfer->num_iso_packets; ++idx) {
|
|
3218
|
-
if ((size_should_be_zero && transfer->iso_packet_desc[idx].length != 0) ||
|
|
3219
|
-
(transfer->iso_packet_desc[idx].length != pipe_info_ex.MaximumBytesPerInterval && idx + 1 < transfer->num_iso_packets && transfer->iso_packet_desc[idx + 1].length > 0)) {
|
|
3220
|
-
usbi_err(TRANSFER_CTX(transfer), "isoch packets for OUT transfer with WinUSB must be contiguous in memory");
|
|
3221
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3222
|
-
}
|
|
3223
|
-
|
|
3224
|
-
size_should_be_zero = (transfer->iso_packet_desc[idx].length == 0);
|
|
3225
|
-
out_transfer_length += transfer->iso_packet_desc[idx].length;
|
|
3226
|
-
}
|
|
3227
|
-
}
|
|
3228
|
-
|
|
3229
|
-
if (transfer_priv->isoch_buffer_handle != NULL) {
|
|
3230
|
-
if (WinUSBX[sub_api].UnregisterIsochBuffer(transfer_priv->isoch_buffer_handle)) {
|
|
3231
|
-
transfer_priv->isoch_buffer_handle = NULL;
|
|
3232
|
-
} else {
|
|
3233
|
-
usbi_err(TRANSFER_CTX(transfer), "failed to unregister WinUSB isoch buffer: %s", windows_error_str(0));
|
|
3234
|
-
return LIBUSB_ERROR_OTHER;
|
|
3235
|
-
}
|
|
3236
|
-
}
|
|
3237
|
-
|
|
3238
|
-
// Register the isoch buffer to the operating system.
|
|
3239
|
-
ret = WinUSBX[sub_api].RegisterIsochBuffer(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, &buffer_handle);
|
|
3240
|
-
if (!ret) {
|
|
3241
|
-
usbi_err(TRANSFER_CTX(transfer), "failed to register WinUSB isoch buffer: %s", windows_error_str(0));
|
|
3242
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
3243
|
-
}
|
|
3244
|
-
|
|
3245
|
-
// Important note: the WinUSB_Read/WriteIsochPipeAsap API requires a ContinueStream parameter that tells whether the isochronous
|
|
3246
|
-
// stream must be continued or if the WinUSB driver can schedule the transfer at its convenience. Profiling subsequent transfers
|
|
3247
|
-
// with ContinueStream = FALSE showed that 5 frames, i.e. about 5 milliseconds, were left empty between each transfer. This
|
|
3248
|
-
// is critical as this greatly diminish the achievable isochronous bandwidth. We solved the problem using the following strategy:
|
|
3249
|
-
// - Transfers are first scheduled with ContinueStream = TRUE and with winusbx_iso_transfer_continue_stream_callback as user callback.
|
|
3250
|
-
// - If the transfer succeeds, winusbx_iso_transfer_continue_stream_callback restore the user callback and calls its.
|
|
3251
|
-
// - If the transfer fails, winusbx_iso_transfer_continue_stream_callback reschedule the transfer and force ContinueStream = FALSE.
|
|
3252
|
-
if (!transfer_priv->iso_break_stream) {
|
|
3253
|
-
transfer_priv->iso_user_callback = transfer->callback;
|
|
3254
|
-
transfer->callback = winusbx_native_iso_transfer_continue_stream_callback;
|
|
3255
|
-
}
|
|
3256
|
-
|
|
3257
|
-
// Initiate the transfers.
|
|
3258
|
-
if (IS_XFERIN(transfer))
|
|
3259
|
-
ret = WinUSBX[sub_api].ReadIsochPipeAsap(buffer_handle, 0, transfer->length, !transfer_priv->iso_break_stream, transfer->num_iso_packets, (PUSBD_ISO_PACKET_DESCRIPTOR)transfer->iso_packet_desc, overlapped);
|
|
3260
|
-
else
|
|
3261
|
-
ret = WinUSBX[sub_api].WriteIsochPipeAsap(buffer_handle, 0, out_transfer_length, !transfer_priv->iso_break_stream, overlapped);
|
|
3262
|
-
|
|
3263
|
-
if (!ret && GetLastError() != ERROR_IO_PENDING) {
|
|
3264
|
-
usbi_err(TRANSFER_CTX(transfer), "ReadIsochPipeAsap/WriteIsochPipeAsap failed: %s", windows_error_str(0));
|
|
3265
|
-
if (!WinUSBX[sub_api].UnregisterIsochBuffer(buffer_handle))
|
|
3266
|
-
usbi_warn(TRANSFER_CTX(transfer), "failed to unregister WinUSB isoch buffer: %s", windows_error_str(0));
|
|
3267
|
-
return LIBUSB_ERROR_IO;
|
|
3268
|
-
}
|
|
3269
|
-
|
|
3270
|
-
// Restore the ContinueStream parameter to TRUE.
|
|
3271
|
-
transfer_priv->iso_break_stream = FALSE;
|
|
3272
|
-
|
|
3273
|
-
transfer_priv->isoch_buffer_handle = buffer_handle;
|
|
3274
|
-
|
|
3275
|
-
return LIBUSB_SUCCESS;
|
|
3276
|
-
} else {
|
|
3277
|
-
PRINT_UNSUPPORTED_API(winusbx_submit_iso_transfer);
|
|
3278
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
3279
|
-
}
|
|
3280
|
-
}
|
|
3281
|
-
|
|
3282
|
-
static int winusbx_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer)
|
|
3283
|
-
{
|
|
3284
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
3285
|
-
struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
|
|
3286
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
|
|
3287
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
3288
|
-
HANDLE winusb_handle;
|
|
3289
|
-
OVERLAPPED *overlapped;
|
|
3290
|
-
BOOL ret;
|
|
3291
|
-
int current_interface;
|
|
3292
|
-
|
|
3293
|
-
CHECK_WINUSBX_AVAILABLE(sub_api);
|
|
3294
|
-
|
|
3295
|
-
current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
|
|
3296
|
-
if (current_interface < 0) {
|
|
3297
|
-
usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
|
|
3298
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
3299
|
-
}
|
|
3300
|
-
|
|
3301
|
-
usbi_dbg(TRANSFER_CTX(transfer), "matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
|
|
3302
|
-
|
|
3303
|
-
transfer_priv->interface_number = (uint8_t)current_interface;
|
|
3304
|
-
winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
|
|
3305
|
-
set_transfer_priv_handle(itransfer, handle_priv->interface_handle[current_interface].dev_handle);
|
|
3306
|
-
overlapped = get_transfer_priv_overlapped(itransfer);
|
|
3307
|
-
|
|
3308
|
-
if (IS_XFERIN(transfer)) {
|
|
3309
|
-
usbi_dbg(TRANSFER_CTX(transfer), "reading %d bytes", transfer->length);
|
|
3310
|
-
ret = WinUSBX[sub_api].ReadPipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped);
|
|
3311
|
-
} else {
|
|
3312
|
-
// Set SHORT_PACKET_TERMINATE if ZLP requested.
|
|
3313
|
-
// Changing this can be a problem with packets in flight, so only allow on the first transfer.
|
|
3314
|
-
UCHAR policy = (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET) != 0;
|
|
3315
|
-
uint8_t* current_zlp = &handle_priv->interface_handle[current_interface].zlp[transfer->endpoint];
|
|
3316
|
-
if (*current_zlp == WINUSB_ZLP_UNSET) {
|
|
3317
|
-
if (policy &&
|
|
3318
|
-
!WinUSBX[sub_api].SetPipePolicy(winusb_handle, transfer->endpoint,
|
|
3319
|
-
SHORT_PACKET_TERMINATE, sizeof(UCHAR), &policy)) {
|
|
3320
|
-
usbi_err(TRANSFER_CTX(transfer), "failed to set SHORT_PACKET_TERMINATE for endpoint %02X", transfer->endpoint);
|
|
3321
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
3322
|
-
}
|
|
3323
|
-
*current_zlp = policy ? WINUSB_ZLP_ON : WINUSB_ZLP_OFF;
|
|
3324
|
-
} else if (policy != (*current_zlp == WINUSB_ZLP_ON)) {
|
|
3325
|
-
usbi_err(TRANSFER_CTX(transfer), "cannot change ZERO_PACKET for endpoint %02X on Windows", transfer->endpoint);
|
|
3326
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
3327
|
-
}
|
|
3328
|
-
|
|
3329
|
-
usbi_dbg(TRANSFER_CTX(transfer), "writing %d bytes", transfer->length);
|
|
3330
|
-
ret = WinUSBX[sub_api].WritePipe(winusb_handle, transfer->endpoint, transfer->buffer, transfer->length, NULL, overlapped);
|
|
3331
|
-
}
|
|
3332
|
-
|
|
3333
|
-
if (!ret && GetLastError() != ERROR_IO_PENDING) {
|
|
3334
|
-
usbi_err(TRANSFER_CTX(transfer), "ReadPipe/WritePipe failed: %s", windows_error_str(0));
|
|
3335
|
-
return LIBUSB_ERROR_IO;
|
|
3336
|
-
}
|
|
3337
|
-
|
|
3338
|
-
return LIBUSB_SUCCESS;
|
|
3339
|
-
}
|
|
3340
|
-
|
|
3341
|
-
static int winusbx_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
|
|
3342
|
-
{
|
|
3343
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
3344
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
3345
|
-
HANDLE winusb_handle;
|
|
3346
|
-
int current_interface;
|
|
3347
|
-
|
|
3348
|
-
CHECK_WINUSBX_AVAILABLE(sub_api);
|
|
3349
|
-
|
|
3350
|
-
current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
|
|
3351
|
-
if (current_interface < 0) {
|
|
3352
|
-
usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot clear");
|
|
3353
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
3354
|
-
}
|
|
3355
|
-
|
|
3356
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "matched endpoint %02X with interface %d", endpoint, current_interface);
|
|
3357
|
-
winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
|
|
3358
|
-
|
|
3359
|
-
if (!WinUSBX[sub_api].ResetPipe(winusb_handle, endpoint)) {
|
|
3360
|
-
usbi_err(HANDLE_CTX(dev_handle), "ResetPipe failed: %s", windows_error_str(0));
|
|
3361
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
3362
|
-
}
|
|
3363
|
-
|
|
3364
|
-
return LIBUSB_SUCCESS;
|
|
3365
|
-
}
|
|
3366
|
-
|
|
3367
|
-
static int winusbx_cancel_transfer(int sub_api, struct usbi_transfer *itransfer)
|
|
3368
|
-
{
|
|
3369
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
3370
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
|
|
3371
|
-
struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
|
|
3372
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
3373
|
-
int current_interface = transfer_priv->interface_number;
|
|
3374
|
-
HANDLE handle;
|
|
3375
|
-
|
|
3376
|
-
CHECK_WINUSBX_AVAILABLE(sub_api);
|
|
3377
|
-
|
|
3378
|
-
usbi_dbg(TRANSFER_CTX(transfer), "will use interface %d", current_interface);
|
|
3379
|
-
|
|
3380
|
-
handle = handle_priv->interface_handle[current_interface].api_handle;
|
|
3381
|
-
if (!WinUSBX[sub_api].AbortPipe(handle, transfer->endpoint)) {
|
|
3382
|
-
usbi_err(TRANSFER_CTX(transfer), "AbortPipe failed: %s", windows_error_str(0));
|
|
3383
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
3384
|
-
}
|
|
3385
|
-
|
|
3386
|
-
return LIBUSB_SUCCESS;
|
|
3387
|
-
}
|
|
3388
|
-
|
|
3389
|
-
/*
|
|
3390
|
-
* from the "How to Use WinUSB to Communicate with a USB Device" Microsoft white paper
|
|
3391
|
-
* (http://www.microsoft.com/whdc/connect/usb/winusb_howto.mspx):
|
|
3392
|
-
* "WinUSB does not support host-initiated reset port and cycle port operations" and
|
|
3393
|
-
* IOCTL_INTERNAL_USB_CYCLE_PORT is only available in kernel mode and the
|
|
3394
|
-
* IOCTL_USB_HUB_CYCLE_PORT ioctl was removed from Vista => the best we can do is
|
|
3395
|
-
* cycle the pipes (and even then, the control pipe can not be reset using WinUSB)
|
|
3396
|
-
*/
|
|
3397
|
-
// TODO: (post hotplug): see if we can force eject the device and redetect it (reuse hotplug?)
|
|
3398
|
-
static int winusbx_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
|
|
3399
|
-
{
|
|
3400
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
3401
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
3402
|
-
HANDLE winusb_handle;
|
|
3403
|
-
int i, j;
|
|
3404
|
-
|
|
3405
|
-
CHECK_WINUSBX_AVAILABLE(sub_api);
|
|
3406
|
-
|
|
3407
|
-
// Reset any available pipe (except control)
|
|
3408
|
-
for (i = 0; i < USB_MAXINTERFACES; i++) {
|
|
3409
|
-
winusb_handle = handle_priv->interface_handle[i].api_handle;
|
|
3410
|
-
if (HANDLE_VALID(winusb_handle)) {
|
|
3411
|
-
for (j = 0; j < priv->usb_interface[i].nb_endpoints; j++) {
|
|
3412
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "resetting ep %02X", priv->usb_interface[i].endpoint[j]);
|
|
3413
|
-
if (!WinUSBX[sub_api].AbortPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))
|
|
3414
|
-
usbi_err(HANDLE_CTX(dev_handle), "AbortPipe (pipe address %02X) failed: %s",
|
|
3415
|
-
priv->usb_interface[i].endpoint[j], windows_error_str(0));
|
|
3416
|
-
|
|
3417
|
-
// FlushPipe seems to fail on OUT pipes
|
|
3418
|
-
if (IS_EPIN(priv->usb_interface[i].endpoint[j])
|
|
3419
|
-
&& (!WinUSBX[sub_api].FlushPipe(winusb_handle, priv->usb_interface[i].endpoint[j])))
|
|
3420
|
-
usbi_err(HANDLE_CTX(dev_handle), "FlushPipe (pipe address %02X) failed: %s",
|
|
3421
|
-
priv->usb_interface[i].endpoint[j], windows_error_str(0));
|
|
3422
|
-
|
|
3423
|
-
if (!WinUSBX[sub_api].ResetPipe(winusb_handle, priv->usb_interface[i].endpoint[j]))
|
|
3424
|
-
usbi_err(HANDLE_CTX(dev_handle), "ResetPipe (pipe address %02X) failed: %s",
|
|
3425
|
-
priv->usb_interface[i].endpoint[j], windows_error_str(0));
|
|
3426
|
-
}
|
|
3427
|
-
}
|
|
3428
|
-
}
|
|
3429
|
-
|
|
3430
|
-
// libusbK & libusb0 have the ability to issue an actual device reset
|
|
3431
|
-
if ((sub_api != SUB_API_WINUSB) && (WinUSBX[sub_api].ResetDevice != NULL)) {
|
|
3432
|
-
winusb_handle = handle_priv->interface_handle[0].api_handle;
|
|
3433
|
-
if (HANDLE_VALID(winusb_handle))
|
|
3434
|
-
WinUSBX[sub_api].ResetDevice(winusb_handle);
|
|
3435
|
-
}
|
|
3436
|
-
|
|
3437
|
-
return LIBUSB_SUCCESS;
|
|
3438
|
-
}
|
|
3439
|
-
|
|
3440
|
-
static enum libusb_transfer_status winusbx_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length)
|
|
3441
|
-
{
|
|
3442
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
3443
|
-
struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
|
|
3444
|
-
int i;
|
|
3445
|
-
|
|
3446
|
-
if (transfer->type == LIBUSB_TRANSFER_TYPE_ISOCHRONOUS) {
|
|
3447
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
3448
|
-
|
|
3449
|
-
if (sub_api == SUB_API_NOTSET)
|
|
3450
|
-
sub_api = priv->sub_api;
|
|
3451
|
-
if (WinUSBX[sub_api].hDll == NULL)
|
|
3452
|
-
return LIBUSB_TRANSFER_ERROR;
|
|
3453
|
-
|
|
3454
|
-
// for isochronous, need to copy the individual iso packet actual_lengths and statuses
|
|
3455
|
-
if ((sub_api == SUB_API_LIBUSBK) || (sub_api == SUB_API_LIBUSB0)) {
|
|
3456
|
-
// iso only supported on libusbk-based backends for now
|
|
3457
|
-
PKISO_CONTEXT iso_context = transfer_priv->iso_context;
|
|
3458
|
-
for (i = 0; i < transfer->num_iso_packets; i++) {
|
|
3459
|
-
if (IS_XFERIN(transfer)) {
|
|
3460
|
-
transfer->iso_packet_desc[i].actual_length = iso_context->IsoPackets[i].actual_length;
|
|
3461
|
-
} else {
|
|
3462
|
-
// On Windows the usbd Length field is not used for OUT transfers.
|
|
3463
|
-
// Copy the requested value back for consistency with other platforms.
|
|
3464
|
-
transfer->iso_packet_desc[i].actual_length = transfer->iso_packet_desc[i].length;
|
|
3465
|
-
}
|
|
3466
|
-
transfer->iso_packet_desc[i].status = usbd_status_to_libusb_transfer_status(iso_context->IsoPackets[i].status);
|
|
3467
|
-
}
|
|
3468
|
-
} else if (sub_api == SUB_API_WINUSB) {
|
|
3469
|
-
if (IS_XFERIN(transfer)) {
|
|
3470
|
-
/* Convert isochronous packet descriptor between Windows and libusb representation.
|
|
3471
|
-
* Both representation are guaranteed to have the same length in bytes.*/
|
|
3472
|
-
PUSBD_ISO_PACKET_DESCRIPTOR usbd_iso_packet_desc = (PUSBD_ISO_PACKET_DESCRIPTOR)transfer->iso_packet_desc;
|
|
3473
|
-
for (i = 0; i < transfer->num_iso_packets; i++) {
|
|
3474
|
-
unsigned int packet_length = (i < transfer->num_iso_packets - 1) ? (usbd_iso_packet_desc[i + 1].Offset - usbd_iso_packet_desc[i].Offset) : usbd_iso_packet_desc[i].Length;
|
|
3475
|
-
unsigned int actual_length = usbd_iso_packet_desc[i].Length;
|
|
3476
|
-
USBD_STATUS status = usbd_iso_packet_desc[i].Status;
|
|
3477
|
-
|
|
3478
|
-
transfer->iso_packet_desc[i].length = packet_length;
|
|
3479
|
-
transfer->iso_packet_desc[i].actual_length = actual_length;
|
|
3480
|
-
transfer->iso_packet_desc[i].status = usbd_status_to_libusb_transfer_status(status);
|
|
3481
|
-
}
|
|
3482
|
-
} else {
|
|
3483
|
-
for (i = 0; i < transfer->num_iso_packets; i++) {
|
|
3484
|
-
transfer->iso_packet_desc[i].status = LIBUSB_TRANSFER_COMPLETED;
|
|
3485
|
-
// On Windows the usbd Length field is not used for OUT transfers.
|
|
3486
|
-
// Copy the requested value back for consistency with other platforms.
|
|
3487
|
-
transfer->iso_packet_desc[i].actual_length = transfer->iso_packet_desc[i].length;
|
|
3488
|
-
}
|
|
3489
|
-
}
|
|
3490
|
-
} else {
|
|
3491
|
-
// This should only occur if backend is not set correctly or other backend isoc is partially implemented
|
|
3492
|
-
PRINT_UNSUPPORTED_API(copy_transfer_data);
|
|
3493
|
-
return LIBUSB_TRANSFER_ERROR;
|
|
3494
|
-
}
|
|
3495
|
-
}
|
|
3496
|
-
|
|
3497
|
-
itransfer->transferred += (int)length;
|
|
3498
|
-
return LIBUSB_TRANSFER_COMPLETED;
|
|
3499
|
-
}
|
|
3500
|
-
|
|
3501
|
-
/*
|
|
3502
|
-
* Internal HID Support functions (from libusb-win32)
|
|
3503
|
-
* Note that functions that complete data transfer synchronously must return
|
|
3504
|
-
* LIBUSB_COMPLETED instead of LIBUSB_SUCCESS
|
|
3505
|
-
*/
|
|
3506
|
-
static int _hid_get_hid_descriptor(struct hid_device_priv *dev, void *data, size_t *size);
|
|
3507
|
-
static int _hid_get_report_descriptor(struct hid_device_priv *dev, void *data, size_t *size);
|
|
3508
|
-
|
|
3509
|
-
static int _hid_wcslen(WCHAR *str)
|
|
3510
|
-
{
|
|
3511
|
-
int i = 0;
|
|
3512
|
-
|
|
3513
|
-
while (str[i] && (str[i] != 0x409))
|
|
3514
|
-
i++;
|
|
3515
|
-
|
|
3516
|
-
return i;
|
|
3517
|
-
}
|
|
3518
|
-
|
|
3519
|
-
static int _hid_get_device_descriptor(struct libusb_device *dev, struct hid_device_priv *hid_priv, void *data, size_t *size)
|
|
3520
|
-
{
|
|
3521
|
-
struct libusb_device_descriptor d;
|
|
3522
|
-
|
|
3523
|
-
/* Copy some values from the cached device descriptor
|
|
3524
|
-
* because we cannot get them through HID */
|
|
3525
|
-
d.bLength = LIBUSB_DT_DEVICE_SIZE;
|
|
3526
|
-
d.bDescriptorType = LIBUSB_DT_DEVICE;
|
|
3527
|
-
d.bcdUSB = dev->device_descriptor.bcdUSB;
|
|
3528
|
-
d.bDeviceClass = dev->device_descriptor.bDeviceClass;
|
|
3529
|
-
d.bDeviceSubClass = dev->device_descriptor.bDeviceSubClass;
|
|
3530
|
-
d.bDeviceProtocol = dev->device_descriptor.bDeviceProtocol;
|
|
3531
|
-
d.bMaxPacketSize0 = dev->device_descriptor.bMaxPacketSize0;
|
|
3532
|
-
d.idVendor = (uint16_t)hid_priv->vid;
|
|
3533
|
-
d.idProduct = (uint16_t)hid_priv->pid;
|
|
3534
|
-
d.bcdDevice = dev->device_descriptor.bcdDevice;
|
|
3535
|
-
d.iManufacturer = hid_priv->string_index[0];
|
|
3536
|
-
d.iProduct = hid_priv->string_index[1];
|
|
3537
|
-
d.iSerialNumber = hid_priv->string_index[2];
|
|
3538
|
-
d.bNumConfigurations = dev->device_descriptor.bNumConfigurations;
|
|
3539
|
-
|
|
3540
|
-
if (*size > LIBUSB_DT_DEVICE_SIZE)
|
|
3541
|
-
*size = LIBUSB_DT_DEVICE_SIZE;
|
|
3542
|
-
memcpy(data, &d, *size);
|
|
3543
|
-
|
|
3544
|
-
return LIBUSB_COMPLETED;
|
|
3545
|
-
}
|
|
3546
|
-
|
|
3547
|
-
static int _hid_get_config_descriptor(struct hid_device_priv *hid_priv, void *data, size_t *size)
|
|
3548
|
-
{
|
|
3549
|
-
char num_endpoints = 0;
|
|
3550
|
-
size_t config_total_len = 0;
|
|
3551
|
-
char tmp[HID_MAX_CONFIG_DESC_SIZE];
|
|
3552
|
-
struct libusb_config_descriptor *cd;
|
|
3553
|
-
struct libusb_interface_descriptor *id;
|
|
3554
|
-
struct libusb_hid_descriptor *hd;
|
|
3555
|
-
struct libusb_endpoint_descriptor *ed;
|
|
3556
|
-
size_t tmp_size;
|
|
3557
|
-
|
|
3558
|
-
if (hid_priv->input_report_size)
|
|
3559
|
-
num_endpoints++;
|
|
3560
|
-
if (hid_priv->output_report_size)
|
|
3561
|
-
num_endpoints++;
|
|
3562
|
-
|
|
3563
|
-
config_total_len = LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE
|
|
3564
|
-
+ LIBUSB_DT_HID_SIZE + num_endpoints * LIBUSB_DT_ENDPOINT_SIZE;
|
|
3565
|
-
|
|
3566
|
-
cd = (struct libusb_config_descriptor *)tmp;
|
|
3567
|
-
id = (struct libusb_interface_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE);
|
|
3568
|
-
hd = (struct libusb_hid_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE
|
|
3569
|
-
+ LIBUSB_DT_INTERFACE_SIZE);
|
|
3570
|
-
ed = (struct libusb_endpoint_descriptor *)(tmp + LIBUSB_DT_CONFIG_SIZE
|
|
3571
|
-
+ LIBUSB_DT_INTERFACE_SIZE
|
|
3572
|
-
+ LIBUSB_DT_HID_SIZE);
|
|
3573
|
-
|
|
3574
|
-
cd->bLength = LIBUSB_DT_CONFIG_SIZE;
|
|
3575
|
-
cd->bDescriptorType = LIBUSB_DT_CONFIG;
|
|
3576
|
-
cd->wTotalLength = (uint16_t)config_total_len;
|
|
3577
|
-
cd->bNumInterfaces = 1;
|
|
3578
|
-
cd->bConfigurationValue = 1;
|
|
3579
|
-
cd->iConfiguration = 0;
|
|
3580
|
-
cd->bmAttributes = 1 << 7; /* bus powered */
|
|
3581
|
-
cd->MaxPower = 50;
|
|
3582
|
-
|
|
3583
|
-
id->bLength = LIBUSB_DT_INTERFACE_SIZE;
|
|
3584
|
-
id->bDescriptorType = LIBUSB_DT_INTERFACE;
|
|
3585
|
-
id->bInterfaceNumber = 0;
|
|
3586
|
-
id->bAlternateSetting = 0;
|
|
3587
|
-
id->bNumEndpoints = num_endpoints;
|
|
3588
|
-
id->bInterfaceClass = 3;
|
|
3589
|
-
id->bInterfaceSubClass = 0;
|
|
3590
|
-
id->bInterfaceProtocol = 0;
|
|
3591
|
-
id->iInterface = 0;
|
|
3592
|
-
|
|
3593
|
-
tmp_size = LIBUSB_DT_HID_SIZE;
|
|
3594
|
-
_hid_get_hid_descriptor(hid_priv, hd, &tmp_size);
|
|
3595
|
-
|
|
3596
|
-
if (hid_priv->input_report_size) {
|
|
3597
|
-
ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
|
|
3598
|
-
ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
|
|
3599
|
-
ed->bEndpointAddress = HID_IN_EP;
|
|
3600
|
-
ed->bmAttributes = 3;
|
|
3601
|
-
ed->wMaxPacketSize = hid_priv->input_report_size - 1;
|
|
3602
|
-
ed->bInterval = 10;
|
|
3603
|
-
ed = (struct libusb_endpoint_descriptor *)((char *)ed + LIBUSB_DT_ENDPOINT_SIZE);
|
|
3604
|
-
}
|
|
3605
|
-
|
|
3606
|
-
if (hid_priv->output_report_size) {
|
|
3607
|
-
ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
|
|
3608
|
-
ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
|
|
3609
|
-
ed->bEndpointAddress = HID_OUT_EP;
|
|
3610
|
-
ed->bmAttributes = 3;
|
|
3611
|
-
ed->wMaxPacketSize = hid_priv->output_report_size - 1;
|
|
3612
|
-
ed->bInterval = 10;
|
|
3613
|
-
}
|
|
3614
|
-
|
|
3615
|
-
if (*size > config_total_len)
|
|
3616
|
-
*size = config_total_len;
|
|
3617
|
-
memcpy(data, tmp, *size);
|
|
3618
|
-
|
|
3619
|
-
return LIBUSB_COMPLETED;
|
|
3620
|
-
}
|
|
3621
|
-
|
|
3622
|
-
static int _hid_get_string_descriptor(struct hid_device_priv *hid_priv, int _index,
|
|
3623
|
-
void *data, size_t *size, HANDLE hid_handle)
|
|
3624
|
-
{
|
|
3625
|
-
void *tmp = NULL;
|
|
3626
|
-
WCHAR string[MAX_USB_STRING_LENGTH];
|
|
3627
|
-
size_t tmp_size = 0;
|
|
3628
|
-
int i;
|
|
3629
|
-
|
|
3630
|
-
/* language ID, EN-US */
|
|
3631
|
-
char string_langid[] = {0x09, 0x04};
|
|
3632
|
-
|
|
3633
|
-
if (_index == 0) {
|
|
3634
|
-
tmp = string_langid;
|
|
3635
|
-
tmp_size = sizeof(string_langid) + 2;
|
|
3636
|
-
} else {
|
|
3637
|
-
for (i = 0; i < 3; i++) {
|
|
3638
|
-
if (_index == (hid_priv->string_index[i])) {
|
|
3639
|
-
tmp = hid_priv->string[i];
|
|
3640
|
-
tmp_size = (_hid_wcslen(hid_priv->string[i]) + 1) * sizeof(WCHAR);
|
|
3641
|
-
break;
|
|
3642
|
-
}
|
|
3643
|
-
}
|
|
3644
|
-
|
|
3645
|
-
if (i == 3) {
|
|
3646
|
-
if (!HidD_GetIndexedString(hid_handle, _index, string, sizeof(string)))
|
|
3647
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3648
|
-
tmp = string;
|
|
3649
|
-
tmp_size = (_hid_wcslen(string) + 1) * sizeof(WCHAR);
|
|
3650
|
-
}
|
|
3651
|
-
}
|
|
3652
|
-
|
|
3653
|
-
if (!tmp_size)
|
|
3654
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3655
|
-
|
|
3656
|
-
if (tmp_size < *size)
|
|
3657
|
-
*size = tmp_size;
|
|
3658
|
-
|
|
3659
|
-
// 2 byte header
|
|
3660
|
-
((uint8_t *)data)[0] = (uint8_t)*size;
|
|
3661
|
-
((uint8_t *)data)[1] = LIBUSB_DT_STRING;
|
|
3662
|
-
memcpy((uint8_t *)data + 2, tmp, *size - 2);
|
|
3663
|
-
|
|
3664
|
-
return LIBUSB_COMPLETED;
|
|
3665
|
-
}
|
|
3666
|
-
|
|
3667
|
-
static int _hid_get_hid_descriptor(struct hid_device_priv *hid_priv, void *data, size_t *size)
|
|
3668
|
-
{
|
|
3669
|
-
struct libusb_hid_descriptor d;
|
|
3670
|
-
uint8_t tmp[MAX_HID_DESCRIPTOR_SIZE];
|
|
3671
|
-
size_t report_len = MAX_HID_DESCRIPTOR_SIZE;
|
|
3672
|
-
|
|
3673
|
-
_hid_get_report_descriptor(hid_priv, tmp, &report_len);
|
|
3674
|
-
|
|
3675
|
-
d.bLength = LIBUSB_DT_HID_SIZE;
|
|
3676
|
-
d.bDescriptorType = LIBUSB_DT_HID;
|
|
3677
|
-
d.bcdHID = 0x0110; /* 1.10 */
|
|
3678
|
-
d.bCountryCode = 0;
|
|
3679
|
-
d.bNumDescriptors = 1;
|
|
3680
|
-
d.bClassDescriptorType = LIBUSB_DT_REPORT;
|
|
3681
|
-
d.wClassDescriptorLength = (uint16_t)report_len;
|
|
3682
|
-
|
|
3683
|
-
if (*size > LIBUSB_DT_HID_SIZE)
|
|
3684
|
-
*size = LIBUSB_DT_HID_SIZE;
|
|
3685
|
-
memcpy(data, &d, *size);
|
|
3686
|
-
|
|
3687
|
-
return LIBUSB_COMPLETED;
|
|
3688
|
-
}
|
|
3689
|
-
|
|
3690
|
-
static int _hid_get_report_descriptor(struct hid_device_priv *hid_priv, void *data, size_t *size)
|
|
3691
|
-
{
|
|
3692
|
-
uint8_t d[MAX_HID_DESCRIPTOR_SIZE];
|
|
3693
|
-
size_t i = 0;
|
|
3694
|
-
|
|
3695
|
-
/* usage page */
|
|
3696
|
-
d[i++] = 0x06; d[i++] = hid_priv->usagePage & 0xFF; d[i++] = hid_priv->usagePage >> 8;
|
|
3697
|
-
/* usage */
|
|
3698
|
-
d[i++] = 0x09; d[i++] = (uint8_t)hid_priv->usage;
|
|
3699
|
-
/* start collection (application) */
|
|
3700
|
-
d[i++] = 0xA1; d[i++] = 0x01;
|
|
3701
|
-
/* input report */
|
|
3702
|
-
if (hid_priv->input_report_size) {
|
|
3703
|
-
/* usage (vendor defined) */
|
|
3704
|
-
d[i++] = 0x09; d[i++] = 0x01;
|
|
3705
|
-
/* logical minimum (0) */
|
|
3706
|
-
d[i++] = 0x15; d[i++] = 0x00;
|
|
3707
|
-
/* logical maximum (255) */
|
|
3708
|
-
d[i++] = 0x25; d[i++] = 0xFF;
|
|
3709
|
-
/* report size (8 bits) */
|
|
3710
|
-
d[i++] = 0x75; d[i++] = 0x08;
|
|
3711
|
-
/* report count */
|
|
3712
|
-
d[i++] = 0x95; d[i++] = (uint8_t)hid_priv->input_report_size - 1;
|
|
3713
|
-
/* input (data, variable, absolute) */
|
|
3714
|
-
d[i++] = 0x81; d[i++] = 0x00;
|
|
3715
|
-
}
|
|
3716
|
-
/* output report */
|
|
3717
|
-
if (hid_priv->output_report_size) {
|
|
3718
|
-
/* usage (vendor defined) */
|
|
3719
|
-
d[i++] = 0x09; d[i++] = 0x02;
|
|
3720
|
-
/* logical minimum (0) */
|
|
3721
|
-
d[i++] = 0x15; d[i++] = 0x00;
|
|
3722
|
-
/* logical maximum (255) */
|
|
3723
|
-
d[i++] = 0x25; d[i++] = 0xFF;
|
|
3724
|
-
/* report size (8 bits) */
|
|
3725
|
-
d[i++] = 0x75; d[i++] = 0x08;
|
|
3726
|
-
/* report count */
|
|
3727
|
-
d[i++] = 0x95; d[i++] = (uint8_t)hid_priv->output_report_size - 1;
|
|
3728
|
-
/* output (data, variable, absolute) */
|
|
3729
|
-
d[i++] = 0x91; d[i++] = 0x00;
|
|
3730
|
-
}
|
|
3731
|
-
/* feature report */
|
|
3732
|
-
if (hid_priv->feature_report_size) {
|
|
3733
|
-
/* usage (vendor defined) */
|
|
3734
|
-
d[i++] = 0x09; d[i++] = 0x03;
|
|
3735
|
-
/* logical minimum (0) */
|
|
3736
|
-
d[i++] = 0x15; d[i++] = 0x00;
|
|
3737
|
-
/* logical maximum (255) */
|
|
3738
|
-
d[i++] = 0x25; d[i++] = 0xFF;
|
|
3739
|
-
/* report size (8 bits) */
|
|
3740
|
-
d[i++] = 0x75; d[i++] = 0x08;
|
|
3741
|
-
/* report count */
|
|
3742
|
-
d[i++] = 0x95; d[i++] = (uint8_t)hid_priv->feature_report_size - 1;
|
|
3743
|
-
/* feature (data, variable, absolute) */
|
|
3744
|
-
d[i++] = 0xb2; d[i++] = 0x02; d[i++] = 0x01;
|
|
3745
|
-
}
|
|
3746
|
-
|
|
3747
|
-
/* end collection */
|
|
3748
|
-
d[i++] = 0xC0;
|
|
3749
|
-
|
|
3750
|
-
if (*size > i)
|
|
3751
|
-
*size = i;
|
|
3752
|
-
memcpy(data, d, *size);
|
|
3753
|
-
|
|
3754
|
-
return LIBUSB_COMPLETED;
|
|
3755
|
-
}
|
|
3756
|
-
|
|
3757
|
-
static int _hid_get_descriptor(struct libusb_device *dev, HANDLE hid_handle, int recipient,
|
|
3758
|
-
int type, int _index, void *data, size_t *size)
|
|
3759
|
-
{
|
|
3760
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
|
|
3761
|
-
UNUSED(recipient);
|
|
3762
|
-
|
|
3763
|
-
switch (type) {
|
|
3764
|
-
case LIBUSB_DT_DEVICE:
|
|
3765
|
-
usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_DEVICE");
|
|
3766
|
-
return _hid_get_device_descriptor(dev, priv->hid, data, size);
|
|
3767
|
-
case LIBUSB_DT_CONFIG:
|
|
3768
|
-
usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_CONFIG");
|
|
3769
|
-
if (!_index)
|
|
3770
|
-
return _hid_get_config_descriptor(priv->hid, data, size);
|
|
3771
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3772
|
-
case LIBUSB_DT_STRING:
|
|
3773
|
-
usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_STRING");
|
|
3774
|
-
return _hid_get_string_descriptor(priv->hid, _index, data, size, hid_handle);
|
|
3775
|
-
case LIBUSB_DT_HID:
|
|
3776
|
-
usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_HID");
|
|
3777
|
-
if (!_index)
|
|
3778
|
-
return _hid_get_hid_descriptor(priv->hid, data, size);
|
|
3779
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3780
|
-
case LIBUSB_DT_REPORT:
|
|
3781
|
-
usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_REPORT");
|
|
3782
|
-
if (!_index)
|
|
3783
|
-
return _hid_get_report_descriptor(priv->hid, data, size);
|
|
3784
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3785
|
-
case LIBUSB_DT_PHYSICAL:
|
|
3786
|
-
usbi_dbg(DEVICE_CTX(dev), "LIBUSB_DT_PHYSICAL");
|
|
3787
|
-
if (HidD_GetPhysicalDescriptor(hid_handle, data, (ULONG)*size))
|
|
3788
|
-
return LIBUSB_COMPLETED;
|
|
3789
|
-
return LIBUSB_ERROR_OTHER;
|
|
3790
|
-
}
|
|
3791
|
-
|
|
3792
|
-
usbi_warn(DEVICE_CTX(dev), "unsupported");
|
|
3793
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
3794
|
-
}
|
|
3795
|
-
|
|
3796
|
-
static int _hid_get_report(struct libusb_device *dev, HANDLE hid_handle, int id, void *data,
|
|
3797
|
-
struct winusb_transfer_priv *tp, size_t size, OVERLAPPED *overlapped, int report_type)
|
|
3798
|
-
{
|
|
3799
|
-
DWORD ioctl_code, expected_size = (DWORD)size;
|
|
3800
|
-
uint8_t *buf;
|
|
3801
|
-
|
|
3802
|
-
if (tp->hid_buffer != NULL)
|
|
3803
|
-
usbi_err(DEVICE_CTX(dev), "program assertion failed - hid_buffer is not NULL");
|
|
3804
|
-
|
|
3805
|
-
if ((size == 0) || (size > MAX_HID_REPORT_SIZE)) {
|
|
3806
|
-
usbi_warn(DEVICE_CTX(dev), "invalid size (%"PRIuPTR")", (uintptr_t)size);
|
|
3807
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3808
|
-
}
|
|
3809
|
-
|
|
3810
|
-
switch (report_type) {
|
|
3811
|
-
case HID_REPORT_TYPE_INPUT:
|
|
3812
|
-
ioctl_code = IOCTL_HID_GET_INPUT_REPORT;
|
|
3813
|
-
break;
|
|
3814
|
-
case HID_REPORT_TYPE_FEATURE:
|
|
3815
|
-
ioctl_code = IOCTL_HID_GET_FEATURE;
|
|
3816
|
-
break;
|
|
3817
|
-
default:
|
|
3818
|
-
usbi_warn(DEVICE_CTX(dev), "unknown HID report type %d", report_type);
|
|
3819
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3820
|
-
}
|
|
3821
|
-
|
|
3822
|
-
// Add a trailing byte to detect overflows
|
|
3823
|
-
buf = calloc(1, expected_size + 1);
|
|
3824
|
-
if (buf == NULL)
|
|
3825
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
3826
|
-
|
|
3827
|
-
buf[0] = (uint8_t)id; // Must be set always
|
|
3828
|
-
usbi_dbg(DEVICE_CTX(dev), "report ID: 0x%02X", buf[0]);
|
|
3829
|
-
|
|
3830
|
-
// NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
|
|
3831
|
-
if (!DeviceIoControl(hid_handle, ioctl_code, buf, expected_size + 1,
|
|
3832
|
-
buf, expected_size + 1, NULL, overlapped)) {
|
|
3833
|
-
if (GetLastError() != ERROR_IO_PENDING) {
|
|
3834
|
-
usbi_err(DEVICE_CTX(dev), "failed to read HID Report: %s", windows_error_str(0));
|
|
3835
|
-
free(buf);
|
|
3836
|
-
return LIBUSB_ERROR_IO;
|
|
3837
|
-
}
|
|
3838
|
-
}
|
|
3839
|
-
|
|
3840
|
-
// Asynchronous wait
|
|
3841
|
-
tp->hid_buffer = buf;
|
|
3842
|
-
tp->hid_dest = data; // copy dest, as not necessarily the start of the transfer buffer
|
|
3843
|
-
tp->hid_expected_size = expected_size;
|
|
3844
|
-
|
|
3845
|
-
return LIBUSB_SUCCESS;
|
|
3846
|
-
}
|
|
3847
|
-
|
|
3848
|
-
static int _hid_set_report(struct libusb_device *dev, HANDLE hid_handle, int id, void *data,
|
|
3849
|
-
struct winusb_transfer_priv *tp, size_t size, OVERLAPPED *overlapped, int report_type)
|
|
3850
|
-
{
|
|
3851
|
-
DWORD ioctl_code, write_size = (DWORD)size;
|
|
3852
|
-
// If an id is reported, we must allow MAX_HID_REPORT_SIZE + 1
|
|
3853
|
-
size_t max_report_size = MAX_HID_REPORT_SIZE + (id ? 1 : 0);
|
|
3854
|
-
uint8_t *buf;
|
|
3855
|
-
|
|
3856
|
-
if (tp->hid_buffer != NULL)
|
|
3857
|
-
usbi_err(DEVICE_CTX(dev), "program assertion failed - hid_buffer is not NULL");
|
|
3858
|
-
|
|
3859
|
-
if ((size == 0) || (size > max_report_size)) {
|
|
3860
|
-
usbi_warn(DEVICE_CTX(dev), "invalid size (%"PRIuPTR")", (uintptr_t)size);
|
|
3861
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3862
|
-
}
|
|
3863
|
-
|
|
3864
|
-
switch (report_type) {
|
|
3865
|
-
case HID_REPORT_TYPE_OUTPUT:
|
|
3866
|
-
ioctl_code = IOCTL_HID_SET_OUTPUT_REPORT;
|
|
3867
|
-
break;
|
|
3868
|
-
case HID_REPORT_TYPE_FEATURE:
|
|
3869
|
-
ioctl_code = IOCTL_HID_SET_FEATURE;
|
|
3870
|
-
break;
|
|
3871
|
-
default:
|
|
3872
|
-
usbi_warn(DEVICE_CTX(dev), "unknown HID report type %d", report_type);
|
|
3873
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3874
|
-
}
|
|
3875
|
-
|
|
3876
|
-
usbi_dbg(DEVICE_CTX(dev), "report ID: 0x%02X", id);
|
|
3877
|
-
// When report IDs are not used (i.e. when id == 0), we must add
|
|
3878
|
-
// a null report ID. Otherwise, we just use original data buffer
|
|
3879
|
-
if (id == 0)
|
|
3880
|
-
write_size++;
|
|
3881
|
-
|
|
3882
|
-
buf = malloc(write_size);
|
|
3883
|
-
if (buf == NULL)
|
|
3884
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
3885
|
-
|
|
3886
|
-
if (id == 0) {
|
|
3887
|
-
buf[0] = 0;
|
|
3888
|
-
memcpy(buf + 1, data, size);
|
|
3889
|
-
} else {
|
|
3890
|
-
// This seems like a waste, but if we don't duplicate the
|
|
3891
|
-
// data, we'll get issues when freeing hid_buffer
|
|
3892
|
-
memcpy(buf, data, size);
|
|
3893
|
-
if (buf[0] != id)
|
|
3894
|
-
usbi_warn(DEVICE_CTX(dev), "mismatched report ID (data is %02X, parameter is %02X)", buf[0], id);
|
|
3895
|
-
}
|
|
3896
|
-
|
|
3897
|
-
// NB: The size returned by DeviceIoControl doesn't include report IDs when not in use (0)
|
|
3898
|
-
if (!DeviceIoControl(hid_handle, ioctl_code, buf, write_size,
|
|
3899
|
-
buf, write_size, NULL, overlapped)) {
|
|
3900
|
-
if (GetLastError() != ERROR_IO_PENDING) {
|
|
3901
|
-
usbi_err(DEVICE_CTX(dev), "failed to write HID Output Report: %s", windows_error_str(0));
|
|
3902
|
-
free(buf);
|
|
3903
|
-
return LIBUSB_ERROR_IO;
|
|
3904
|
-
}
|
|
3905
|
-
}
|
|
3906
|
-
|
|
3907
|
-
tp->hid_buffer = buf;
|
|
3908
|
-
tp->hid_dest = NULL;
|
|
3909
|
-
return LIBUSB_SUCCESS;
|
|
3910
|
-
}
|
|
3911
|
-
|
|
3912
|
-
static int _hid_class_request(struct libusb_device *dev, HANDLE hid_handle, int request_type,
|
|
3913
|
-
int request, int value, int _index, void *data, struct winusb_transfer_priv *tp,
|
|
3914
|
-
size_t size, OVERLAPPED *overlapped)
|
|
3915
|
-
{
|
|
3916
|
-
int report_type = (value >> 8) & 0xFF;
|
|
3917
|
-
int report_id = value & 0xFF;
|
|
3918
|
-
|
|
3919
|
-
UNUSED(_index);
|
|
3920
|
-
|
|
3921
|
-
if ((LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_INTERFACE)
|
|
3922
|
-
&& (LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_DEVICE))
|
|
3923
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3924
|
-
|
|
3925
|
-
if (LIBUSB_REQ_OUT(request_type) && request == HID_REQ_SET_REPORT)
|
|
3926
|
-
return _hid_set_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type);
|
|
3927
|
-
|
|
3928
|
-
if (LIBUSB_REQ_IN(request_type) && request == HID_REQ_GET_REPORT)
|
|
3929
|
-
return _hid_get_report(dev, hid_handle, report_id, data, tp, size, overlapped, report_type);
|
|
3930
|
-
|
|
3931
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
3932
|
-
}
|
|
3933
|
-
|
|
3934
|
-
/*
|
|
3935
|
-
* HID API functions
|
|
3936
|
-
*/
|
|
3937
|
-
static bool hid_init(struct libusb_context *ctx)
|
|
3938
|
-
{
|
|
3939
|
-
DLL_GET_HANDLE(ctx, hid);
|
|
3940
|
-
|
|
3941
|
-
DLL_LOAD_FUNC(hid, HidD_GetAttributes, true);
|
|
3942
|
-
DLL_LOAD_FUNC(hid, HidD_GetHidGuid, true);
|
|
3943
|
-
DLL_LOAD_FUNC(hid, HidD_GetPreparsedData, true);
|
|
3944
|
-
DLL_LOAD_FUNC(hid, HidD_FreePreparsedData, true);
|
|
3945
|
-
DLL_LOAD_FUNC(hid, HidD_GetManufacturerString, true);
|
|
3946
|
-
DLL_LOAD_FUNC(hid, HidD_GetProductString, true);
|
|
3947
|
-
DLL_LOAD_FUNC(hid, HidD_GetSerialNumberString, true);
|
|
3948
|
-
DLL_LOAD_FUNC(hid, HidD_GetIndexedString, true);
|
|
3949
|
-
DLL_LOAD_FUNC(hid, HidP_GetCaps, true);
|
|
3950
|
-
DLL_LOAD_FUNC(hid, HidD_SetNumInputBuffers, true);
|
|
3951
|
-
DLL_LOAD_FUNC(hid, HidD_GetPhysicalDescriptor, true);
|
|
3952
|
-
DLL_LOAD_FUNC(hid, HidD_FlushQueue, true);
|
|
3953
|
-
DLL_LOAD_FUNC(hid, HidP_GetValueCaps, true);
|
|
3954
|
-
|
|
3955
|
-
return true;
|
|
3956
|
-
}
|
|
3957
|
-
|
|
3958
|
-
static void hid_exit(void)
|
|
3959
|
-
{
|
|
3960
|
-
DLL_FREE_HANDLE(hid);
|
|
3961
|
-
}
|
|
3962
|
-
|
|
3963
|
-
// NB: open and close must ensure that they only handle interface of
|
|
3964
|
-
// the right API type, as these functions can be called wholesale from
|
|
3965
|
-
// composite_open(), with interfaces belonging to different APIs
|
|
3966
|
-
static int hid_open(int sub_api, struct libusb_device_handle *dev_handle)
|
|
3967
|
-
{
|
|
3968
|
-
struct libusb_device *dev = dev_handle->dev;
|
|
3969
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev);
|
|
3970
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
3971
|
-
HIDD_ATTRIBUTES hid_attributes;
|
|
3972
|
-
PHIDP_PREPARSED_DATA preparsed_data = NULL;
|
|
3973
|
-
HIDP_CAPS capabilities;
|
|
3974
|
-
HIDP_VALUE_CAPS *value_caps;
|
|
3975
|
-
HANDLE hid_handle = INVALID_HANDLE_VALUE;
|
|
3976
|
-
int i, j;
|
|
3977
|
-
// report IDs handling
|
|
3978
|
-
ULONG size[3];
|
|
3979
|
-
int nb_ids[2]; // zero and nonzero report IDs
|
|
3980
|
-
#if defined(ENABLE_LOGGING)
|
|
3981
|
-
const char * const type[3] = {"input", "output", "feature"};
|
|
3982
|
-
#endif
|
|
3983
|
-
|
|
3984
|
-
UNUSED(sub_api);
|
|
3985
|
-
CHECK_HID_AVAILABLE;
|
|
3986
|
-
|
|
3987
|
-
if (priv->hid == NULL) {
|
|
3988
|
-
usbi_err(HANDLE_CTX(dev_handle), "program assertion failed - private HID structure is uninitialized");
|
|
3989
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
3990
|
-
}
|
|
3991
|
-
|
|
3992
|
-
for (i = 0; i < USB_MAXINTERFACES; i++) {
|
|
3993
|
-
if ((priv->usb_interface[i].path != NULL)
|
|
3994
|
-
&& (priv->usb_interface[i].apib->id == USB_API_HID)) {
|
|
3995
|
-
hid_handle = windows_open(dev_handle, priv->usb_interface[i].path, GENERIC_READ | GENERIC_WRITE);
|
|
3996
|
-
/*
|
|
3997
|
-
* http://www.lvr.com/hidfaq.htm: Why do I receive "Access denied" when attempting to access my HID?
|
|
3998
|
-
* "Windows 2000 and later have exclusive read/write access to HIDs that are configured as a system
|
|
3999
|
-
* keyboards or mice. An application can obtain a handle to a system keyboard or mouse by not
|
|
4000
|
-
* requesting READ or WRITE access with CreateFile. Applications can then use HidD_SetFeature and
|
|
4001
|
-
* HidD_GetFeature (if the device supports Feature reports)."
|
|
4002
|
-
*/
|
|
4003
|
-
if (hid_handle == INVALID_HANDLE_VALUE) {
|
|
4004
|
-
usbi_warn(HANDLE_CTX(dev_handle), "could not open HID device in R/W mode (keyboard or mouse?) - trying without");
|
|
4005
|
-
hid_handle = windows_open(dev_handle, priv->usb_interface[i].path, 0);
|
|
4006
|
-
if (hid_handle == INVALID_HANDLE_VALUE) {
|
|
4007
|
-
usbi_err(HANDLE_CTX(dev_handle), "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0));
|
|
4008
|
-
switch (GetLastError()) {
|
|
4009
|
-
case ERROR_FILE_NOT_FOUND: // The device was disconnected
|
|
4010
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
4011
|
-
case ERROR_ACCESS_DENIED:
|
|
4012
|
-
return LIBUSB_ERROR_ACCESS;
|
|
4013
|
-
default:
|
|
4014
|
-
return LIBUSB_ERROR_IO;
|
|
4015
|
-
}
|
|
4016
|
-
}
|
|
4017
|
-
priv->usb_interface[i].restricted_functionality = true;
|
|
4018
|
-
}
|
|
4019
|
-
handle_priv->interface_handle[i].api_handle = hid_handle;
|
|
4020
|
-
}
|
|
4021
|
-
}
|
|
4022
|
-
|
|
4023
|
-
hid_attributes.Size = sizeof(hid_attributes);
|
|
4024
|
-
do {
|
|
4025
|
-
if (!HidD_GetAttributes(hid_handle, &hid_attributes)) {
|
|
4026
|
-
usbi_err(HANDLE_CTX(dev_handle), "could not gain access to HID top collection (HidD_GetAttributes)");
|
|
4027
|
-
break;
|
|
4028
|
-
}
|
|
4029
|
-
|
|
4030
|
-
priv->hid->vid = hid_attributes.VendorID;
|
|
4031
|
-
priv->hid->pid = hid_attributes.ProductID;
|
|
4032
|
-
|
|
4033
|
-
// Set the maximum available input buffer size
|
|
4034
|
-
for (i = 32; HidD_SetNumInputBuffers(hid_handle, i); i *= 2);
|
|
4035
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "set maximum input buffer size to %d", i / 2);
|
|
4036
|
-
|
|
4037
|
-
// Get the maximum input and output report size
|
|
4038
|
-
if (!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) {
|
|
4039
|
-
usbi_err(HANDLE_CTX(dev_handle), "could not read HID preparsed data (HidD_GetPreparsedData)");
|
|
4040
|
-
break;
|
|
4041
|
-
}
|
|
4042
|
-
if (HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) {
|
|
4043
|
-
usbi_err(HANDLE_CTX(dev_handle), "could not parse HID capabilities (HidP_GetCaps)");
|
|
4044
|
-
break;
|
|
4045
|
-
}
|
|
4046
|
-
|
|
4047
|
-
// Find out if interrupt will need report IDs
|
|
4048
|
-
size[0] = capabilities.NumberInputValueCaps;
|
|
4049
|
-
size[1] = capabilities.NumberOutputValueCaps;
|
|
4050
|
-
size[2] = capabilities.NumberFeatureValueCaps;
|
|
4051
|
-
for (j = HidP_Input; j <= HidP_Feature; j++) {
|
|
4052
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "%lu HID %s report value(s) found", ULONG_CAST(size[j]), type[j]);
|
|
4053
|
-
priv->hid->uses_report_ids[j] = false;
|
|
4054
|
-
if (size[j] > 0) {
|
|
4055
|
-
value_caps = calloc(size[j], sizeof(HIDP_VALUE_CAPS));
|
|
4056
|
-
if ((value_caps != NULL)
|
|
4057
|
-
&& (HidP_GetValueCaps((HIDP_REPORT_TYPE)j, value_caps, &size[j], preparsed_data) == HIDP_STATUS_SUCCESS)
|
|
4058
|
-
&& (size[j] >= 1)) {
|
|
4059
|
-
nb_ids[0] = 0;
|
|
4060
|
-
nb_ids[1] = 0;
|
|
4061
|
-
for (i = 0; i < (int)size[j]; i++) {
|
|
4062
|
-
usbi_dbg(HANDLE_CTX(dev_handle), " Report ID: 0x%02X", value_caps[i].ReportID);
|
|
4063
|
-
if (value_caps[i].ReportID != 0)
|
|
4064
|
-
nb_ids[1]++;
|
|
4065
|
-
else
|
|
4066
|
-
nb_ids[0]++;
|
|
4067
|
-
}
|
|
4068
|
-
if (nb_ids[1] != 0) {
|
|
4069
|
-
if (nb_ids[0] != 0)
|
|
4070
|
-
usbi_warn(HANDLE_CTX(dev_handle), "program assertion failed - zero and nonzero report IDs used for %s",
|
|
4071
|
-
type[j]);
|
|
4072
|
-
priv->hid->uses_report_ids[j] = true;
|
|
4073
|
-
}
|
|
4074
|
-
} else {
|
|
4075
|
-
usbi_warn(HANDLE_CTX(dev_handle), " could not process %s report IDs", type[j]);
|
|
4076
|
-
}
|
|
4077
|
-
free(value_caps);
|
|
4078
|
-
}
|
|
4079
|
-
}
|
|
4080
|
-
|
|
4081
|
-
// Set the report sizes
|
|
4082
|
-
priv->hid->input_report_size = capabilities.InputReportByteLength;
|
|
4083
|
-
priv->hid->output_report_size = capabilities.OutputReportByteLength;
|
|
4084
|
-
priv->hid->feature_report_size = capabilities.FeatureReportByteLength;
|
|
4085
|
-
|
|
4086
|
-
// Store usage and usagePage values
|
|
4087
|
-
priv->hid->usage = capabilities.Usage;
|
|
4088
|
-
priv->hid->usagePage = capabilities.UsagePage;
|
|
4089
|
-
|
|
4090
|
-
// Fetch string descriptors
|
|
4091
|
-
priv->hid->string_index[0] = dev->device_descriptor.iManufacturer;
|
|
4092
|
-
if (priv->hid->string_index[0] != 0)
|
|
4093
|
-
HidD_GetManufacturerString(hid_handle, priv->hid->string[0], sizeof(priv->hid->string[0]));
|
|
4094
|
-
else
|
|
4095
|
-
priv->hid->string[0][0] = 0;
|
|
4096
|
-
|
|
4097
|
-
priv->hid->string_index[1] = dev->device_descriptor.iProduct;
|
|
4098
|
-
if (priv->hid->string_index[1] != 0)
|
|
4099
|
-
// Using HidD_GetIndexedString() instead of HidD_GetProductString(), as the latter would otherwise return the name
|
|
4100
|
-
// of the interface instead of the iProduct string whenever the iInterface member of the USB_INTERFACE_DESCRIPTOR
|
|
4101
|
-
// structure for the interface is nonzero (see Remarks section in the documentation of the HID API routines)
|
|
4102
|
-
HidD_GetIndexedString(hid_handle, priv->hid->string_index[1], priv->hid->string[1], sizeof(priv->hid->string[1]));
|
|
4103
|
-
else
|
|
4104
|
-
priv->hid->string[1][0] = 0;
|
|
4105
|
-
|
|
4106
|
-
priv->hid->string_index[2] = dev->device_descriptor.iSerialNumber;
|
|
4107
|
-
if (priv->hid->string_index[2] != 0)
|
|
4108
|
-
HidD_GetSerialNumberString(hid_handle, priv->hid->string[2], sizeof(priv->hid->string[2]));
|
|
4109
|
-
else
|
|
4110
|
-
priv->hid->string[2][0] = 0;
|
|
4111
|
-
} while (0);
|
|
4112
|
-
|
|
4113
|
-
if (preparsed_data)
|
|
4114
|
-
HidD_FreePreparsedData(preparsed_data);
|
|
4115
|
-
|
|
4116
|
-
return LIBUSB_SUCCESS;
|
|
4117
|
-
}
|
|
4118
|
-
|
|
4119
|
-
static void hid_close(int sub_api, struct libusb_device_handle *dev_handle)
|
|
4120
|
-
{
|
|
4121
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
4122
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
4123
|
-
HANDLE file_handle;
|
|
4124
|
-
int i;
|
|
4125
|
-
|
|
4126
|
-
UNUSED(sub_api);
|
|
4127
|
-
|
|
4128
|
-
if (DLL_HANDLE_NAME(hid) == NULL)
|
|
4129
|
-
return;
|
|
4130
|
-
|
|
4131
|
-
for (i = 0; i < USB_MAXINTERFACES; i++) {
|
|
4132
|
-
if (priv->usb_interface[i].apib->id == USB_API_HID) {
|
|
4133
|
-
file_handle = handle_priv->interface_handle[i].api_handle;
|
|
4134
|
-
if (HANDLE_VALID(file_handle))
|
|
4135
|
-
CloseHandle(file_handle);
|
|
4136
|
-
}
|
|
4137
|
-
}
|
|
4138
|
-
}
|
|
4139
|
-
|
|
4140
|
-
static int hid_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
|
|
4141
|
-
{
|
|
4142
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
4143
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
4144
|
-
|
|
4145
|
-
UNUSED(sub_api);
|
|
4146
|
-
CHECK_HID_AVAILABLE;
|
|
4147
|
-
|
|
4148
|
-
// NB: Disconnection detection is not possible in this function
|
|
4149
|
-
if (priv->usb_interface[iface].path == NULL)
|
|
4150
|
-
return LIBUSB_ERROR_NOT_FOUND; // invalid iface
|
|
4151
|
-
|
|
4152
|
-
// We use dev_handle as a flag for interface claimed
|
|
4153
|
-
if (handle_priv->interface_handle[iface].dev_handle == INTERFACE_CLAIMED)
|
|
4154
|
-
return LIBUSB_ERROR_BUSY; // already claimed
|
|
4155
|
-
|
|
4156
|
-
handle_priv->interface_handle[iface].dev_handle = INTERFACE_CLAIMED;
|
|
4157
|
-
|
|
4158
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "claimed interface %u", iface);
|
|
4159
|
-
handle_priv->active_interface = iface;
|
|
4160
|
-
|
|
4161
|
-
return LIBUSB_SUCCESS;
|
|
4162
|
-
}
|
|
4163
|
-
|
|
4164
|
-
static int hid_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
|
|
4165
|
-
{
|
|
4166
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
4167
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
4168
|
-
|
|
4169
|
-
UNUSED(sub_api);
|
|
4170
|
-
CHECK_HID_AVAILABLE;
|
|
4171
|
-
|
|
4172
|
-
if (priv->usb_interface[iface].path == NULL)
|
|
4173
|
-
return LIBUSB_ERROR_NOT_FOUND; // invalid iface
|
|
4174
|
-
|
|
4175
|
-
if (handle_priv->interface_handle[iface].dev_handle != INTERFACE_CLAIMED)
|
|
4176
|
-
return LIBUSB_ERROR_NOT_FOUND; // invalid iface
|
|
4177
|
-
|
|
4178
|
-
handle_priv->interface_handle[iface].dev_handle = INVALID_HANDLE_VALUE;
|
|
4179
|
-
|
|
4180
|
-
return LIBUSB_SUCCESS;
|
|
4181
|
-
}
|
|
4182
|
-
|
|
4183
|
-
static int hid_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
|
|
4184
|
-
{
|
|
4185
|
-
UNUSED(sub_api);
|
|
4186
|
-
UNUSED(iface);
|
|
4187
|
-
|
|
4188
|
-
CHECK_HID_AVAILABLE;
|
|
4189
|
-
|
|
4190
|
-
if (altsetting != 0) {
|
|
4191
|
-
usbi_err(HANDLE_CTX(dev_handle), "set interface altsetting not supported for altsetting >0");
|
|
4192
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
4193
|
-
}
|
|
4194
|
-
|
|
4195
|
-
return LIBUSB_SUCCESS;
|
|
4196
|
-
}
|
|
4197
|
-
|
|
4198
|
-
static int hid_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
|
|
4199
|
-
{
|
|
4200
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
4201
|
-
struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
|
|
4202
|
-
struct libusb_device_handle *dev_handle = transfer->dev_handle;
|
|
4203
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
4204
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
4205
|
-
WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer;
|
|
4206
|
-
HANDLE hid_handle;
|
|
4207
|
-
OVERLAPPED *overlapped;
|
|
4208
|
-
int current_interface;
|
|
4209
|
-
uint8_t config;
|
|
4210
|
-
size_t size;
|
|
4211
|
-
int r;
|
|
4212
|
-
|
|
4213
|
-
UNUSED(sub_api);
|
|
4214
|
-
CHECK_HID_AVAILABLE;
|
|
4215
|
-
|
|
4216
|
-
safe_free(transfer_priv->hid_buffer);
|
|
4217
|
-
transfer_priv->hid_dest = NULL;
|
|
4218
|
-
size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
|
|
4219
|
-
|
|
4220
|
-
if (size > MAX_CTRL_BUFFER_LENGTH)
|
|
4221
|
-
return LIBUSB_ERROR_INVALID_PARAM;
|
|
4222
|
-
|
|
4223
|
-
current_interface = get_valid_interface(dev_handle, USB_API_HID);
|
|
4224
|
-
if (current_interface < 0) {
|
|
4225
|
-
if (auto_claim(transfer, ¤t_interface, USB_API_HID) != LIBUSB_SUCCESS)
|
|
4226
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
4227
|
-
}
|
|
4228
|
-
|
|
4229
|
-
usbi_dbg(ITRANSFER_CTX(itransfer), "will use interface %d", current_interface);
|
|
4230
|
-
|
|
4231
|
-
transfer_priv->interface_number = (uint8_t)current_interface;
|
|
4232
|
-
hid_handle = handle_priv->interface_handle[current_interface].api_handle;
|
|
4233
|
-
set_transfer_priv_handle(itransfer, hid_handle);
|
|
4234
|
-
overlapped = get_transfer_priv_overlapped(itransfer);
|
|
4235
|
-
|
|
4236
|
-
switch (LIBUSB_REQ_TYPE(setup->RequestType)) {
|
|
4237
|
-
case LIBUSB_REQUEST_TYPE_STANDARD:
|
|
4238
|
-
switch (setup->Request) {
|
|
4239
|
-
case LIBUSB_REQUEST_GET_DESCRIPTOR:
|
|
4240
|
-
r = _hid_get_descriptor(dev_handle->dev, hid_handle, LIBUSB_REQ_RECIPIENT(setup->RequestType),
|
|
4241
|
-
(setup->Value >> 8) & 0xFF, setup->Value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size);
|
|
4242
|
-
break;
|
|
4243
|
-
case LIBUSB_REQUEST_GET_CONFIGURATION:
|
|
4244
|
-
r = winusb_get_configuration(dev_handle, &config);
|
|
4245
|
-
if (r == LIBUSB_SUCCESS) {
|
|
4246
|
-
size = 1;
|
|
4247
|
-
((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = config;
|
|
4248
|
-
r = LIBUSB_COMPLETED;
|
|
4249
|
-
}
|
|
4250
|
-
break;
|
|
4251
|
-
case LIBUSB_REQUEST_SET_CONFIGURATION:
|
|
4252
|
-
if (setup->Value == priv->active_config) {
|
|
4253
|
-
r = LIBUSB_COMPLETED;
|
|
4254
|
-
} else {
|
|
4255
|
-
usbi_warn(TRANSFER_CTX(transfer), "cannot set configuration other than the default one");
|
|
4256
|
-
r = LIBUSB_ERROR_NOT_SUPPORTED;
|
|
4257
|
-
}
|
|
4258
|
-
break;
|
|
4259
|
-
case LIBUSB_REQUEST_GET_INTERFACE:
|
|
4260
|
-
size = 1;
|
|
4261
|
-
((uint8_t *)transfer->buffer)[LIBUSB_CONTROL_SETUP_SIZE] = 0;
|
|
4262
|
-
r = LIBUSB_COMPLETED;
|
|
4263
|
-
break;
|
|
4264
|
-
case LIBUSB_REQUEST_SET_INTERFACE:
|
|
4265
|
-
r = hid_set_interface_altsetting(0, dev_handle, (uint8_t)setup->Index, (uint8_t)setup->Value);
|
|
4266
|
-
if (r == LIBUSB_SUCCESS)
|
|
4267
|
-
r = LIBUSB_COMPLETED;
|
|
4268
|
-
break;
|
|
4269
|
-
default:
|
|
4270
|
-
usbi_warn(TRANSFER_CTX(transfer), "unsupported HID control request");
|
|
4271
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
4272
|
-
}
|
|
4273
|
-
break;
|
|
4274
|
-
case LIBUSB_REQUEST_TYPE_CLASS:
|
|
4275
|
-
r = _hid_class_request(dev_handle->dev, hid_handle, setup->RequestType, setup->Request, setup->Value,
|
|
4276
|
-
setup->Index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, transfer_priv,
|
|
4277
|
-
size, overlapped);
|
|
4278
|
-
break;
|
|
4279
|
-
default:
|
|
4280
|
-
usbi_warn(TRANSFER_CTX(transfer), "unsupported HID control request");
|
|
4281
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
4282
|
-
}
|
|
4283
|
-
|
|
4284
|
-
if (r < 0)
|
|
4285
|
-
return r;
|
|
4286
|
-
|
|
4287
|
-
if (r == LIBUSB_COMPLETED) {
|
|
4288
|
-
// Force request to be completed synchronously. Transferred size has been set by previous call
|
|
4289
|
-
windows_force_sync_completion(itransfer, (ULONG)size);
|
|
4290
|
-
r = LIBUSB_SUCCESS;
|
|
4291
|
-
}
|
|
4292
|
-
|
|
4293
|
-
return LIBUSB_SUCCESS;
|
|
4294
|
-
}
|
|
4295
|
-
|
|
4296
|
-
static int hid_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer)
|
|
4297
|
-
{
|
|
4298
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
4299
|
-
struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
|
|
4300
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
|
|
4301
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
4302
|
-
HANDLE hid_handle;
|
|
4303
|
-
OVERLAPPED *overlapped;
|
|
4304
|
-
bool direction_in;
|
|
4305
|
-
BOOL ret;
|
|
4306
|
-
int current_interface, length;
|
|
4307
|
-
|
|
4308
|
-
UNUSED(sub_api);
|
|
4309
|
-
CHECK_HID_AVAILABLE;
|
|
4310
|
-
|
|
4311
|
-
if (IS_XFEROUT(transfer) && (transfer->flags & LIBUSB_TRANSFER_ADD_ZERO_PACKET))
|
|
4312
|
-
return LIBUSB_ERROR_NOT_SUPPORTED;
|
|
4313
|
-
|
|
4314
|
-
transfer_priv->hid_dest = NULL;
|
|
4315
|
-
safe_free(transfer_priv->hid_buffer);
|
|
4316
|
-
|
|
4317
|
-
current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
|
|
4318
|
-
if (current_interface < 0) {
|
|
4319
|
-
usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
|
|
4320
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
4321
|
-
}
|
|
4322
|
-
|
|
4323
|
-
usbi_dbg(TRANSFER_CTX(transfer), "matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
|
|
4324
|
-
|
|
4325
|
-
transfer_priv->interface_number = (uint8_t)current_interface;
|
|
4326
|
-
hid_handle = handle_priv->interface_handle[current_interface].api_handle;
|
|
4327
|
-
set_transfer_priv_handle(itransfer, hid_handle);
|
|
4328
|
-
overlapped = get_transfer_priv_overlapped(itransfer);
|
|
4329
|
-
direction_in = IS_XFERIN(transfer);
|
|
4330
|
-
|
|
4331
|
-
// If report IDs are not in use, an extra prefix byte must be added
|
|
4332
|
-
if (((direction_in) && (!priv->hid->uses_report_ids[0]))
|
|
4333
|
-
|| ((!direction_in) && (!priv->hid->uses_report_ids[1])))
|
|
4334
|
-
length = transfer->length + 1;
|
|
4335
|
-
else
|
|
4336
|
-
length = transfer->length;
|
|
4337
|
-
|
|
4338
|
-
// Add a trailing byte to detect overflows on input
|
|
4339
|
-
transfer_priv->hid_buffer = calloc(1, length + 1);
|
|
4340
|
-
if (transfer_priv->hid_buffer == NULL)
|
|
4341
|
-
return LIBUSB_ERROR_NO_MEM;
|
|
4342
|
-
|
|
4343
|
-
transfer_priv->hid_expected_size = length;
|
|
4344
|
-
|
|
4345
|
-
if (direction_in) {
|
|
4346
|
-
transfer_priv->hid_dest = transfer->buffer;
|
|
4347
|
-
usbi_dbg(TRANSFER_CTX(transfer), "reading %d bytes (report ID: 0x00)", length);
|
|
4348
|
-
ret = ReadFile(hid_handle, transfer_priv->hid_buffer, length + 1, NULL, overlapped);
|
|
4349
|
-
} else {
|
|
4350
|
-
if (!priv->hid->uses_report_ids[1])
|
|
4351
|
-
memcpy(transfer_priv->hid_buffer + 1, transfer->buffer, transfer->length);
|
|
4352
|
-
else
|
|
4353
|
-
// We could actually do without the calloc and memcpy in this case
|
|
4354
|
-
memcpy(transfer_priv->hid_buffer, transfer->buffer, transfer->length);
|
|
4355
|
-
|
|
4356
|
-
usbi_dbg(TRANSFER_CTX(transfer), "writing %d bytes (report ID: 0x%02X)", length, transfer_priv->hid_buffer[0]);
|
|
4357
|
-
ret = WriteFile(hid_handle, transfer_priv->hid_buffer, length, NULL, overlapped);
|
|
4358
|
-
}
|
|
4359
|
-
|
|
4360
|
-
if (!ret && GetLastError() != ERROR_IO_PENDING) {
|
|
4361
|
-
usbi_err(TRANSFER_CTX(transfer), "HID transfer failed: %s", windows_error_str(0));
|
|
4362
|
-
safe_free(transfer_priv->hid_buffer);
|
|
4363
|
-
return LIBUSB_ERROR_IO;
|
|
4364
|
-
}
|
|
4365
|
-
|
|
4366
|
-
return LIBUSB_SUCCESS;
|
|
4367
|
-
}
|
|
4368
|
-
|
|
4369
|
-
static int hid_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
|
|
4370
|
-
{
|
|
4371
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
4372
|
-
HANDLE hid_handle;
|
|
4373
|
-
int current_interface;
|
|
4374
|
-
|
|
4375
|
-
UNUSED(sub_api);
|
|
4376
|
-
CHECK_HID_AVAILABLE;
|
|
4377
|
-
|
|
4378
|
-
// Flushing the queues on all interfaces is the best we can achieve
|
|
4379
|
-
for (current_interface = 0; current_interface < USB_MAXINTERFACES; current_interface++) {
|
|
4380
|
-
hid_handle = handle_priv->interface_handle[current_interface].api_handle;
|
|
4381
|
-
if (HANDLE_VALID(hid_handle))
|
|
4382
|
-
HidD_FlushQueue(hid_handle);
|
|
4383
|
-
}
|
|
4384
|
-
|
|
4385
|
-
return LIBUSB_SUCCESS;
|
|
4386
|
-
}
|
|
4387
|
-
|
|
4388
|
-
static int hid_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
|
|
4389
|
-
{
|
|
4390
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
4391
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
4392
|
-
HANDLE hid_handle;
|
|
4393
|
-
int current_interface;
|
|
4394
|
-
|
|
4395
|
-
UNUSED(sub_api);
|
|
4396
|
-
CHECK_HID_AVAILABLE;
|
|
4397
|
-
|
|
4398
|
-
current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
|
|
4399
|
-
if (current_interface < 0) {
|
|
4400
|
-
usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot clear");
|
|
4401
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
4402
|
-
}
|
|
4403
|
-
|
|
4404
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "matched endpoint %02X with interface %d", endpoint, current_interface);
|
|
4405
|
-
hid_handle = handle_priv->interface_handle[current_interface].api_handle;
|
|
4406
|
-
|
|
4407
|
-
// No endpoint selection with Microsoft's implementation, so we try to flush the
|
|
4408
|
-
// whole interface. Should be OK for most case scenarios
|
|
4409
|
-
if (!HidD_FlushQueue(hid_handle)) {
|
|
4410
|
-
usbi_err(HANDLE_CTX(dev_handle), "Flushing of HID queue failed: %s", windows_error_str(0));
|
|
4411
|
-
// Device was probably disconnected
|
|
4412
|
-
return LIBUSB_ERROR_NO_DEVICE;
|
|
4413
|
-
}
|
|
4414
|
-
|
|
4415
|
-
return LIBUSB_SUCCESS;
|
|
4416
|
-
}
|
|
4417
|
-
|
|
4418
|
-
// This extra function is only needed for HID
|
|
4419
|
-
static enum libusb_transfer_status hid_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length)
|
|
4420
|
-
{
|
|
4421
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
4422
|
-
struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
|
|
4423
|
-
enum libusb_transfer_status r = LIBUSB_TRANSFER_COMPLETED;
|
|
4424
|
-
|
|
4425
|
-
UNUSED(sub_api);
|
|
4426
|
-
|
|
4427
|
-
if (transfer_priv->hid_buffer != NULL) {
|
|
4428
|
-
// If we have a valid hid_buffer, it means the transfer was async
|
|
4429
|
-
if (transfer_priv->hid_dest != NULL) { // Data readout
|
|
4430
|
-
if (length > 0) {
|
|
4431
|
-
// First, check for overflow
|
|
4432
|
-
if ((size_t)length > transfer_priv->hid_expected_size) {
|
|
4433
|
-
usbi_err(TRANSFER_CTX(transfer), "OVERFLOW!");
|
|
4434
|
-
length = (DWORD)transfer_priv->hid_expected_size;
|
|
4435
|
-
r = LIBUSB_TRANSFER_OVERFLOW;
|
|
4436
|
-
}
|
|
4437
|
-
|
|
4438
|
-
if (transfer_priv->hid_buffer[0] == 0) {
|
|
4439
|
-
memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer + 1, length);
|
|
4440
|
-
} else {
|
|
4441
|
-
memcpy(transfer_priv->hid_dest, transfer_priv->hid_buffer, length);
|
|
4442
|
-
}
|
|
4443
|
-
}
|
|
4444
|
-
transfer_priv->hid_dest = NULL;
|
|
4445
|
-
}
|
|
4446
|
-
// For write, we just need to free the hid buffer
|
|
4447
|
-
safe_free(transfer_priv->hid_buffer);
|
|
4448
|
-
}
|
|
4449
|
-
|
|
4450
|
-
itransfer->transferred += (int)length;
|
|
4451
|
-
return r;
|
|
4452
|
-
}
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
/*
|
|
4456
|
-
* Composite API functions
|
|
4457
|
-
*/
|
|
4458
|
-
static int composite_open(int sub_api, struct libusb_device_handle *dev_handle)
|
|
4459
|
-
{
|
|
4460
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
4461
|
-
int i, r = LIBUSB_ERROR_NOT_FOUND;
|
|
4462
|
-
// SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID
|
|
4463
|
-
bool available[SUB_API_MAX + 1];
|
|
4464
|
-
|
|
4465
|
-
UNUSED(sub_api);
|
|
4466
|
-
|
|
4467
|
-
for (i = 0; i < SUB_API_MAX + 1; i++)
|
|
4468
|
-
available[i] = false;
|
|
4469
|
-
|
|
4470
|
-
for (i = 0; i < USB_MAXINTERFACES; i++) {
|
|
4471
|
-
switch (priv->usb_interface[i].apib->id) {
|
|
4472
|
-
case USB_API_WINUSBX:
|
|
4473
|
-
if (priv->usb_interface[i].sub_api != SUB_API_NOTSET)
|
|
4474
|
-
available[priv->usb_interface[i].sub_api] = true;
|
|
4475
|
-
break;
|
|
4476
|
-
case USB_API_HID:
|
|
4477
|
-
available[SUB_API_MAX] = true;
|
|
4478
|
-
break;
|
|
4479
|
-
default:
|
|
4480
|
-
break;
|
|
4481
|
-
}
|
|
4482
|
-
}
|
|
4483
|
-
|
|
4484
|
-
for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers
|
|
4485
|
-
if (available[i]) {
|
|
4486
|
-
r = usb_api_backend[USB_API_WINUSBX].open(i, dev_handle);
|
|
4487
|
-
if (r != LIBUSB_SUCCESS)
|
|
4488
|
-
return r;
|
|
4489
|
-
}
|
|
4490
|
-
}
|
|
4491
|
-
|
|
4492
|
-
if (available[SUB_API_MAX]) { // HID driver
|
|
4493
|
-
r = hid_open(SUB_API_NOTSET, dev_handle);
|
|
4494
|
-
|
|
4495
|
-
// On Windows 10 version 1903 (OS Build 18362) and later Windows blocks attempts to
|
|
4496
|
-
// open HID devices with a U2F usage unless running as administrator. We ignore this
|
|
4497
|
-
// failure and proceed without the HID device opened.
|
|
4498
|
-
if (r == LIBUSB_ERROR_ACCESS) {
|
|
4499
|
-
usbi_dbg(HANDLE_CTX(dev_handle), "ignoring access denied error while opening HID interface of composite device");
|
|
4500
|
-
r = LIBUSB_SUCCESS;
|
|
4501
|
-
}
|
|
4502
|
-
}
|
|
4503
|
-
|
|
4504
|
-
return r;
|
|
4505
|
-
}
|
|
4506
|
-
|
|
4507
|
-
static void composite_close(int sub_api, struct libusb_device_handle *dev_handle)
|
|
4508
|
-
{
|
|
4509
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
4510
|
-
int i;
|
|
4511
|
-
// SUB_API_MAX + 1 as the SUB_API_MAX pos is used to indicate availability of HID
|
|
4512
|
-
bool available[SUB_API_MAX + 1];
|
|
4513
|
-
|
|
4514
|
-
UNUSED(sub_api);
|
|
4515
|
-
|
|
4516
|
-
for (i = 0; i < SUB_API_MAX + 1; i++)
|
|
4517
|
-
available[i] = false;
|
|
4518
|
-
|
|
4519
|
-
for (i = 0; i < USB_MAXINTERFACES; i++) {
|
|
4520
|
-
switch (priv->usb_interface[i].apib->id) {
|
|
4521
|
-
case USB_API_WINUSBX:
|
|
4522
|
-
if (priv->usb_interface[i].sub_api != SUB_API_NOTSET)
|
|
4523
|
-
available[priv->usb_interface[i].sub_api] = true;
|
|
4524
|
-
break;
|
|
4525
|
-
case USB_API_HID:
|
|
4526
|
-
available[SUB_API_MAX] = true;
|
|
4527
|
-
break;
|
|
4528
|
-
default:
|
|
4529
|
-
break;
|
|
4530
|
-
}
|
|
4531
|
-
}
|
|
4532
|
-
|
|
4533
|
-
for (i = 0; i < SUB_API_MAX; i++) { // WinUSB-like drivers
|
|
4534
|
-
if (available[i])
|
|
4535
|
-
usb_api_backend[USB_API_WINUSBX].close(i, dev_handle);
|
|
4536
|
-
}
|
|
4537
|
-
|
|
4538
|
-
if (available[SUB_API_MAX]) // HID driver
|
|
4539
|
-
hid_close(SUB_API_NOTSET, dev_handle);
|
|
4540
|
-
}
|
|
4541
|
-
|
|
4542
|
-
static int composite_claim_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
|
|
4543
|
-
{
|
|
4544
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
4545
|
-
|
|
4546
|
-
UNUSED(sub_api);
|
|
4547
|
-
CHECK_SUPPORTED_API(priv->usb_interface[iface].apib, claim_interface);
|
|
4548
|
-
|
|
4549
|
-
return priv->usb_interface[iface].apib->
|
|
4550
|
-
claim_interface(priv->usb_interface[iface].sub_api, dev_handle, iface);
|
|
4551
|
-
}
|
|
4552
|
-
|
|
4553
|
-
static int composite_set_interface_altsetting(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface, uint8_t altsetting)
|
|
4554
|
-
{
|
|
4555
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
4556
|
-
|
|
4557
|
-
UNUSED(sub_api);
|
|
4558
|
-
CHECK_SUPPORTED_API(priv->usb_interface[iface].apib, set_interface_altsetting);
|
|
4559
|
-
|
|
4560
|
-
return priv->usb_interface[iface].apib->
|
|
4561
|
-
set_interface_altsetting(priv->usb_interface[iface].sub_api, dev_handle, iface, altsetting);
|
|
4562
|
-
}
|
|
4563
|
-
|
|
4564
|
-
static int composite_release_interface(int sub_api, struct libusb_device_handle *dev_handle, uint8_t iface)
|
|
4565
|
-
{
|
|
4566
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
4567
|
-
|
|
4568
|
-
UNUSED(sub_api);
|
|
4569
|
-
CHECK_SUPPORTED_API(priv->usb_interface[iface].apib, release_interface);
|
|
4570
|
-
|
|
4571
|
-
return priv->usb_interface[iface].apib->
|
|
4572
|
-
release_interface(priv->usb_interface[iface].sub_api, dev_handle, iface);
|
|
4573
|
-
}
|
|
4574
|
-
|
|
4575
|
-
static int composite_submit_control_transfer(int sub_api, struct usbi_transfer *itransfer)
|
|
4576
|
-
{
|
|
4577
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
4578
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
4579
|
-
struct libusb_config_descriptor *conf_desc;
|
|
4580
|
-
WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *)transfer->buffer;
|
|
4581
|
-
int iface, pass, r;
|
|
4582
|
-
|
|
4583
|
-
UNUSED(sub_api);
|
|
4584
|
-
|
|
4585
|
-
// Interface shouldn't matter for control, but it does in practice, with Windows'
|
|
4586
|
-
// restrictions with regards to accessing HID keyboards and mice. Try to target
|
|
4587
|
-
// a specific interface first, if possible.
|
|
4588
|
-
switch (LIBUSB_REQ_RECIPIENT(setup->RequestType)) {
|
|
4589
|
-
case LIBUSB_RECIPIENT_INTERFACE:
|
|
4590
|
-
iface = setup->Index & 0xFF;
|
|
4591
|
-
break;
|
|
4592
|
-
case LIBUSB_RECIPIENT_ENDPOINT:
|
|
4593
|
-
r = libusb_get_active_config_descriptor(transfer->dev_handle->dev, &conf_desc);
|
|
4594
|
-
if (r == LIBUSB_SUCCESS) {
|
|
4595
|
-
iface = get_interface_by_endpoint(conf_desc, (setup->Index & 0xFF));
|
|
4596
|
-
libusb_free_config_descriptor(conf_desc);
|
|
4597
|
-
break;
|
|
4598
|
-
}
|
|
4599
|
-
// No break if not able to determine interface
|
|
4600
|
-
// Fall through
|
|
4601
|
-
default:
|
|
4602
|
-
iface = -1;
|
|
4603
|
-
break;
|
|
4604
|
-
}
|
|
4605
|
-
|
|
4606
|
-
// Try and target a specific interface if the control setup indicates such
|
|
4607
|
-
if ((iface >= 0) && (iface < USB_MAXINTERFACES)) {
|
|
4608
|
-
usbi_dbg(TRANSFER_CTX(transfer), "attempting control transfer targeted to interface %d", iface);
|
|
4609
|
-
if ((priv->usb_interface[iface].path != NULL)
|
|
4610
|
-
&& (priv->usb_interface[iface].apib->submit_control_transfer != NULL)) {
|
|
4611
|
-
r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer);
|
|
4612
|
-
if (r == LIBUSB_SUCCESS)
|
|
4613
|
-
return r;
|
|
4614
|
-
}
|
|
4615
|
-
}
|
|
4616
|
-
|
|
4617
|
-
// Either not targeted to a specific interface or no luck in doing so.
|
|
4618
|
-
// Try a 2 pass approach with all interfaces.
|
|
4619
|
-
for (pass = 0; pass < 2; pass++) {
|
|
4620
|
-
for (iface = 0; iface < USB_MAXINTERFACES; iface++) {
|
|
4621
|
-
if ((priv->usb_interface[iface].path != NULL)
|
|
4622
|
-
&& (priv->usb_interface[iface].apib->submit_control_transfer != NULL)) {
|
|
4623
|
-
if ((pass == 0) && (priv->usb_interface[iface].restricted_functionality)) {
|
|
4624
|
-
usbi_dbg(TRANSFER_CTX(transfer), "trying to skip restricted interface #%d (HID keyboard or mouse?)", iface);
|
|
4625
|
-
continue;
|
|
4626
|
-
}
|
|
4627
|
-
usbi_dbg(TRANSFER_CTX(transfer), "using interface %d", iface);
|
|
4628
|
-
r = priv->usb_interface[iface].apib->submit_control_transfer(priv->usb_interface[iface].sub_api, itransfer);
|
|
4629
|
-
// If not supported on this API, it may be supported on another, so don't give up yet!!
|
|
4630
|
-
if (r == LIBUSB_ERROR_NOT_SUPPORTED)
|
|
4631
|
-
continue;
|
|
4632
|
-
return r;
|
|
4633
|
-
}
|
|
4634
|
-
}
|
|
4635
|
-
}
|
|
4636
|
-
|
|
4637
|
-
usbi_err(TRANSFER_CTX(transfer), "no libusb supported interfaces to complete request");
|
|
4638
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
4639
|
-
}
|
|
4640
|
-
|
|
4641
|
-
static int composite_submit_bulk_transfer(int sub_api, struct usbi_transfer *itransfer)
|
|
4642
|
-
{
|
|
4643
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
4644
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
|
|
4645
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
4646
|
-
int current_interface;
|
|
4647
|
-
|
|
4648
|
-
UNUSED(sub_api);
|
|
4649
|
-
|
|
4650
|
-
current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
|
|
4651
|
-
if (current_interface < 0) {
|
|
4652
|
-
usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
|
|
4653
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
4654
|
-
}
|
|
4655
|
-
|
|
4656
|
-
CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, submit_bulk_transfer);
|
|
4657
|
-
|
|
4658
|
-
return priv->usb_interface[current_interface].apib->
|
|
4659
|
-
submit_bulk_transfer(priv->usb_interface[current_interface].sub_api, itransfer);
|
|
4660
|
-
}
|
|
4661
|
-
|
|
4662
|
-
static int composite_submit_iso_transfer(int sub_api, struct usbi_transfer *itransfer)
|
|
4663
|
-
{
|
|
4664
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
4665
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(transfer->dev_handle);
|
|
4666
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
4667
|
-
int current_interface;
|
|
4668
|
-
|
|
4669
|
-
UNUSED(sub_api);
|
|
4670
|
-
|
|
4671
|
-
current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
|
|
4672
|
-
if (current_interface < 0) {
|
|
4673
|
-
usbi_err(TRANSFER_CTX(transfer), "unable to match endpoint to an open interface - cancelling transfer");
|
|
4674
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
4675
|
-
}
|
|
4676
|
-
|
|
4677
|
-
CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, submit_iso_transfer);
|
|
4678
|
-
|
|
4679
|
-
return priv->usb_interface[current_interface].apib->
|
|
4680
|
-
submit_iso_transfer(priv->usb_interface[current_interface].sub_api, itransfer);
|
|
4681
|
-
}
|
|
4682
|
-
|
|
4683
|
-
static int composite_clear_halt(int sub_api, struct libusb_device_handle *dev_handle, unsigned char endpoint)
|
|
4684
|
-
{
|
|
4685
|
-
struct winusb_device_handle_priv *handle_priv = get_winusb_device_handle_priv(dev_handle);
|
|
4686
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
4687
|
-
int current_interface;
|
|
4688
|
-
|
|
4689
|
-
UNUSED(sub_api);
|
|
4690
|
-
|
|
4691
|
-
current_interface = interface_by_endpoint(priv, handle_priv, endpoint);
|
|
4692
|
-
if (current_interface < 0) {
|
|
4693
|
-
usbi_err(HANDLE_CTX(dev_handle), "unable to match endpoint to an open interface - cannot clear");
|
|
4694
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
4695
|
-
}
|
|
4696
|
-
|
|
4697
|
-
CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, clear_halt);
|
|
4698
|
-
|
|
4699
|
-
return priv->usb_interface[current_interface].apib->
|
|
4700
|
-
clear_halt(priv->usb_interface[current_interface].sub_api, dev_handle, endpoint);
|
|
4701
|
-
}
|
|
4702
|
-
|
|
4703
|
-
static int composite_cancel_transfer(int sub_api, struct usbi_transfer *itransfer)
|
|
4704
|
-
{
|
|
4705
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
4706
|
-
struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
|
|
4707
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
4708
|
-
int current_interface = transfer_priv->interface_number;
|
|
4709
|
-
|
|
4710
|
-
UNUSED(sub_api);
|
|
4711
|
-
|
|
4712
|
-
if ((current_interface < 0) || (current_interface >= USB_MAXINTERFACES)) {
|
|
4713
|
-
usbi_err(TRANSFER_CTX(transfer), "program assertion failed - invalid interface_number");
|
|
4714
|
-
return LIBUSB_ERROR_NOT_FOUND;
|
|
4715
|
-
}
|
|
4716
|
-
|
|
4717
|
-
CHECK_SUPPORTED_API(priv->usb_interface[current_interface].apib, cancel_transfer);
|
|
4718
|
-
|
|
4719
|
-
return priv->usb_interface[current_interface].apib->
|
|
4720
|
-
cancel_transfer(priv->usb_interface[current_interface].sub_api, itransfer);
|
|
4721
|
-
}
|
|
4722
|
-
|
|
4723
|
-
static int composite_reset_device(int sub_api, struct libusb_device_handle *dev_handle)
|
|
4724
|
-
{
|
|
4725
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(dev_handle->dev);
|
|
4726
|
-
int i, r;
|
|
4727
|
-
bool available[SUB_API_MAX];
|
|
4728
|
-
|
|
4729
|
-
UNUSED(sub_api);
|
|
4730
|
-
|
|
4731
|
-
for (i = 0; i < SUB_API_MAX; i++)
|
|
4732
|
-
available[i] = false;
|
|
4733
|
-
|
|
4734
|
-
for (i = 0; i < USB_MAXINTERFACES; i++) {
|
|
4735
|
-
if ((priv->usb_interface[i].apib->id == USB_API_WINUSBX)
|
|
4736
|
-
&& (priv->usb_interface[i].sub_api != SUB_API_NOTSET))
|
|
4737
|
-
available[priv->usb_interface[i].sub_api] = true;
|
|
4738
|
-
}
|
|
4739
|
-
|
|
4740
|
-
for (i = 0; i < SUB_API_MAX; i++) {
|
|
4741
|
-
if (available[i]) {
|
|
4742
|
-
r = usb_api_backend[USB_API_WINUSBX].reset_device(i, dev_handle);
|
|
4743
|
-
if (r != LIBUSB_SUCCESS)
|
|
4744
|
-
return r;
|
|
4745
|
-
}
|
|
4746
|
-
}
|
|
4747
|
-
|
|
4748
|
-
return LIBUSB_SUCCESS;
|
|
4749
|
-
}
|
|
4750
|
-
|
|
4751
|
-
static enum libusb_transfer_status composite_copy_transfer_data(int sub_api, struct usbi_transfer *itransfer, DWORD length)
|
|
4752
|
-
{
|
|
4753
|
-
struct libusb_transfer *transfer = USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
|
|
4754
|
-
struct winusb_transfer_priv *transfer_priv = get_winusb_transfer_priv(itransfer);
|
|
4755
|
-
struct winusb_device_priv *priv = usbi_get_device_priv(transfer->dev_handle->dev);
|
|
4756
|
-
int current_interface = transfer_priv->interface_number;
|
|
4757
|
-
|
|
4758
|
-
UNUSED(sub_api);
|
|
4759
|
-
if (priv->usb_interface[current_interface].apib->copy_transfer_data == NULL) {
|
|
4760
|
-
usbi_err(TRANSFER_CTX(transfer), "program assertion failed - no function to copy transfer data");
|
|
4761
|
-
return LIBUSB_TRANSFER_ERROR;
|
|
4762
|
-
}
|
|
4763
|
-
|
|
4764
|
-
return priv->usb_interface[current_interface].apib->
|
|
4765
|
-
copy_transfer_data(priv->usb_interface[current_interface].sub_api, itransfer, length);
|
|
4766
|
-
}
|