summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPete Batard <pbatard@gmail.com>2010-01-18 20:32:38 +0000
committerPete Batard <pbatard@gmail.com>2010-01-18 20:32:38 +0000
commit7a8f7d1826c754aed2a4ae5f369b8882cc4cb884 (patch)
tree95e4b7cfe4bc9999d196974eb4f23d5ce9f4b1bd
parent2012ca7b23b2199022c51e84ca1d82838a9a570c (diff)
downloadlibusb-7a8f7d1826c754aed2a4ae5f369b8882cc4cb884.tar.gz
r89: extended API support
- composite devices as a separate backend API - mutidriver support in composite devices interface - HID: device interface path, open/close (WIP) - added HID test in xusb.c - fixed Windows version and DDK support - smaller fixes
-rw-r--r--README_MSVC.txt6
-rw-r--r--examples/xusb.c10
-rw-r--r--libusb/os/windows_usb.c663
-rw-r--r--libusb/os/windows_usb.h84
4 files changed, 635 insertions, 128 deletions
diff --git a/README_MSVC.txt b/README_MSVC.txt
index 1b59b73..2885364 100644
--- a/README_MSVC.txt
+++ b/README_MSVC.txt
@@ -1,4 +1,4 @@
-To compile libusb 1.0 using MSVC 9:
+To compile libusb 1.0 using Microsoft Visual Studio:
Note: in the text below, (Win32) means "when producing 32 bit binaries" and
(x64) "when producing 64 bit binaries". This is independent of whether your
@@ -21,8 +21,8 @@ platform is actually 32 or 64 bit.
http://sourceware.org/pthreads-win32/ and create both a pthreadVC2_x64.lib
and pthreadVC2_x64.dll from the latest pthread-win32 source.
- To help compiling pthreadVC2_x64.dll on x64 platforms, sample .sln and .vcproj
- files for pthread-win32 are provided in the msvc\pthread-win32_x64\ directory.
+ To help compiling pthreadVC2_x64.dll on x64 platforms, sample .sln and
+ .vcproj files are provided in the msvc\pthread-win32_x64\ directory.
- (x64) Copy pthreadVC2_x64.lib to the msvc directory.
diff --git a/examples/xusb.c b/examples/xusb.c
index 4775194..ecb6070 100644
--- a/examples/xusb.c
+++ b/examples/xusb.c
@@ -116,6 +116,7 @@ enum test_type {
USE_XBOX,
USE_KEY,
USE_JTAG,
+ USE_HID,
} test_mode;
uint16_t VID, PID;
@@ -448,14 +449,21 @@ int main(int argc, char** argv)
if (argc == 2) {
if ((argv[1][0] != '-') || (argv[1][1] == 'h')) {
- printf("usage: %s [-h] [-j] [-k] [-x]\n", argv[0]);
+ printf("usage: %s [-h] [-i] [-j] [-k] [-x]\n", argv[0]);
printf(" -h: display usage\n");
+ printf(" -i: test IBM HID Optical Mouse\n");
printf(" -j: test OLIMEX ARM-USB-TINY JTAG, 2 channel composite device\n");
printf(" -k: test Generic 2 GB USB Key\n");
printf(" -x: test Microsoft XBox Controller Type S (default)\n");
return 0;
}
switch(argv[1][1]) {
+ case 'i':
+ // IBM HID Optical mouse - 1 interface
+ VID = 0x04B3;
+ PID = 0x3108;
+ test_mode = USE_HID;
+ break;
case 'j':
// OLIMEX ARM-USB-TINY JTAG, 2 channel composite device - 2 interfaces
VID = 0x15BA;
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index 1962391..4ebfcaf 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -17,13 +17,10 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+
+// If using Visual Studio 2008 or earlier, Windows 7 is not defined...
#if defined(_MSC_VER)
-// If the following is true, then Microsoft provided an improper WINVER
-// to Visual Studio 2008 on Windows 7. Both should be set to 0x601
-#if (WINVER <= _WIN32_WINNT_LONGHORN) && (WINVER >= _WIN32_WINNT_WIN7)
-#undef WINVER
-#define WINVER 0x601
-#undef _WIN32_WINNT_WIN7
+#if !defined(_WIN32_WINNT_WIN7)
#define _WIN32_WINNT_WIN7 0x601
#endif
#include <config_msvc.h>
@@ -39,13 +36,8 @@
#include <windows.h>
#include <setupapi.h>
#if defined(_MSC_VER)
-// Fixes DDK errors
-#if !defined __drv_maxIRQL
-#define __drv_maxIRQL(x)
-#endif
-#if !defined __drv_preferredFunction
-#define __drv_preferredFunction(func,why)
-#endif
+#include <api/sal_supp.h>
+#include <api/driverspecs.h>
#include <api/usbiodef.h>
#include <api/usbioctl.h>
#include <api/cfgmgr32.h>
@@ -85,8 +77,8 @@
static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian);
static int windows_clock_gettime(int clk_id, struct timespec *tp);
// WinUSB API prototypes
-static int winusb_api_init(struct libusb_context *ctx);
-static int winusb_api_exit(void);
+static int winusb_init(struct libusb_context *ctx);
+static int winusb_exit(void);
static int winusb_open(struct libusb_device_handle *dev_handle);
static void winusb_close(struct libusb_device_handle *dev_handle);
static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int iface);
@@ -99,6 +91,29 @@ static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned c
static int winusb_abort_transfers(struct usbi_transfer *itransfer);
static int winusb_abort_control(struct usbi_transfer *itransfer);
static int winusb_reset_device(struct libusb_device_handle *dev_handle);
+// HID API prototypes
+static int hid_init(struct libusb_context *ctx);
+static int hid_exit(void);
+static int hid_open(struct libusb_device_handle *dev_handle);
+static void hid_close(struct libusb_device_handle *dev_handle);
+//static int hid_claim_interface(struct libusb_device_handle *dev_handle, int iface);
+//static int hid_release_interface(struct libusb_device_handle *dev_handle, int iface);
+// Composite API prototypes
+static int composite_init(struct libusb_context *ctx);
+static int composite_exit(void);
+static int composite_open(struct libusb_device_handle *dev_handle);
+static void composite_close(struct libusb_device_handle *dev_handle);
+static int composite_claim_interface(struct libusb_device_handle *dev_handle, int iface);
+static int composite_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting);
+static int composite_release_interface(struct libusb_device_handle *dev_handle, int iface);
+static int composite_submit_control_transfer(struct usbi_transfer *itransfer);
+static int composite_submit_bulk_transfer(struct usbi_transfer *itransfer);
+static int composite_submit_iso_transfer(struct usbi_transfer *itransfer);
+static int composite_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint);
+static int composite_abort_transfers(struct usbi_transfer *itransfer);
+static int composite_abort_control(struct usbi_transfer *itransfer);
+static int composite_reset_device(struct libusb_device_handle *dev_handle);
+
// Global variables
struct windows_hcd_priv* hcd_root = NULL;
@@ -106,9 +121,12 @@ uint64_t hires_frequency, hires_ticks_to_ps;
const uint64_t epoch_time = 116444736000000000; // 1970.01.01 00:00:000 in MS Filetime
DWORD_PTR old_affinity_mask;
enum windows_version windows_version = WINDOWS_UNSUPPORTED;
-// WinUSB globals
+// API globals
bool api_winusb_available = false;
#define CHECK_WINUSB_AVAILABLE do { if (!api_winusb_available) return LIBUSB_ERROR_ACCESS; } while (0)
+bool api_hid_available = false;
+#define CHECK_HID_AVAILABLE do { if (!api_hid_available) return LIBUSB_ERROR_ACCESS; } while (0)
+
/*
* Converts a WCHAR string to UTF8 (allocate returned string)
@@ -314,7 +332,7 @@ static int windows_init(struct libusb_context *ctx)
SP_DEVICE_INTERFACE_DETAIL_DATA *dev_interface_details = NULL;
GUID guid;
libusb_bus_t bus;
- int r = LIBUSB_SUCCESS;
+ int i, r = LIBUSB_SUCCESS;
LARGE_INTEGER li_frequency;
OSVERSIONINFO os_version;
@@ -347,9 +365,11 @@ static int windows_init(struct libusb_context *ctx)
init_polling();
// Initialize the low level APIs
- r = winusb_api_init(ctx);
- if (r != LIBUSB_SUCCESS) {
- return r;
+ for (i=0; i<USB_API_MAX; i++) {
+ r = usb_api_backend[i].init(ctx);
+ if (r != LIBUSB_SUCCESS) {
+ return r;
+ }
}
// Because QueryPerformanceCounter might report different values when
@@ -436,7 +456,6 @@ static int initialize_device(struct libusb_device *dev, libusb_bus_t busnum,
// a driver issue => report this
// TODO: use this for automated driver installation
// TODO: can we get an error code to confirm from SetupDiWhatever?
- priv->driver = safe_strdup("no_driver");
usbi_dbg("* DRIVERLESS DEVICE *");
}
@@ -779,8 +798,6 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs
// Finally, if device is a hub, recurse
if (conn_info.DeviceIsHub) {
- // Force the driver name
- priv->driver = safe_strdup("usbhub");
// Find number of ports for this hub
size = sizeof(USB_NODE_INFORMATION);
if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_INFORMATION, &hub_node, size,
@@ -812,7 +829,7 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs
static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, struct windows_device_priv *priv)
{
DEVINST child_devinst;
- int i, j, max_guids, nb_paths, interface_number;
+ unsigned i, j, api, max_guids, nb_paths, interface_number;
bool found;
DWORD type, size;
CONFIGRET r;
@@ -824,6 +841,7 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str
GUID guid;
GUID guid_table[MAX_USB_DEVICES];
char* sanitized_path[MAX_USB_DEVICES];
+ uint8_t api_type[MAX_USB_DEVICES];
char* sanitized_short = NULL;
char path[MAX_PATH_LENGTH];
char driver[MAX_KEY_LENGTH];
@@ -903,11 +921,14 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str
continue;
}
- if (safe_strcmp(driver, "WinUSB") == 0) {
- sanitized_path[nb_paths++] = sanitize_path(dev_interface_details->DevicePath);
- if (nb_paths > MAX_USB_DEVICES) {
- usbi_warn(ctx, "more than %d devices - ignoring the rest", MAX_USB_DEVICES);
- break;
+ for (api=USB_API_WINUSB; api<USB_API_MAX; api++) {
+ if (safe_strcmp(driver, usb_api_backend[api].driver_name) == 0) {
+ api_type[nb_paths] = api;
+ sanitized_path[nb_paths++] = sanitize_path(dev_interface_details->DevicePath);
+ if (nb_paths > MAX_USB_DEVICES) {
+ usbi_warn(ctx, "more than %d devices - ignoring the rest", MAX_USB_DEVICES);
+ break;
+ }
}
}
}
@@ -942,6 +963,8 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str
for (j=0; j<nb_paths; j++) {
if (safe_strncmp(sanitized_path[j], sanitized_short, strlen(sanitized_short)) == 0) {
priv->usb_interface[interface_number].path = sanitized_path[j];
+ priv->usb_interface[interface_number].apib = &usb_api_backend[api_type[j]];
+ priv->composite_api_flags |= 1<<api_type[j];
sanitized_path[j] = NULL;
}
}
@@ -969,6 +992,75 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str
}
/*
+ * Likewise, HID device interfaces's path (\\.\HID\...) are not enumerated through the
+ * generic USB devices GUID, but are actually children of one such device
+ */
+static int set_hid_device(struct libusb_context *ctx, struct windows_device_priv *priv)
+ {
+ char path[MAX_PATH_LENGTH];
+ char *sanitized_path = NULL;
+ HDEVINFO dev_info;
+ SP_DEVICE_INTERFACE_DETAIL_DATA *dev_interface_details = NULL;
+ SP_DEVINFO_DATA dev_info_data;
+ DEVINST parent_devinst;
+ GUID guid;
+ int r = LIBUSB_SUCCESS;
+ unsigned i, interface_number;
+
+ interface_number = 0;
+ HidD_GetHidGuid(&guid);
+ for (i = 0; ; i++)
+ {
+ // safe loop: free up any (unprotected) dynamic resource
+ safe_free(dev_interface_details);
+ safe_free(sanitized_path);
+
+ dev_interface_details = get_interface_details(ctx, &dev_info, guid, i);
+ // safe loop: end of loop condition
+ if ( (dev_interface_details == NULL)
+ || (r != LIBUSB_SUCCESS) )
+ break;
+
+ dev_info_data.cbSize = sizeof(dev_info_data);
+ if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) {
+ usbi_warn(ctx, "could not retrieve info data for device %s, skipping: %s",
+ dev_interface_details->DevicePath, windows_error_str(0));
+ continue;
+ }
+
+ // Retrieve parent's path using PnP Configuration Manager (CM)
+ if (CM_Get_Parent(&parent_devinst, dev_info_data.DevInst, 0) != CR_SUCCESS) {
+ usbi_warn(ctx, "could not retrieve parent info data for device %s, skipping: %s",
+ dev_interface_details->DevicePath, windows_error_str(0));
+ continue;
+ }
+
+ if (CM_Get_Device_ID(parent_devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) {
+ usbi_warn(ctx, "could not retrieve parent's path for device %s, skipping: %s",
+ dev_interface_details->DevicePath, windows_error_str(0));
+ continue;
+ }
+
+ // Fix parent's path inconsistencies before attempting to compare
+ sanitized_path = sanitize_path(path);
+ if (sanitized_path == NULL) {
+ usbi_warn(ctx, "could not sanitize parent's path for device %s, skipping.",
+ dev_interface_details->DevicePath);
+ continue;
+ }
+
+ // NB: we compare strings of different lengths below => strncmp
+ if (safe_strncmp(priv->path, sanitized_path, strlen(sanitized_path)) == 0) {
+ priv->usb_interface[interface_number].path = sanitize_path(dev_interface_details->DevicePath);
+ usbi_dbg("interface_path[%d]: %s", interface_number, priv->usb_interface[interface_number].path);
+ interface_number++;
+ }
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+/*
* This function retrieves and sets the paths of all non-hub devices
* NB: No I/O with device is required during this call
*/
@@ -986,10 +1078,10 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
GUID guid;
DWORD size, reg_type, port_nr;
int r = LIBUSB_SUCCESS;
- unsigned i, j;
+ unsigned i, j, k, api;
bool found;
- // TODO: MI_## automated driver installation:
+ // TODO: MI_## automated driver installation
guid = GUID_DEVINTERFACE_USB_DEVICE;
for (i = 0; ; i++)
{
@@ -1005,8 +1097,8 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
dev_info_data.cbSize = sizeof(dev_info_data);
if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) {
- usbi_warn(ctx, "could not retrieve info data for device #%u, skipping: %s",
- i, windows_error_str(0));
+ usbi_warn(ctx, "could not retrieve info data for device %s, skipping: %s",
+ dev_interface_details->DevicePath, windows_error_str(0));
continue;
}
@@ -1014,28 +1106,29 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
if ( (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_ADDRESS,
&reg_type, (BYTE*)&port_nr, 4, &size))
&& (size != 4) ){
- usbi_warn(ctx, "could not retrieve port number for device #%u, skipping: %s",
- i, windows_error_str(0));
+ usbi_warn(ctx, "could not retrieve port number for device %s, skipping: %s",
+ dev_interface_details->DevicePath, windows_error_str(0));
continue;
}
// Retrieve parent's path using PnP Configuration Manager (CM)
if (CM_Get_Parent(&parent_devinst, dev_info_data.DevInst, 0) != CR_SUCCESS) {
- usbi_warn(ctx, "could not retrieve parent info data for device #%u, skipping: %s",
- i, windows_error_str(0));
+ usbi_warn(ctx, "could not retrieve parent info data for device %s, skipping: %s",
+ dev_interface_details->DevicePath, windows_error_str(0));
continue;
}
if (CM_Get_Device_ID(parent_devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) {
- usbi_warn(ctx, "could not retrieve parent's path for device #%u, skipping: %s",
- i, windows_error_str(0));
+ usbi_warn(ctx, "could not retrieve parent's path for device %s, skipping: %s",
+ dev_interface_details->DevicePath, windows_error_str(0));
continue;
}
- // Fix parent's path inconsistancies before attempting to compare
+ // Fix parent's path inconsistencies before attempting to compare
sanitized_path = sanitize_path(path);
if (sanitized_path == NULL) {
- usbi_warn(ctx, "could not sanitize parent's path for device #%u, skipping.", i);
+ usbi_warn(ctx, "could not sanitize parent's path for device %s, skipping.",
+ dev_interface_details->DevicePath);
continue;
}
@@ -1052,6 +1145,7 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
parent_priv = __device_priv(priv->parent_dev);
// NB: we compare strings of different lengths below => strncmp
+// usbi_dbg("Comparing: %s vs %s", parent_priv->path, sanitized_path);
if ( (safe_strncmp(parent_priv->path, sanitized_path, strlen(sanitized_path)) == 0)
&& (port_nr == priv->connection_index) ) {
@@ -1065,34 +1159,41 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
// It tells us if we can use WinUSB, if we have a composite device, and the API to use
if(!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_SERVICE,
&reg_type, (BYTE*)reg_key, MAX_KEY_LENGTH, &size)) {
- usbi_err(ctx, "could not retrieve driver information for device #%u, skipping: %s",
- i, windows_error_str(0));
+ usbi_err(ctx, "could not retrieve driver information for device %s, skipping: %s",
+ dev_interface_details->DevicePath, windows_error_str(0));
break;
}
- priv->driver = safe_strdup(reg_key);
- usbi_dbg("driver: %s", priv->driver);
+ usbi_dbg("driver: %s", reg_key);
found = true;
- if (safe_strcmp(priv->driver, "WinUSB") == 0) {
- priv->apib = &windows_winusb_backend;
- // For non composite, the first interface is the same as the device
- priv->usb_interface[0].path = safe_strdup(priv->path); // needs strdup
- } else if (safe_strcmp(reg_key, "usbccgp") == 0) {
- // Composite (multi-interface) devices are identified by their use of
- // the USB Common Class Generic Parent driver
- if (set_composite_device(ctx, dev_info_data.DevInst, priv) == LIBUSB_SUCCESS) {
- priv->apib = &windows_winusb_backend;
- } else {
- priv->apib = &windows_template_backend;
+ for (api = 0; api<USB_API_MAX; api++) {
+ if (safe_strcmp(reg_key, usb_api_backend[api].driver_name) == 0) {
+ priv->apib = &usb_api_backend[api];
+ switch(api) {
+ case USB_API_COMPOSITE:
+ set_composite_device(ctx, dev_info_data.DevInst, priv);
+ break;
+ case USB_API_HID:
+ set_hid_device(ctx, priv);
+ break;
+ default:
+ // For other devices, the first interface is the same as the device
+ priv->usb_interface[0].path = safe_strdup(priv->path); // needs strdup
+ // The following is needed if we want to API calls to work for both simple
+ // and composite devices, as
+ for(k=0; k<USB_MAXINTERFACES; k++) {
+ priv->usb_interface[k].apib = &usb_api_backend[api];
+ }
+ break;
+ }
}
- } else {
- // All other USB access drivers (HID, Mass Storage) are ignored for now
}
break;
}
}
if (!found) {
+ // TODO: warn about ghost drivers and how to remove them
usbi_warn(ctx, "could not match %s with a libusb device.", dev_interface_details->DevicePath);
continue;
}
@@ -1145,7 +1246,8 @@ static int windows_get_device_list(struct libusb_context *ctx, struct discovered
*/
static void windows_exit(void)
{
- struct windows_hcd_priv* hcd_tmp;
+ struct windows_hcd_priv* hcd_tmp;
+ int i;
while (hcd_root != NULL)
{
@@ -1155,7 +1257,9 @@ static void windows_exit(void)
safe_free(hcd_tmp);
}
- winusb_api_exit();
+ for (i=0; i<USB_API_MAX; i++) {
+ usb_api_backend[i].exit();
+ }
exit_polling();
SetThreadAffinityMask(GetCurrentThread(), old_affinity_mask);
@@ -1219,11 +1323,7 @@ static void windows_close(struct libusb_device_handle *dev_handle)
{
struct windows_device_priv *priv = __device_priv(dev_handle->dev);
- // Incidentally, we could just add a "close" member and have it not
- // warn.
- if(&windows_winusb_backend == priv->apib) {
- winusb_close(dev_handle);
- }
+ priv->apib->close(dev_handle);
}
static int windows_get_configuration(struct libusb_device_handle *dev_handle, int *config)
@@ -1623,75 +1723,133 @@ const struct usbi_os_backend windows_backend = {
};
-const struct windows_driver_backend windows_winusb_backend = {
- "WinUSB",
- winusb_open,
- winusb_claim_interface,
- winusb_set_interface_altsetting,
- winusb_release_interface,
- winusb_clear_halt,
- winusb_reset_device,
- winusb_submit_bulk_transfer,
- winusb_submit_iso_transfer,
- winusb_submit_control_transfer,
- winusb_abort_control,
- winusb_abort_transfers,
-};
-
+/*
+ * USB API backends
+ */
+static int unsupported_init(struct libusb_context *ctx) {
+ return LIBUSB_SUCCESS;
+}
+static int unsupported_exit(void) {
+ return LIBUSB_SUCCESS;
+}
static int unsupported_open(struct libusb_device_handle *dev_handle) {
- PRINT_UNSUPPORTED_API(unsupported_open);
+ PRINT_UNSUPPORTED_API(open);
+}
+static void unsupported_close(struct libusb_device_handle *dev_handle) {
+ usbi_dbg("unsupported API call for 'close'");
}
static int unsupported_claim_interface(struct libusb_device_handle *dev_handle, int iface) {
- PRINT_UNSUPPORTED_API(unsupported_claim_interface);
+ PRINT_UNSUPPORTED_API(claim_interface);
}
static int unsupported_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting) {
- PRINT_UNSUPPORTED_API(unsupported_set_interface_altsetting);
+ PRINT_UNSUPPORTED_API(set_interface_altsetting);
}
static int unsupported_release_interface(struct libusb_device_handle *dev_handle, int iface) {
- PRINT_UNSUPPORTED_API(unsupported_release_interface);
+ PRINT_UNSUPPORTED_API(release_interface);
}
static int unsupported_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint) {
- PRINT_UNSUPPORTED_API(unsupported_clear_halt);
+ PRINT_UNSUPPORTED_API(clear_halt);
}
static int unsupported_reset_device(struct libusb_device_handle *dev_handle) {
- PRINT_UNSUPPORTED_API(unsupported_reset_device);
+ PRINT_UNSUPPORTED_API(reset_device);
}
static int unsupported_submit_bulk_transfer(struct usbi_transfer *itransfer) {
- PRINT_UNSUPPORTED_API(unsupported_submit_bulk_transfer);
+ PRINT_UNSUPPORTED_API(submit_bulk_transfer);
}
static int unsupported_submit_iso_transfer(struct usbi_transfer *itransfer) {
- PRINT_UNSUPPORTED_API(unsupported_submit_iso_transfer);
+ PRINT_UNSUPPORTED_API(submit_iso_transfer);
}
static int unsupported_submit_control_transfer(struct usbi_transfer *itransfer) {
- PRINT_UNSUPPORTED_API(unsupported_submit_control_transfer);
+ PRINT_UNSUPPORTED_API(submit_control_transfer);
}
static int unsupported_abort_control(struct usbi_transfer *itransfer) {
- PRINT_UNSUPPORTED_API(unsupported_abort_control);
+ PRINT_UNSUPPORTED_API(abort_control);
}
static int unsupported_abort_transfers(struct usbi_transfer *itransfer) {
- PRINT_UNSUPPORTED_API(unsupported_abort_transfers);
-}
-
-const struct windows_driver_backend windows_template_backend = {
- "Dummy",
- unsupported_open,
- unsupported_claim_interface,
- unsupported_set_interface_altsetting,
- unsupported_release_interface,
- unsupported_clear_halt,
- unsupported_reset_device,
- unsupported_submit_bulk_transfer,
- unsupported_submit_iso_transfer,
- unsupported_submit_control_transfer,
- unsupported_abort_control,
- unsupported_abort_transfers,
+ PRINT_UNSUPPORTED_API(abort_transfers);
+}
+
+const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
+ {
+ "Dummy",
+ "",
+ USB_API_TEMPLATE,
+ unsupported_init,
+ unsupported_exit,
+ unsupported_open,
+ unsupported_close,
+ unsupported_claim_interface,
+ unsupported_set_interface_altsetting,
+ unsupported_release_interface,
+ unsupported_clear_halt,
+ unsupported_reset_device,
+ unsupported_submit_bulk_transfer,
+ unsupported_submit_iso_transfer,
+ unsupported_submit_control_transfer,
+ unsupported_abort_control,
+ unsupported_abort_transfers,
+ }, {
+ "Composite",
+ "usbccgp",
+ USB_API_COMPOSITE,
+ composite_init,
+ composite_exit,
+ composite_open,
+ composite_close,
+ composite_claim_interface,
+ composite_set_interface_altsetting,
+ composite_release_interface,
+ composite_clear_halt,
+ composite_reset_device,
+ composite_submit_bulk_transfer,
+ composite_submit_iso_transfer,
+ composite_submit_control_transfer,
+ composite_abort_control,
+ composite_abort_transfers,
+ }, {
+ "WinUSB",
+ "WinUSB",
+ USB_API_WINUSB,
+ winusb_init,
+ winusb_exit,
+ winusb_open,
+ winusb_close,
+ winusb_claim_interface,
+ winusb_set_interface_altsetting,
+ winusb_release_interface,
+ winusb_clear_halt,
+ winusb_reset_device,
+ winusb_submit_bulk_transfer,
+ winusb_submit_iso_transfer,
+ winusb_submit_control_transfer,
+ winusb_abort_control,
+ winusb_abort_transfers,
+ }, {
+ "HID",
+ "HidUsb",
+ USB_API_HID,
+ hid_init,
+ hid_exit,
+ hid_open,
+ hid_close,
+ unsupported_claim_interface,
+ unsupported_set_interface_altsetting,
+ unsupported_release_interface,
+ unsupported_clear_halt,
+ unsupported_reset_device,
+ unsupported_submit_bulk_transfer,
+ unsupported_submit_iso_transfer,
+ unsupported_submit_control_transfer,
+ unsupported_abort_control,
+ unsupported_abort_transfers,
+ },
};
/*
* WinUSB API functions
*/
-static int winusb_api_init(struct libusb_context *ctx)
+static int winusb_init(struct libusb_context *ctx)
{
DLL_LOAD(winusb.dll, WinUsb_Initialize, TRUE);
DLL_LOAD(winusb.dll, WinUsb_Free, TRUE);
@@ -1715,12 +1873,15 @@ static int winusb_api_init(struct libusb_context *ctx)
return LIBUSB_SUCCESS;
}
-static int winusb_api_exit(void)
+static int winusb_exit(void)
{
api_winusb_available = false;
return LIBUSB_SUCCESS;
}
+// NB: open and close must ensure that they only handle interface of
+// the right API type, as these functions can be called wholesale from
+// composite_open(), with interfaces belonging to different APIs
static int winusb_open(struct libusb_device_handle *dev_handle)
{
struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
@@ -1734,7 +1895,8 @@ static int winusb_open(struct libusb_device_handle *dev_handle)
// WinUSB requires a seperate handle for each interface
for (i = 0; i < USB_MAXINTERFACES; i++) {
- if (priv->usb_interface[i].path != NULL) {
+ if ( (priv->usb_interface[i].path != NULL)
+ && (priv->usb_interface[i].apib->id == USB_API_WINUSB) ) {
file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (file_handle == INVALID_HANDLE_VALUE) {
@@ -1758,6 +1920,7 @@ static int winusb_open(struct libusb_device_handle *dev_handle)
static void winusb_close(struct libusb_device_handle *dev_handle)
{
struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv;
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
HANDLE file_handle;
int i;
@@ -1765,9 +1928,11 @@ static void winusb_close(struct libusb_device_handle *dev_handle)
return;
for (i = 0; i < USB_MAXINTERFACES; i++) {
- file_handle = handle_priv->interface_handle[i].file;
- if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) {
- CloseHandle(file_handle);
+ if (priv->usb_interface[i].apib->id == USB_API_WINUSB) {
+ file_handle = handle_priv->interface_handle[i].file;
+ if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) {
+ CloseHandle(file_handle);
+ }
}
}
}
@@ -1777,7 +1942,7 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int i
struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv;
struct windows_device_priv *priv = __device_priv(dev_handle->dev);
- bool is_composite = (safe_strcmp(priv->driver, "usbccgp") == 0);
+ bool is_composite = (priv->apib->id == USB_API_COMPOSITE);
HANDLE file_handle, winusb_handle;
USB_INTERFACE_DESCRIPTOR if_desc;
UCHAR policy;
@@ -1891,6 +2056,7 @@ static int winusb_release_interface(struct libusb_device_handle *dev_handle, int
/*
* Return the first valid WinUSB handle, for control transfers
*/
+// TODO: make this function generic for all drivers
static int winusb_get_valid_interface(struct windows_device_handle_priv *handle_priv)
{
int i;
@@ -1985,6 +2151,7 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer)
// Use priv_transfer to store data needed for async polling
transfer_priv->pollable_fd = wfd;
+ transfer_priv->interface_number = current_interface;
return LIBUSB_SUCCESS;
}
@@ -2068,6 +2235,7 @@ static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer)
}
transfer_priv->pollable_fd = wfd;
+ transfer_priv->interface_number = current_interface;
return LIBUSB_SUCCESS;
}
@@ -2199,3 +2367,272 @@ static int winusb_reset_device(struct libusb_device_handle *dev_handle)
return LIBUSB_SUCCESS;
}
+
+
+/*
+ * HID API functions
+ */
+static int hid_init(struct libusb_context *ctx)
+{
+ DLL_LOAD(hid.dll, HidD_GetAttributes, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetHidGuid, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetPreparsedData, TRUE);
+ DLL_LOAD(hid.dll, HidD_FreePreparsedData, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetManufacturerString, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetProductString, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetSerialNumberString, TRUE);
+ DLL_LOAD(hid.dll, HidP_GetCaps, TRUE);
+ DLL_LOAD(hid.dll, HidD_SetNumInputBuffers, TRUE);
+ DLL_LOAD(hid.dll, HidD_SetFeature, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetFeature, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetPhysicalDescriptor, TRUE);
+ DLL_LOAD(hid.dll, HidD_GetInputReport, FALSE);
+ DLL_LOAD(hid.dll, HidD_SetOutputReport, FALSE);
+
+ api_hid_available = true;
+ return LIBUSB_SUCCESS;
+}
+
+static int hid_exit(void)
+{
+ api_hid_available = false;
+ return LIBUSB_SUCCESS;
+}
+
+// NB: open and close must ensure that they only handle interface of
+// the right API type, as these functions can be called wholesale from
+// composite_open(), with interfaces belonging to different APIs
+static int hid_open(struct libusb_device_handle *dev_handle)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv;
+
+ HANDLE file_handle;
+ int i;
+
+ CHECK_HID_AVAILABLE;
+
+ // TODO: do we need separate IF handles with HIDs?
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if ( (priv->usb_interface[i].path != NULL)
+ && (priv->usb_interface[i].apib->id == USB_API_HID) ) {
+// file_handle = CreateFileA(priv->usb_interface[i].path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
+// NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+
+ /*
+ * http://www.lvr.com/hidfaq.htm: Why do I receive "Access denied" when attempting to access my HID?
+ * "Windows 2000 and later have exclusive read/write access to HIDs that are configured as a system
+ * keyboards or mice. An application can obtain a handle to a system keyboard or mouse by not
+ * requesting READ or WRITE access with CreateFile. Applications can then use HidD_SetFeature and
+ * HidD_GetFeature (if the device supports Feature reports)."
+ */
+ file_handle = CreateFileA(priv->usb_interface[i].path, 0, FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+ // TODO: open above rw and fallback to no r/w if failure
+ if (file_handle == INVALID_HANDLE_VALUE) {
+ usbi_err(ctx, "could not open device %s (interface %d): %s", priv->path, i, windows_error_str(0));
+ switch(GetLastError()) {
+ case ERROR_FILE_NOT_FOUND: // The device was disconnected
+ return LIBUSB_ERROR_NO_DEVICE;
+ case ERROR_ACCESS_DENIED:
+ return LIBUSB_ERROR_ACCESS;
+ default:
+ return LIBUSB_ERROR_IO;
+ }
+ }
+ handle_priv->interface_handle[i].file = file_handle;
+ }
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
+static void hid_close(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv;
+ HANDLE file_handle;
+ int i;
+
+ if (!api_hid_available)
+ return;
+
+ for (i = 0; i < USB_MAXINTERFACES; i++) {
+ if (priv->usb_interface[i].apib->id == USB_API_HID) {
+ file_handle = handle_priv->interface_handle[i].file;
+ if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) {
+ CloseHandle(file_handle);
+ }
+ }
+ }
+}
+
+/*
+ * Composite API functions
+ */
+static int composite_init(struct libusb_context *ctx)
+{
+ return LIBUSB_SUCCESS;
+}
+
+static int composite_exit(void)
+{
+ return LIBUSB_SUCCESS;
+}
+
+static int composite_open(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ unsigned api;
+ int r;
+ uint8_t flag = 1<<USB_API_WINUSB;
+
+ for (api=USB_API_WINUSB; api<USB_API_MAX; api++) {
+ if (priv->composite_api_flags & flag) {
+ r = usb_api_backend[api].open(dev_handle);
+ if (r != LIBUSB_SUCCESS) {
+ return r;
+ }
+ }
+ flag <<= 1;
+ }
+ return LIBUSB_SUCCESS;
+}
+
+static void composite_close(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ unsigned api;
+ uint8_t flag = 1<<USB_API_WINUSB;
+
+ for (api=USB_API_WINUSB; api<USB_API_MAX; api++) {
+ if (priv->composite_api_flags & flag) {
+ usb_api_backend[api].close(dev_handle);
+ }
+ flag <<= 1;
+ }
+}
+
+static int composite_claim_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ return priv->usb_interface[iface].apib->claim_interface(dev_handle, iface);
+}
+
+static int composite_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ return priv->usb_interface[iface].apib->set_interface_altsetting(dev_handle, iface, altsetting);
+}
+
+static int composite_release_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ return priv->usb_interface[iface].apib->release_interface(dev_handle, iface);
+}
+
+static int composite_submit_control_transfer(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ int i;
+
+ // Interface doesn't matter for control. Might have to review this section
+ // for multiple drivers, if one API is better for control than another.
+ for (i=0; i<USB_MAXINTERFACES; i++) {
+ if (priv->usb_interface[i].path != NULL) {
+ return priv->usb_interface[i].apib->submit_control_transfer(itransfer);
+ }
+ }
+
+ usbi_err(ctx, "no libusb supported interfaces to complete request");
+ return LIBUSB_ERROR_NOT_FOUND;
+}
+
+static int composite_submit_bulk_transfer(struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)transfer->dev_handle->os_priv;
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ int current_interface;
+
+ current_interface = winusb_interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ return priv->usb_interface[current_interface].apib->submit_bulk_transfer(itransfer);
+}
+
+static int composite_submit_iso_transfer(struct usbi_transfer *itransfer) {
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)transfer->dev_handle->os_priv;
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+ int current_interface;
+
+ current_interface = winusb_interface_by_endpoint(priv, handle_priv, transfer->endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cancelling transfer");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ return priv->usb_interface[current_interface].apib->submit_iso_transfer(itransfer);
+}
+
+static int composite_clear_halt(struct libusb_device_handle *dev_handle, unsigned char endpoint)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+ struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv;
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ int current_interface;
+
+ current_interface = winusb_interface_by_endpoint(priv, handle_priv, endpoint);
+ if (current_interface < 0) {
+ usbi_err(ctx, "unable to match endpoint to an open interface - cannot clear");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ return priv->usb_interface[current_interface].apib->clear_halt(dev_handle, endpoint);
+}
+
+static int composite_abort_control(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+
+ return priv->usb_interface[transfer_priv->interface_number].apib->abort_control(itransfer);
+}
+
+static int composite_abort_transfers(struct usbi_transfer *itransfer)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_priv *priv = __device_priv(transfer->dev_handle->dev);
+
+ return priv->usb_interface[transfer_priv->interface_number].apib->abort_transfers(itransfer);
+}
+
+
+static int composite_reset_device(struct libusb_device_handle *dev_handle)
+{
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+ unsigned api;
+ int r;
+ uint8_t flag = 1<<USB_API_WINUSB;
+
+ for (api=USB_API_WINUSB; api<USB_API_MAX; api++) {
+ if (priv->composite_api_flags & flag) {
+ r = usb_api_backend[api].reset_device(dev_handle);
+ if (r != LIBUSB_SUCCESS) {
+ return r;
+ }
+ }
+ flag <<= 1;
+ }
+ return LIBUSB_SUCCESS;
+}
diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h
index 692d2d2..63f89cd 100644
--- a/libusb/os/windows_usb.h
+++ b/libusb/os/windows_usb.h
@@ -75,10 +75,15 @@ void inline upperize(char* str) {
#define wchar_to_utf8_ms(wstr, str, strlen) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, strlen, NULL, NULL)
#define ERRNO GetLastError()
-// This is used to support multiple kernel drivers in Windows.
-struct windows_driver_backend {
- const char *name; // A human-readable name for your backend, e.g. "WinUSB"
+// This is used to support multiple kernel drivers and USB APIs in Windows.
+struct windows_usb_api_backend {
+ const char *name; // A human-readable name for your backend, e.g. "WinUSB"
+ const char *driver_name; // Driver's name, without .sys, e.g. "usbccgp"
+ const uint8_t id;
+ int (*init)(struct libusb_context *ctx);
+ int (*exit)(void);
int (*open)(struct libusb_device_handle *dev_handle);
+ void (*close)(struct libusb_device_handle *dev_handle);
int (*claim_interface)(struct libusb_device_handle *dev_handle, int iface);
int (*set_interface_altsetting)(struct libusb_device_handle *dev_handle, int iface, int altsetting);
int (*release_interface)(struct libusb_device_handle *dev_handle, int iface);
@@ -90,8 +95,13 @@ struct windows_driver_backend {
int (*abort_control)(struct usbi_transfer *itransfer);
int (*abort_transfers)(struct usbi_transfer *itransfer);
};
-extern const struct windows_driver_backend windows_template_backend;
-extern const struct windows_driver_backend windows_winusb_backend;
+
+#define USB_API_TEMPLATE 0
+#define USB_API_COMPOSITE 1
+#define USB_API_WINUSB 2
+#define USB_API_HID 3
+#define USB_API_MAX 4
+extern const struct windows_usb_api_backend usb_api_backend[USB_API_MAX];
#define PRINT_UNSUPPORTED_API(fname) \
usbi_dbg("unsupported API call for '" \
@@ -131,12 +141,13 @@ struct windows_device_priv {
ULONG connection_index; // also required for some usermode ops
char *path; // path used by Windows to reference the USB node
struct {
- char *path; // each interface has a path as well
+ char *path; // each interface needs a Windows device interface path,
+ struct windows_usb_api_backend const *apib; // an API backend (multiple drivers support),
int8_t nb_endpoints; // and a set of endpoint addresses (USB_MAXENDPOINTS)
uint8_t *endpoint;
} usb_interface[USB_MAXINTERFACES];
- char *driver; // driver name (eg WinUSB, USBSTOR, HidUsb, etc)
- struct windows_driver_backend const *apib;
+ struct windows_usb_api_backend const *apib;
+ uint8_t composite_api_flags;
uint8_t active_config;
USB_DEVICE_DESCRIPTOR dev_descriptor;
unsigned char **config_descriptor; // list of pointers to the cached config descriptors
@@ -147,13 +158,14 @@ static inline void windows_device_priv_init(struct windows_device_priv* p) {
p->parent_dev = NULL;
p->connection_index = 0;
p->path = NULL;
- p->driver = NULL;
- p->apib = &windows_template_backend;
+ p->apib = &usb_api_backend[USB_API_TEMPLATE];
+ p->composite_api_flags = 0;
p->active_config = 0;
p->config_descriptor = NULL;
memset(&(p->dev_descriptor), 0, sizeof(USB_DEVICE_DESCRIPTOR));
for (i=0; i<USB_MAXINTERFACES; i++) {
p->usb_interface[i].path = NULL;
+ p->usb_interface[i].apib = &usb_api_backend[USB_API_TEMPLATE];
p->usb_interface[i].nb_endpoints = 0;
p->usb_interface[i].endpoint = NULL;
}
@@ -162,7 +174,6 @@ static inline void windows_device_priv_init(struct windows_device_priv* p) {
static inline void windows_device_priv_release(struct windows_device_priv* p, int num_configurations) {
int i;
safe_free(p->path);
- safe_free(p->driver);
if ((num_configurations > 0) && (p->config_descriptor != NULL)) {
for (i=0; i < num_configurations; i++)
safe_free(p->config_descriptor[i]);
@@ -197,6 +208,7 @@ static inline struct windows_device_handle_priv *__device_handle_priv(
// used for async polling functions
struct windows_transfer_priv {
struct winfd pollable_fd;
+ uint8_t interface_number;
};
@@ -380,3 +392,53 @@ DLL_DECLARE(WINAPI, BOOL, WinUsb_AbortPipe,
(WINUSB_INTERFACE_HANDLE, UCHAR));
DLL_DECLARE(WINAPI, BOOL, WinUsb_FlushPipe,
(WINUSB_INTERFACE_HANDLE, UCHAR));
+
+/* hid.dll interface */
+
+#pragma pack(1)
+typedef struct {
+ ULONG Size;
+ USHORT VendorID;
+ USHORT ProductID;
+ USHORT VersionNumber;
+} HIDD_ATTRIBUTES, *PHIDD_ATTRIBUTES;
+#pragma pack()
+
+typedef USHORT USAGE;
+typedef struct {
+ USAGE Usage;
+ USAGE UsagePage;
+ USHORT InputReportByteLength;
+ USHORT OutputReportByteLength;
+ USHORT FeatureReportByteLength;
+ USHORT Reserved[17];
+ USHORT NumberLinkCollectionNodes;
+ USHORT NumberInputButtonCaps;
+ USHORT NumberInputValueCaps;
+ USHORT NumberInputDataIndices;
+ USHORT NumberOutputButtonCaps;
+ USHORT NumberOutputValueCaps;
+ USHORT NumberOutputDataIndices;
+ USHORT NumberFeatureButtonCaps;
+ USHORT NumberFeatureValueCaps;
+ USHORT NumberFeatureDataIndices;
+} HIDP_CAPS, *PHIDP_CAPS;
+
+typedef void* PHIDP_PREPARSED_DATA;
+DLL_DECLARE(WINAPI, BOOL, HidD_GetAttributes, (HANDLE, PHIDD_ATTRIBUTES));
+DLL_DECLARE(WINAPI, VOID, HidD_GetHidGuid, (LPGUID));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetPreparsedData,
+ (HANDLE, PHIDP_PREPARSED_DATA *));
+DLL_DECLARE(WINAPI, BOOL, HidD_FreePreparsedData, (PHIDP_PREPARSED_DATA));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetManufacturerString, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetProductString, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetSerialNumberString, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, NTSTATUS, HidP_GetCaps,
+ (PHIDP_PREPARSED_DATA, PHIDP_CAPS));
+DLL_DECLARE(WINAPI, BOOL, HidD_SetNumInputBuffers, (HANDLE, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_SetFeature, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetFeature, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetPhysicalDescriptor, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_GetInputReport, (HANDLE, PVOID, ULONG));
+DLL_DECLARE(WINAPI, BOOL, HidD_SetOutputReport, (HANDLE, PVOID, ULONG));
+