summaryrefslogtreecommitdiff
path: root/libusb
diff options
context:
space:
mode:
authorPete Batard <pbatard@gmail.com>2010-01-14 01:15:20 +0000
committerPete Batard <pbatard@gmail.com>2010-01-14 01:15:20 +0000
commiteacdaf7c213adbe0ceee37d3b62019d607241a52 (patch)
tree2ebdd21c7cd592beabd116c945cc1252d9a02271 /libusb
parentf47443958ede27696e963623fb8869adb20e19b0 (diff)
downloadlibusb-eacdaf7c213adbe0ceee37d3b62019d607241a52.tar.gz
svn r22: Partial async I/O (control only) with custom poll and OVERLAPPED pointers as fds. Should read device strings. Also some provisions for composite devices.
Diffstat (limited to 'libusb')
-rw-r--r--libusb/os/windows_compat.c125
-rw-r--r--libusb/os/windows_compat.h33
-rw-r--r--libusb/os/windows_usb.c363
-rw-r--r--libusb/os/windows_usb.h226
4 files changed, 467 insertions, 280 deletions
diff --git a/libusb/os/windows_compat.c b/libusb/os/windows_compat.c
index 029b71c..8387b0f 100644
--- a/libusb/os/windows_compat.c
+++ b/libusb/os/windows_compat.c
@@ -32,29 +32,8 @@
* -----------------------------------------------------------------------------
*
*
- * poll implementation from polipo (http://www.pps.jussieu.fr/~jch/software/polipo/):
- * -----------------------------------------------------------------------------
- * Copyright (c) 2006 by Dan Kennedy.
- * Copyright (c) 2006 by Juliusz Chroboczek.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
+ * parts of poll implementation from libusb-win32 v1, by Stephan Meyer et al.
*
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- * -----------------------------------------------------------------------------
*/
#include <errno.h>
#include <fcntl.h>
@@ -95,69 +74,53 @@ int pipe (int filedes[2]) {
return 0;
}
-// NB: because this implementation of poll uses select(), executables
-// need to be linked against the winsock library (-lws2_32)
-int mingw_poll(struct pollfd *fds, unsigned int nfds, int timo)
+// Rudimentary poll using OVERLAPPED
+int windows_poll(struct pollfd *fds, unsigned int nfds, int timeout)
{
- struct timeval timeout, *toptr;
- fd_set ifds, ofds, efds, *ip, *op;
- int i, rc;
+ int i, triggered = 0;
+ OVERLAPPED* io;
- /* Set up the file-descriptor sets in ifds, ofds and efds. */
- FD_ZERO(&ifds);
- FD_ZERO(&ofds);
- FD_ZERO(&efds);
- for (i = 0, op = ip = 0; i < nfds; ++i) {
- fds[i].revents = 0;
- if(fds[i].events & (POLLIN|POLLPRI)) {
- ip = &ifds;
- FD_SET(fds[i].fd, ip);
- }
- if(fds[i].events & POLLOUT) {
- op = &ofds;
- FD_SET(fds[i].fd, op);
- }
- FD_SET(fds[i].fd, &efds);
- }
+ for (i = 0; i < nfds; ++i) {
+ fds[i].revents = 0;
- /* Set up the timeval structure for the timeout parameter */
- if(timo < 0) {
- toptr = 0;
- } else {
- toptr = &timeout;
- timeout.tv_sec = timo / 1000;
- timeout.tv_usec = (timo - timeout.tv_sec * 1000) * 1000;
- }
+ /* form io.c:
+ * -# During initialization, libusb opens an internal pipe, and it adds the read
+ * end of this pipe to the set of file descriptors to be polled.
+ * -# During libusb_close(), libusb writes some dummy data on this control pipe.
+ * This immediately interrupts the event handler. libusb also records
+ * internally that it is trying to interrupt event handlers for this
+ * high-priority event.
+ */
+ // TODO: for now, we just ignore the control pipe
+ if (i==0)
+ continue;
-#ifdef DEBUG_POLL
- printf("Entering select() sec=%ld usec=%ld ip=%lx op=%lx\n",
- (long)timeout.tv_sec, (long)timeout.tv_usec, (long)ip, (long)op);
-#endif
- rc = select(0, ip, op, &efds, toptr);
-#ifdef DEBUG_POLL
- printf("Exiting select rc=%d\n", rc);
-#endif
+ // All the fds above 1 are actually OVERLAPPED pointers converted to int
+ io = (OVERLAPPED*)fds[i].fd;
- if(rc <= 0)
- return rc;
+ printf("windows_poll: fd[%d] (fd = %p) got events %04X\n", i, io, fds[i].events);
- if(rc > 0) {
- for (i = 0; i < nfds; ++i) {
- int fd = fds[i].fd;
- if(fds[i].events & (POLLIN|POLLPRI) && FD_ISSET(fd, &ifds))
- fds[i].revents |= POLLIN;
- if(fds[i].events & POLLOUT && FD_ISSET(fd, &ofds))
- fds[i].revents |= POLLOUT;
- if(FD_ISSET(fd, &efds))
- /* Some error was detected ... should be some way to know. */
- fds[i].revents |= POLLHUP;
-#ifdef DEBUG_POLL
- printf("%d %d %d revent = %x\n",
- FD_ISSET(fd, &ifds), FD_ISSET(fd, &ofds), FD_ISSET(fd, &efds),
- fds[i].revents
- );
-#endif
- }
- }
- return rc;
+ if (HasOverlappedIoCompleted(io)) {
+ printf(" completed\n");
+ fds[i].revents |= POLLIN;
+ triggered++;
+ } else {
+ switch(WaitForSingleObject(io->hEvent, (timeout==-1)?INFINITE:timeout))
+ {
+ case WAIT_OBJECT_0:
+ printf(" completed after wait\n");
+ fds[i].revents |= POLLIN;
+ triggered++;
+ break;
+ case WAIT_TIMEOUT:
+ printf(" timed out\n");
+ break;
+ default:
+ fds[i].revents |= POLLERR;
+ break;
+ }
+ }
+ }
+
+ return triggered;
}
diff --git a/libusb/os/windows_compat.h b/libusb/os/windows_compat.h
index 0df4da8..3761bfd 100644
--- a/libusb/os/windows_compat.h
+++ b/libusb/os/windows_compat.h
@@ -32,36 +32,13 @@
* -----------------------------------------------------------------------------
*
*
- * poll implementation from polipo (http://www.pps.jussieu.fr/~jch/software/polipo/):
- * -----------------------------------------------------------------------------
- * Copyright (c) 2006 by Dan Kennedy.
- * Copyright (c) 2006 by Juliusz Chroboczek.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
+ * parts of poll implementation from libusb-win32 v1, by Stephan Meyer et al.
*
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- * -----------------------------------------------------------------------------
*/
#pragma once
-/* winsock doesn't feature poll(), so there is a version implemented
- * in terms of select() in mingw.c. The following definitions
- * are copied from linux man pages. A poll() macro is defined to
- * call the version in mingw.c.
+/*
+ * Copied from linux man pages.
*/
#define POLLIN 0x0001 /* There is data to read */
#define POLLPRI 0x0002 /* There is urgent data to read */
@@ -75,11 +52,11 @@ struct pollfd {
short events; /* requested events */
short revents; /* returned events */
};
-#define poll(x, y, z) mingw_poll(x, y, z)
+#define poll(x, y, z) windows_poll(x, y, z)
typedef unsigned int nfds_t;
int pipe(int pipefd[2]);
-int mingw_poll(struct pollfd *fds, unsigned int nfds, int timo);
+int windows_poll(struct pollfd *fds, unsigned int nfds, int timeout);
#ifndef TIMESPEC_TO_TIMEVAL
#define TIMESPEC_TO_TIMEVAL(tv, ts) { \
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index dd75422..101ade3 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -70,13 +70,20 @@
const GUID GUID_DEVINTERFACE_USB_DEVICE = { 0xA5DCBF10, 0x6530, 0x11D2, {0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED} };
#endif
+// HACK: WinUSB composite device test
+#ifndef GUID_DEVINTERFACE_LIBUSB_DEVICE
+ // {78a1c341-4539-11d3-b88d-00c04fad5171}
+// const GUID GUID_DEVINTERFACE_LIBUSB_DEVICE = { 0x78a1c341, 0x4539, 0x11d3, {0xb8, 0x8d, 0x00, 0xc0, 0x4f, 0xad, 0x51, 0x71} };
+ // {b35924d6-3e16-4a9e-9782-5524a4b79bac (XBOX)
+ const GUID GUID_DEVINTERFACE_LIBUSB_DEVICE = { 0xB35924d6, 0x3E16, 0x4A9E, {0x97, 0x82, 0x55, 0x24, 0xA4, 0xB7, 0x9b, 0xAC} };
+#endif
+
// The 3 macros below are used in conjunction with safe loops.
#define LOOP_CHECK(fcall) { r=fcall; if (r != LIBUSB_SUCCESS) continue; }
#define LOOP_CONTINUE(...) { usbi_warn(ctx, __VA_ARGS__); continue; }
#define LOOP_BREAK(err) { r=err; continue; }
static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian);
-static int windows_get_active_config(struct libusb_device *dev);
static int windows_clock_gettime(int clk_id, struct timespec *tp);
// WinUSB API prototypes
static int winusb_api_init(struct libusb_context *ctx);
@@ -85,6 +92,7 @@ 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);
static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface);
+static int winusb_submit_control_transfer(struct usbi_transfer *itransfer, OVERLAPPED *io);
// HCD private chained list
struct windows_hcd_priv* hcd_root = NULL;
@@ -239,11 +247,12 @@ static int windows_init(struct libusb_context *ctx)
usbi_dbg("hires timer available (Frequency: %"PRIu64" Hz)", hires_frequency);
}
-/*
+//#define TEST_TIMER 3333
+#ifdef TEST_TIMER
// Test our timer
struct timespec tp;
uint64_t start_time, end_time;
- uint64_t duration_ms = 3333;
+ uint64_t duration_ms = TEST_TIMER;
if (windows_clock_gettime(USBI_CLOCK_MONOTONIC, &tp) != LIBUSB_SUCCESS)
return LIBUSB_ERROR_OTHER;
// Make sure computations are 64 bit
@@ -253,7 +262,7 @@ static int windows_init(struct libusb_context *ctx)
return LIBUSB_ERROR_OTHER;
end_time = ((uint64_t)tp.tv_sec)*1000000000 + ((uint64_t)tp.tv_nsec);
usbi_dbg("timed %"PRIu64" ns: %"PRIu64" ns", (uint64_t)(duration_ms*1000000), (uint64_t)(end_time-start_time));
-*/
+#endif
// We maintain a chained list of the Host Controllers found
struct windows_hcd_priv** _hcd_cur = &hcd_root;
@@ -331,11 +340,10 @@ static int windows_init(struct libusb_context *ctx)
* Initialize device structure, including active config
*/
static int initialize_device(struct libusb_device *dev, libusb_bus_t busnum,
- libusb_devaddr_t devaddr, char *path, int connection_index,
+ libusb_devaddr_t devaddr, char *path, int connection_index, uint8_t active_config,
struct libusb_device *parent_dev)
{
struct windows_device_priv *priv = __device_priv(dev);
- int active_config = 0;
// Set default values
windows_device_priv_init(priv);
@@ -346,15 +354,18 @@ static int initialize_device(struct libusb_device *dev, libusb_bus_t busnum,
priv->connection_index = connection_index;
priv->parent_dev = parent_dev;
- active_config = windows_get_active_config(dev);
+ priv->active_config = active_config;
- if (active_config < 0) {
- return active_config;
- } else if (active_config == 0) {
- // specs say a configuration value of 0 means unconfigured.
- usbi_dbg("assuming unconfigured device");
+ if (priv->active_config != 0) {
+ usbi_dbg("active config: %d", priv->active_config);
+ } else {
+ // USB devices that don't have a config value are usually missing
+ // 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 *");
}
- priv->active_config = active_config;
return LIBUSB_SUCCESS;
}
@@ -571,7 +582,7 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs
if (!is_hcd) {
// TODO: add EX info
size = sizeof(USB_NODE_CONNECTION_INFORMATION);
- conn_info.ConnectionIndex = i;
+ conn_info.ConnectionIndex = i;
if (!DeviceIoControl(hub_handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, &conn_info, size,
&conn_info, size, &size, NULL)) {
LOOP_CONTINUE("could not get node connection information: %s", windows_error_str());
@@ -593,6 +604,7 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs
// HCDs have only 1 node, and it's always a hub
conn_info.DeviceAddress = 0;
conn_info.DeviceIsHub = true;
+ conn_info.CurrentConfigurationValue = 1;
}
// If this node is a hub (HCD or not), open it
@@ -661,14 +673,9 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs
LOOP_BREAK(LIBUSB_ERROR_NO_MEM);
}
- LOOP_CHECK(initialize_device(dev, busnum, devaddr, path_str, i, parent_dev));
+ LOOP_CHECK(initialize_device(dev, busnum, devaddr, path_str, i,
+ conn_info.CurrentConfigurationValue, parent_dev));
priv = __device_priv(dev);
- // Detect devices that don't have a driver
- // TODO: use this for automated driver installation
- if (!conn_info.CurrentConfigurationValue) {
- priv->driver = safe_strdup("no_driver");
- usbi_dbg("* THIS DEVICE HAS NO DRIVER *");
- }
path_str = NULL; // protect our path from being freed
@@ -732,14 +739,14 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
{
struct windows_device_priv *priv;
struct windows_device_priv *parent_priv;
- char parent_path[MAX_PATH_LENGTH];
+ char path[MAX_PATH_LENGTH];
char reg_key[MAX_KEY_LENGTH];
char *sanitized_path = NULL;
- HDEVINFO dev_info;
+ HDEVINFO dev_info; //, dev_info2;
SP_DEVICE_INTERFACE_DATA dev_interface_data;
SP_DEVICE_INTERFACE_DETAIL_DATA *dev_interface_details = NULL;
SP_DEVINFO_DATA dev_info_data;
- DEVINST parent_devinst;
+ DEVINST parent_devinst; //, child_devinst
GUID guid;
DWORD size, reg_type;
int r = LIBUSB_SUCCESS;
@@ -748,8 +755,12 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
// List all connected devices that are not a hub
guid = GUID_DEVINTERFACE_USB_DEVICE;
- dev_info = SetupDiGetClassDevs(&guid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
+// guid = GUID_DEVINTERFACE_LIBUSB_DEVICE; // Why doesn't this work?!?!
+ dev_info = SetupDiGetClassDevs(&guid, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
+ // "USB\\VID_045E&PID_0289\\7&7EF95EB&0&1"
+ // "USB\\VID_15BA&PID_0004&MI_00\\7&259ca3ed&5&0000"
+ // dev_info = SetupDiGetClassDevsA(NULL, "USB\\VID_15BA&PID_0004&MI_00\\7&259ca3ed&5&0000", NULL, DIGCF_ALLCLASSES|DIGCF_DEVICEINTERFACE);
if (dev_info != INVALID_HANDLE_VALUE)
{
@@ -768,6 +779,8 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
||(r != LIBUSB_SUCCESS) )
break;
+// usbi_dbg("*********i = %d", i);
+
// Read interface data (dummy + actual) to access the device path
if (!SetupDiGetDeviceInterfaceDetail(dev_info, &dev_interface_data, NULL, 0, &size, NULL)) {
// The dummy call should fail with ERROR_INSUFFICIENT_BUFFER
@@ -792,6 +805,8 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
i, windows_error_str());
}
+// usbi_dbg("GOT %s", dev_interface_details->DevicePath);
+
// Retrieve location information (port#) through the Location Information registry data
dev_info_data.cbSize = sizeof(dev_info_data);
if (!SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data)) {
@@ -818,13 +833,13 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
i, windows_error_str());
}
- if (CM_Get_Device_ID(parent_devinst, parent_path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) {
+ if (CM_Get_Device_ID(parent_devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) {
LOOP_CONTINUE("could not retrieve parent's path for device #%u, skipping: %s",
i, windows_error_str());
}
// Fix parent's path inconsistancies before attempting to compare
- sanitized_path = sanitize_path(parent_path);
+ sanitized_path = sanitize_path(path);
if (sanitized_path == NULL) {
LOOP_CONTINUE("could not sanitize parent's path for device #%u, skipping.", i);
}
@@ -841,20 +856,73 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
parent_priv = __device_priv(priv->parent_dev);
if ( (safe_strncmp(parent_priv->path, sanitized_path, strlen(sanitized_path)) == 0) &&
(port_nr == priv->connection_index) ) {
- priv->path = sanitize_path(dev_interface_details->DevicePath);
- usbi_dbg("path (%d:%d): %s", discdevs->devices[j]->bus_number,
- discdevs->devices[j]->device_address, priv->path);
- found = true;
+ safe_free(sanitized_path);
+
+ // before anything, check the service name to know what kind of device we have.
// The service name is really the driver name without ".sys" ("WinUSB", "HidUsb", ...)
- // We store it as it tells which API we should use to access our device
+ // It tells us if we can use WinUSB or if we need to handle a composite device
if(!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_SERVICE,
&reg_type, (BYTE*)reg_key, MAX_KEY_LENGTH, &size)) {
LOOP_CONTINUE("could not retrieve driver information for device #%u, skipping: %s",
i, windows_error_str());
}
- usbi_dbg("driver: %s\n", reg_key);
+ usbi_dbg("driver: %s", reg_key);
+
+ // Composite devices use the USB Common Class Generic Parent driver
+ if (safe_strncmp(reg_key, "usbccgp", MAX_KEY_LENGTH) == 0) {
+ usbi_dbg("composite device %s", dev_interface_details->DevicePath);
+/*
+ // We can't use the ccgp driver for WinUSB. Instead, try the first child
+ if (CM_Get_Child(&child_devinst, dev_info_data.DevInst, 0) != CR_SUCCESS) {
+ LOOP_CONTINUE("could not retrieve child info data for device #%u, skipping: %s",
+ i, windows_error_str());
+ }
+
+ if (CM_Get_Device_ID(child_devinst, path, MAX_PATH_LENGTH, 0) != CR_SUCCESS) {
+ LOOP_CONTINUE("could not retrieve children's path for device #%u, skipping: %s",
+ i, windows_error_str());
+ }
+
+ // Of course, no CM function returns a path that we can actually use with CreateFile
+ // (that would have been too easy), and of course, there's absolutely NO WAY to list
+ // the composite WinUSB devices using SetupDi, because Microsoft decided they should
+ // be 100% invisible to the SetupDi functions...
+
+
+ // Try a call requiring admin privs...
+
+ dev_info2 = SetupDiCreateDeviceInfoList(NULL, NULL);
+ if (dev_info2 == INVALID_HANDLE_VALUE) {
+ usbi_dbg("dammit 1");
+ }
+
+ if (!SetupDiCreateDeviceInfo(dev_info2, "USB\\VID_15BA&PID_0004&MI_00\\7&259ca3ed&5&0000", NULL, NULL, NULL, 0, NULL)) {
+ usbi_dbg("dammit 2: %s", windows_error_str());
+ }
+
+// SetupDiEnumDeviceInterfaces
+*/
+// safe_strncat(path, MAX_PATH_LENGTH, "#{A5DCBF10-6530-11D2-901F-00C04FB951ED}", sizeof("#{A5DCBF10-6530-11D2-901F-00C04FB951ED}"));
+ // sanitized_path = sanitize_path(path);
+ sanitized_path = sanitize_path(dev_interface_details->DevicePath);
+ if (sanitized_path == NULL) {
+ LOOP_CONTINUE("could not sanitize child's path for device #%u, skipping.", i);
+ }
+
+ // TODO: actual check for WinUSB driver on ALL children
+ safe_strncpy(reg_key, MAX_KEY_LENGTH, "WinUSB", sizeof("WinUSB"));
+ usbi_dbg("TODO: FETCH ACTUAL DRIVER (forcing driver to: %s)", reg_key);
+ } else {
+ sanitized_path = sanitize_path(dev_interface_details->DevicePath);
+ }
+
priv->driver = safe_strdup(reg_key);
+ priv->path = sanitized_path;
+ sanitized_path = NULL; // safe loop
+ usbi_dbg("path (%d:%d): %s", discdevs->devices[j]->bus_number,
+ discdevs->devices[j]->device_address, priv->path);
+ found = true;
break;
}
@@ -965,16 +1033,6 @@ static int windows_get_config_descriptor(struct libusb_device *dev, uint8_t conf
}
/*
- * Retrieve the bConfigurationValue for the active configuration for a device.
- * This is meant to be called during init so that the value can be cached
- */
-static int windows_get_active_config(struct libusb_device *dev)
-{
- // TODO: As we don't have control msg I/O yet, force the value to first conf.
- return 1;
-}
-
-/*
* return the cached copy of the active config descriptor
*/
static int windows_get_active_config_descriptor(struct libusb_device *dev, unsigned char *buffer, size_t len, int *host_endian)
@@ -989,10 +1047,36 @@ static int windows_get_active_config_descriptor(struct libusb_device *dev, unsig
return windows_get_config_descriptor(dev, priv->active_config-1, buffer, len, host_endian);
}
+// From libusb-win32
+static OVERLAPPED* create_overlapped(void)
+{
+ OVERLAPPED* io = malloc(sizeof(OVERLAPPED));
+
+ if(io == NULL)
+ return NULL;
+
+ memset(io, 0, sizeof(OVERLAPPED));
+ io->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if(!io->hEvent) {
+ free(io);
+ return NULL;
+ }
+ return io;
+}
+
+// From libusb-win32
+void free_overlapped(OVERLAPPED* io)
+{
+ if(io->hEvent)
+ CloseHandle(io->hEvent);
+ free(io);
+}
+
static int windows_open(struct libusb_device_handle *dev_handle)
{
int r = LIBUSB_SUCCESS;
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;
// Select the API to use
if (safe_strcmp(priv->driver, "WinUSB") == 0) {
@@ -1001,19 +1085,28 @@ static int windows_open(struct libusb_device_handle *dev_handle)
r = LIBUSB_ERROR_NOT_SUPPORTED;
}
- // TODO: setup polling
+ // TODO: update pipe info here?
+ // TODO: HANDLE is a void* which we cast to int => MASSIVE POTENTIAL ISSUE!!!
+ // => provide a lookup table for fd <-> HANDLE ?
+// usbi_dbg("WARNING: casting (HANDLE) %p to (int) 0x%x", handle_priv->file_handle, (int)handle_priv->file_handle);
+// usbi_add_pollfd(HANDLE_CTX(dev_handle), (int)handle_priv->file_handle, POLLIN);
+
return r;
}
static void windows_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;
if (safe_strcmp(priv->driver, "WinUSB") == 0) {
winusb_close(dev_handle);
}
- // TODO: cancel polling
+ // TODO: free pipe?
+ // TODO: HANDLE vs int
+// usbi_remove_pollfd (HANDLE_CTX(dev_handle), (int)handle_priv->file_handle);
+
}
/*
@@ -1116,8 +1209,31 @@ static int submit_iso_transfer(struct usbi_transfer *itransfer)
static int submit_control_transfer(struct usbi_transfer *itransfer)
{
- // TODO: call WinUsb_ControlTransfer
- return LIBUSB_ERROR_NOT_SUPPORTED;
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ OVERLAPPED *io;
+ int r;
+
+ // TODO: is it safe to create io in open?
+ if((io = create_overlapped()) == NULL)
+ return LIBUSB_ERROR_NO_MEM;
+
+ r = winusb_submit_control_transfer(itransfer, io);
+ if (r != LIBUSB_SUCCESS) {
+ free_overlapped(io);
+ return r;
+ }
+
+ // TODO: are transfer reused?
+ transfer_priv->io = io;
+
+ // TODO: we use the OVERLAPPED _pointer_ as a file descriptor with a
+ // *VERY DANGEROUS* cast to _int_)
+ usbi_dbg("WARNING: casting (OVERLAPPED*) %p to (int) 0x%x", io, (int)io);
+ usbi_add_pollfd(ctx, (int)io, POLLIN);
+
+ return LIBUSB_SUCCESS;
}
static int windows_submit_transfer(struct usbi_transfer *itransfer)
@@ -1169,9 +1285,102 @@ static void windows_clear_transfer_priv(struct usbi_transfer *itransfer)
{
}
+static void windows_control_callback (struct usbi_transfer *itransfer, int io_result, uint32_t io_size)
+{
+ int status;
+
+ usbi_dbg("handling control completion with status %d", io_result);
+
+ // TODO
+ switch(io_result) {
+ default:
+ status = LIBUSB_TRANSFER_COMPLETED;
+ itransfer->transferred += io_size;
+ break;
+ }
+
+ usbi_handle_transfer_completion(itransfer, status);
+}
+
+
+static void windows_handle_callback (struct usbi_transfer *itransfer, int io_result, uint32_t io_size)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+
+ switch (transfer->type) {
+ case LIBUSB_TRANSFER_TYPE_CONTROL:
+ windows_control_callback (itransfer, io_result, io_size);
+ break;
+ case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_INTERRUPT:
+// windows_bulk_callback (itransfer, io_result, io_size);
+ break;
+ case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
+ // TODO: ain't gonna happen with WinUSB
+// windows_isoc_callback (itransfer, io_result);
+ break;
+ default:
+ usbi_err(TRANSFER_CTX(transfer), "unknown endpoint type %d", transfer->type);
+ }
+}
+
static int windows_handle_events(struct libusb_context *ctx, struct pollfd *fds, nfds_t nfds, int num_ready)
{
- return LIBUSB_ERROR_NOT_SUPPORTED;
+ struct windows_transfer_priv* transfer_priv = NULL;
+ int i = 0;
+ bool found = false;
+ struct usbi_transfer *transfer;
+ DWORD io_size;
+
+
+// pthread_mutex_lock(&ctx->open_devs_lock);
+ for (i = 0; i < nfds && num_ready > 0; i++) {
+ struct pollfd *pollfd = &fds[i];
+// struct libusb_device_handle *handle;
+// struct windows_device_handle_priv *hpriv = NULL;
+
+ usbi_dbg("checking fd %x with revents = %x", fds[i], pollfd->revents);
+
+ if (!pollfd->revents) {
+ continue;
+ }
+
+ num_ready--;
+
+ list_for_each_entry(transfer, &ctx->flying_transfers, list) {
+ transfer_priv = usbi_transfer_get_os_priv(transfer);
+ if ((int)transfer_priv->io == pollfd->fd) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ if (!GetOverlappedResult(transfer_priv->handle, transfer_priv->io, &io_size, false)) {
+ usbi_err(ctx, "GetOverlappedResult failed: %s", windows_error_str());
+ } else {
+ // Remove the polled "fd"
+ usbi_remove_pollfd(ctx, (int)transfer_priv->io);
+ windows_handle_callback(transfer, 0, io_size);
+ }
+ }
+
+/*
+ list_for_each_entry(handle, &ctx->open_devs, list) {
+ hpriv = (struct windows_device_handle_priv *)handle->os_priv;
+ // TODO: does this actually work?
+ usbi_dbg("pollfd->fd = %x", pollfd->fd);
+ // TODO: HANDLE vs int
+ if ((int)hpriv->io == pollfd->fd) {
+ usbi_dbg("io == fd");
+ break;
+ }
+ }
+*/
+ }
+
+// pthread_mutex_unlock(&ctx->open_devs_lock);
+ return LIBUSB_SUCCESS;
}
/*
@@ -1306,7 +1515,7 @@ static int winusb_open(struct libusb_device_handle *dev_handle)
handle = CreateFileA(priv->path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
if (handle == INVALID_HANDLE_VALUE) {
- usbi_err(ctx, "could not open device: %s", windows_error_str());
+ usbi_err(ctx, "could not open device %s: %s", priv->path, windows_error_str());
// TODO? Create a windows errcode -> libusb errcode function
switch(GetLastError()) {
case ERROR_FILE_NOT_FOUND: // The device was disconnected
@@ -1322,28 +1531,25 @@ static int winusb_open(struct libusb_device_handle *dev_handle)
}
/*
-
-
WINUSB_INTERFACE_HANDLE interface_handle;
USB_INTERFACE_DESCRIPTOR interface_desc;
WINUSB_PIPE_INFORMATION pipe_info;
uint8_t speed, i;
ULONG length;
-
length = sizeof(speed);
if (!WinUsb_QueryDeviceInformation(winusb_handle, DEVICE_SPEED, &length, &speed)) {
usbi_err(ctx, "could not get device speed: %s", windows_error_str());
return LIBUSB_ERROR_IO;
}
- /* TODO:
- * Because the Fx2 device supports only one interface that has no alternative settings,
- * the AlternateSettingNumber parameter is set to zero and the function is called only
- * once. If the device supports multiple interfaces, call WinUsb_GetAssociatedInterface
- * to obtain interface handles for associated interfaces.
- */
-/*
+ // TODO:
+ // Because the Fx2 device supports only one interface that has no alternative settings,
+ // the AlternateSettingNumber parameter is set to zero and the function is called only
+ // once. If the device supports multiple interfaces, call WinUsb_GetAssociatedInterface
+ // to obtain interface handles for associated interfaces.
+
+
if (!WinUsb_QueryInterfaceSettings(winusb_handle, 0, &interface_desc)) {
usbi_err(ctx, "could not get interface settings: %s", windows_error_str());
return LIBUSB_ERROR_IO;
@@ -1379,7 +1585,7 @@ static int winusb_open(struct libusb_device_handle *dev_handle)
*/
static void winusb_close(struct libusb_device_handle *dev_handle)
{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+// 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;
if (!api_winusb_available)
@@ -1449,7 +1655,7 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int i
static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface)
{
- struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+// 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;
CHECK_WINUSB_AVAILABLE;
@@ -1475,3 +1681,38 @@ static int winusb_release_interface(struct libusb_device_handle *dev_handle, int
return LIBUSB_SUCCESS;
}
+
+static int winusb_submit_control_transfer(struct usbi_transfer *itransfer, OVERLAPPED *io)
+{
+ struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
+ struct libusb_context *ctx = DEVICE_CTX(transfer->dev_handle->dev);
+ struct windows_transfer_priv *transfer_priv = usbi_transfer_get_os_priv(itransfer);
+ struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)transfer->dev_handle->os_priv;
+ WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *) transfer->buffer;
+ ULONG size, junk;
+
+ //TODO: multiple interfaces
+ int iface = 0; // Force interface 0
+
+ size = transfer->length - LIBUSB_CONTROL_SETUP_SIZE;
+
+ if (size > MAX_CTRL_BUFFER_LENGTH)
+ return LIBUSB_ERROR_INVALID_PARAM;
+
+ if (!WinUsb_ControlTransfer(handle_priv->interface_handle[iface], *setup, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size, &junk, io)) {
+ if(GetLastError() != ERROR_IO_PENDING) {
+ usbi_err(ctx, "WinUsb_ControlTransfer failed: %s", windows_error_str());
+ return LIBUSB_ERROR_IO;
+ }
+ } else {
+ usbi_err(ctx, "chill out man; this is like way too fast for async I/O...");
+ return LIBUSB_ERROR_IO;
+ }
+
+ // TODO: don't store this is transfer_priv
+ transfer_priv->handle = handle_priv->interface_handle[iface];
+
+ usbi_dbg("overlapped WinUsb_ControlTransfer initiated");
+
+ return LIBUSB_SUCCESS;
+}
diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h
index c070fa8..524fa4f 100644
--- a/libusb/os/windows_usb.h
+++ b/libusb/os/windows_usb.h
@@ -51,6 +51,10 @@
#define safe_sprintf _snprintf
#define safe_unref_device(dev) do {if (dev != NULL) {libusb_unref_device(dev); dev = NULL;}} while(0)
+// #define MAX_ISO_BUFFER_LENGTH 32768
+// #define MAX_BULK_BUFFER_LENGTH 16384
+#define MAX_CTRL_BUFFER_LENGTH 4096
+
#define ROOT_PREFIX "\\\\.\\"
#define MAX_PATH_LENGTH 128
#define MAX_KEY_LENGTH 64
@@ -117,7 +121,7 @@ static inline struct windows_device_priv *__device_priv(struct libusb_device *de
return (struct windows_device_priv *)dev->os_priv;
}
-typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
+typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
struct windows_device_handle_priv {
bool is_open;
@@ -126,7 +130,9 @@ struct windows_device_handle_priv {
};
struct windows_transfer_priv {
- int NOT_IMPLEMENTED;
+ OVERLAPPED* io;
+ HANDLE handle;
+ uint32_t io_size;
};
@@ -219,111 +225,111 @@ typedef struct _USB_HUB_CAPABILITIES_EX {
CTL_CODE( FILE_DEVICE_USB, USB_GET_HUB_CAPABILITIES_EX, \
METHOD_BUFFERED, FILE_ANY_ACCESS )
#endif
-
-/*
- * WinUSB macros - from libusb-win32 1.x
- */
-#pragma once
-
-#define DLL_DECLARE(api, ret, name, args) \
- typedef ret (api * __dll_##name##_t)args; __dll_##name##_t name
-
-#define DLL_LOAD(dll, name, ret_on_failure) \
- do { \
- HMODULE h = GetModuleHandle(#dll); \
- if(!h) \
- h = LoadLibrary(#dll); \
- if(!h) { \
- if(ret_on_failure) \
- return LIBUSB_ERROR_OTHER; \
- else break; } \
- if((name = (__dll_##name##_t)GetProcAddress(h, #name))) \
- break; \
- if((name = (__dll_##name##_t)GetProcAddress(h, #name "A"))) \
- break; \
- if((name = (__dll_##name##_t)GetProcAddress(h, #name "W"))) \
- break; \
- if(ret_on_failure) \
- return LIBUSB_ERROR_OTHER; \
- } while(0)
-
-
-/* winusb.dll interface */
-
-#define SHORT_PACKET_TERMINATE 0x01
-#define AUTO_CLEAR_STALL 0x02
-#define PIPE_TRANSFER_TIMEOUT 0x03
-#define IGNORE_SHORT_PACKETS 0x04
-#define ALLOW_PARTIAL_READS 0x05
-#define AUTO_FLUSH 0x06
-#define RAW_IO 0x07
-#define MAXIMUM_TRANSFER_SIZE 0x08
-#define AUTO_SUSPEND 0x81
-#define SUSPEND_DELAY 0x83
-#define DEVICE_SPEED 0x01
-#define LowSpeed 0x01
-#define FullSpeed 0x02
-#define HighSpeed 0x03
-
-typedef enum _USBD_PIPE_TYPE {
- UsbdPipeTypeControl,
- UsbdPipeTypeIsochronous,
- UsbdPipeTypeBulk,
- UsbdPipeTypeInterrupt
-} USBD_PIPE_TYPE;
-
-typedef struct {
- USBD_PIPE_TYPE PipeType;
- UCHAR PipeId;
- USHORT MaximumPacketSize;
- UCHAR Interval;
-} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION;
-
-#pragma pack(1)
-typedef struct {
- UCHAR request_type;
- UCHAR request;
- USHORT value;
- USHORT index;
- USHORT length;
-} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET;
-#pragma pack()
-
-DLL_DECLARE(WINAPI, BOOL, WinUsb_Initialize,
- (HANDLE, PWINUSB_INTERFACE_HANDLE));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_Free, (WINUSB_INTERFACE_HANDLE));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_GetAssociatedInterface,
- (WINUSB_INTERFACE_HANDLE, UCHAR, PWINUSB_INTERFACE_HANDLE));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_GetDescriptor,
- (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, USHORT, PUCHAR,
- ULONG, PULONG));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryInterfaceSettings,
- (WINUSB_INTERFACE_HANDLE, UCHAR, PUSB_INTERFACE_DESCRIPTOR));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryDeviceInformation,
- (WINUSB_INTERFACE_HANDLE, ULONG, PULONG, PVOID));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_SetCurrentAlternateSetting,
- (WINUSB_INTERFACE_HANDLE, UCHAR));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_GetCurrentAlternateSetting,
- (WINUSB_INTERFACE_HANDLE, PUCHAR));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryPipe,
- (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR,
- PWINUSB_PIPE_INFORMATION));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_SetPipePolicy,
- (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, ULONG, PVOID));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_GetPipePolicy,
- (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, PULONG, PVOID));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_ReadPipe,
- (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG,
- LPOVERLAPPED));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_WritePipe,
- (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG,
- LPOVERLAPPED));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_ControlTransfer,
- (WINUSB_INTERFACE_HANDLE, WINUSB_SETUP_PACKET, PUCHAR, ULONG,
- PULONG, LPOVERLAPPED));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_ResetPipe,
- (WINUSB_INTERFACE_HANDLE, UCHAR));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_AbortPipe,
- (WINUSB_INTERFACE_HANDLE, UCHAR));
-DLL_DECLARE(WINAPI, BOOL, WinUsb_FlushPipe,
- (WINUSB_INTERFACE_HANDLE, UCHAR));
+
+/*
+ * WinUSB macros - from libusb-win32 1.x
+ */
+#pragma once
+
+#define DLL_DECLARE(api, ret, name, args) \
+ typedef ret (api * __dll_##name##_t)args; __dll_##name##_t name
+
+#define DLL_LOAD(dll, name, ret_on_failure) \
+ do { \
+ HMODULE h = GetModuleHandle(#dll); \
+ if(!h) \
+ h = LoadLibrary(#dll); \
+ if(!h) { \
+ if(ret_on_failure) \
+ return LIBUSB_ERROR_OTHER; \
+ else break; } \
+ if((name = (__dll_##name##_t)GetProcAddress(h, #name))) \
+ break; \
+ if((name = (__dll_##name##_t)GetProcAddress(h, #name "A"))) \
+ break; \
+ if((name = (__dll_##name##_t)GetProcAddress(h, #name "W"))) \
+ break; \
+ if(ret_on_failure) \
+ return LIBUSB_ERROR_OTHER; \
+ } while(0)
+
+
+/* winusb.dll interface */
+
+#define SHORT_PACKET_TERMINATE 0x01
+#define AUTO_CLEAR_STALL 0x02
+#define PIPE_TRANSFER_TIMEOUT 0x03
+#define IGNORE_SHORT_PACKETS 0x04
+#define ALLOW_PARTIAL_READS 0x05
+#define AUTO_FLUSH 0x06
+#define RAW_IO 0x07
+#define MAXIMUM_TRANSFER_SIZE 0x08
+#define AUTO_SUSPEND 0x81
+#define SUSPEND_DELAY 0x83
+#define DEVICE_SPEED 0x01
+#define LowSpeed 0x01
+#define FullSpeed 0x02
+#define HighSpeed 0x03
+
+typedef enum _USBD_PIPE_TYPE {
+ UsbdPipeTypeControl,
+ UsbdPipeTypeIsochronous,
+ UsbdPipeTypeBulk,
+ UsbdPipeTypeInterrupt
+} USBD_PIPE_TYPE;
+
+typedef struct {
+ USBD_PIPE_TYPE PipeType;
+ UCHAR PipeId;
+ USHORT MaximumPacketSize;
+ UCHAR Interval;
+} WINUSB_PIPE_INFORMATION, *PWINUSB_PIPE_INFORMATION;
+
+#pragma pack(1)
+typedef struct {
+ UCHAR request_type;
+ UCHAR request;
+ USHORT value;
+ USHORT index;
+ USHORT length;
+} WINUSB_SETUP_PACKET, *PWINUSB_SETUP_PACKET;
+#pragma pack()
+
+DLL_DECLARE(WINAPI, BOOL, WinUsb_Initialize,
+ (HANDLE, PWINUSB_INTERFACE_HANDLE));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_Free, (WINUSB_INTERFACE_HANDLE));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetAssociatedInterface,
+ (WINUSB_INTERFACE_HANDLE, UCHAR, PWINUSB_INTERFACE_HANDLE));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetDescriptor,
+ (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR, USHORT, PUCHAR,
+ ULONG, PULONG));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryInterfaceSettings,
+ (WINUSB_INTERFACE_HANDLE, UCHAR, PUSB_INTERFACE_DESCRIPTOR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryDeviceInformation,
+ (WINUSB_INTERFACE_HANDLE, ULONG, PULONG, PVOID));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_SetCurrentAlternateSetting,
+ (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetCurrentAlternateSetting,
+ (WINUSB_INTERFACE_HANDLE, PUCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_QueryPipe,
+ (WINUSB_INTERFACE_HANDLE, UCHAR, UCHAR,
+ PWINUSB_PIPE_INFORMATION));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_SetPipePolicy,
+ (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, ULONG, PVOID));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_GetPipePolicy,
+ (WINUSB_INTERFACE_HANDLE, UCHAR, ULONG, PULONG, PVOID));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_ReadPipe,
+ (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG,
+ LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_WritePipe,
+ (WINUSB_INTERFACE_HANDLE, UCHAR, PUCHAR, ULONG, PULONG,
+ LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_ControlTransfer,
+ (WINUSB_INTERFACE_HANDLE, WINUSB_SETUP_PACKET, PUCHAR, ULONG,
+ PULONG, LPOVERLAPPED));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_ResetPipe,
+ (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_AbortPipe,
+ (WINUSB_INTERFACE_HANDLE, UCHAR));
+DLL_DECLARE(WINAPI, BOOL, WinUsb_FlushPipe,
+ (WINUSB_INTERFACE_HANDLE, UCHAR));