summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/xusb.c49
-rw-r--r--libusb/os/windows_usb.c253
-rw-r--r--libusb/os/windows_usb.h6
3 files changed, 244 insertions, 64 deletions
diff --git a/examples/xusb.c b/examples/xusb.c
index 43e1ca7..686392d 100644
--- a/examples/xusb.c
+++ b/examples/xusb.c
@@ -25,6 +25,29 @@
#include <libusb/libusb.h>
+//#define USE_MOUSE
+#define USE_XBOX
+
+#ifdef USE_MOUSE
+// Logitech optical mouse
+#define VID 0x046D
+#define PID 0xC03E
+#endif
+
+#ifdef USE_XBOX
+// Microsoft XBox Controller
+#define VID 0x045E
+#define PID 0x0289
+#endif
+
+#ifdef USE_KEY
+// 2 GB Usb key
+#define VID 0x0204
+#define PID 0x6025
+#endif
+
+
+
static void print_devs(libusb_device **devs)
{
libusb_device *dev;
@@ -44,11 +67,31 @@ static void print_devs(libusb_device **devs)
libusb_get_bus_number(dev), libusb_get_device_address(dev));
// DEBUG: Access an XBox gamepad through WinUSB
- if ((desc.idVendor == 0x045e) && (desc.idProduct == 0x0289)) {
- printf("Opening Xbox gamepad:\n");
+// if ((desc.idVendor == 0x045e) && (desc.idProduct == 0x0289)) {
+ if ((desc.idVendor == VID) && (desc.idProduct == PID)) {
+ printf("Opening device:\n");
r = libusb_open(dev, &handle);
- if (r != LIBUSB_SUCCESS)
+ if (r != LIBUSB_SUCCESS) {
+ printf("libusb error: %d\n", r);
+ continue;
+ }
+
+ printf("Claiming interface:\n");
+ r = libusb_claim_interface(handle, 0);
+ if (r != LIBUSB_SUCCESS) {
printf("libusb error: %d\n", r);
+ continue;
+ }
+
+ printf("Releasing interface:\n");
+ r = libusb_release_interface(handle, 0);
+ if (r != LIBUSB_SUCCESS) {
+ printf("libusb error: %d\n", r);
+ continue;
+ }
+
+ printf("Closing device:\n");
+ libusb_close(handle);
}
}
}
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index 438fa26..dd75422 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -83,6 +83,8 @@ static int winusb_api_init(struct libusb_context *ctx);
static int winusb_api_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);
+static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface);
// HCD private chained list
struct windows_hcd_priv* hcd_root = NULL;
@@ -92,7 +94,7 @@ uint64_t hires_frequency, hires_ticks_to_ps;
const uint64_t epoch_time = 116444736000000000;
DWORD_PTR old_affinity_mask;
bool api_winusb_available = false;
-#define CHECK_WINUSB_AVAILABLE do { if (!api_winusb_available) return LIBUSB_ERROR_NOT_SUPPORTED; } while (0)
+#define CHECK_WINUSB_AVAILABLE do { if (!api_winusb_available) return LIBUSB_ERROR_ACCESS; } while (0)
/*
* Converts a WCHAR string to UTF8 (allocate returned string)
@@ -577,7 +579,7 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs
if (conn_info.ConnectionStatus == NoDeviceConnected) {
continue;
- }
+ }
if (conn_info.DeviceAddress == 0) {
LOOP_CONTINUE("program assertion failed - device address is zero "
@@ -661,6 +663,13 @@ static int usb_enumerate_hub(struct libusb_context *ctx, struct discovered_devs
LOOP_CHECK(initialize_device(dev, busnum, devaddr, path_str, i, 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
// Setup the cached descriptors. Note that only non HCDs can fetch descriptors
@@ -690,6 +699,8 @@ 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,
@@ -739,12 +750,14 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
guid = GUID_DEVINTERFACE_USB_DEVICE;
dev_info = SetupDiGetClassDevs(&guid, NULL, NULL, (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
+
if (dev_info != INVALID_HANDLE_VALUE)
{
dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
for (i = 0; ; i++)
{
+
// safe loop: free up any (unprotected) dynamic resource
safe_free(dev_interface_details);
safe_free(sanitized_path);
@@ -800,7 +813,7 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
}
// Retrieve parent's path using PnP Configuration Manager (CM)
- if (CM_Get_Parent(&parent_devinst, dev_info_data.DevInst, 0) != CR_SUCCESS) {
+ if (CM_Get_Parent(&parent_devinst, dev_info_data.DevInst, 0) != CR_SUCCESS) {
LOOP_CONTINUE("could not retrieve parent info data for device #%u, skipping: %s",
i, windows_error_str());
}
@@ -832,6 +845,17 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
usbi_dbg("path (%d:%d): %s", discdevs->devices[j]->bus_number,
discdevs->devices[j]->device_address, priv->path);
found = true;
+
+ // 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
+ 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);
+ priv->driver = safe_strdup(reg_key);
+
break;
}
}
@@ -968,10 +992,14 @@ static int windows_get_active_config_descriptor(struct libusb_device *dev, unsig
static int windows_open(struct libusb_device_handle *dev_handle)
{
int r = LIBUSB_SUCCESS;
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
- r = winusb_open(dev_handle);
- if (r != LIBUSB_SUCCESS)
- return r;
+ // Select the API to use
+ if (safe_strcmp(priv->driver, "WinUSB") == 0) {
+ r = winusb_open(dev_handle);
+ } else {
+ r = LIBUSB_ERROR_NOT_SUPPORTED;
+ }
// TODO: setup polling
return r;
@@ -979,7 +1007,12 @@ static int windows_open(struct libusb_device_handle *dev_handle)
static void windows_close(struct libusb_device_handle *dev_handle)
{
- winusb_close(dev_handle);
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+
+ if (safe_strcmp(priv->driver, "WinUSB") == 0) {
+ winusb_close(dev_handle);
+ }
+
// TODO: cancel polling
}
@@ -1007,12 +1040,33 @@ static int windows_set_configuration(struct libusb_device_handle *dev_handle, in
static int windows_claim_interface(struct libusb_device_handle *dev_handle, int iface)
{
- return LIBUSB_ERROR_NOT_SUPPORTED;
+ int r = LIBUSB_SUCCESS;
+
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+
+ // Select the API to use
+ if (safe_strcmp(priv->driver, "WinUSB") == 0) {
+ r = winusb_claim_interface(dev_handle, iface);
+ } else {
+ r = LIBUSB_ERROR_NOT_SUPPORTED;
+ }
+
+ return r;
}
static int windows_release_interface(struct libusb_device_handle *dev_handle, int iface)
{
- return LIBUSB_ERROR_NOT_SUPPORTED;
+ int r = LIBUSB_SUCCESS;
+ struct windows_device_priv *priv = __device_priv(dev_handle->dev);
+
+ // Select the API to use
+ if (safe_strcmp(priv->driver, "WinUSB") == 0) {
+ r = winusb_release_interface(dev_handle, iface);
+ } else {
+ r = LIBUSB_ERROR_NOT_SUPPORTED;
+ }
+
+ return r;
}
static int windows_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
@@ -1062,6 +1116,7 @@ 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;
}
@@ -1227,7 +1282,6 @@ static int winusb_api_init(struct libusb_context *ctx)
static int winusb_api_exit(void)
{
- CHECK_WINUSB_AVAILABLE;
api_winusb_available = false;
return LIBUSB_SUCCESS;
}
@@ -1242,11 +1296,6 @@ static int winusb_open(struct libusb_device_handle *dev_handle)
struct windows_device_handle_priv *handle_priv = (struct windows_device_handle_priv *)dev_handle->os_priv;
HANDLE handle;
- WINUSB_INTERFACE_HANDLE winusb_handle;
- USB_INTERFACE_DESCRIPTOR interface_desc;
- WINUSB_PIPE_INFORMATION pipe_info;
- uint8_t speed, i;
- ULONG length;
CHECK_WINUSB_AVAILABLE;
/*
@@ -1270,19 +1319,23 @@ static int winusb_open(struct libusb_device_handle *dev_handle)
}
handle_priv->file_handle = handle;
+}
- if (!WinUsb_Initialize(handle, &winusb_handle)) {
- usbi_err(ctx, "could not initialize WinUSB: %s", windows_error_str());
- return LIBUSB_ERROR_IO;
- }
+/*
+
+
+ WINUSB_INTERFACE_HANDLE interface_handle;
+ USB_INTERFACE_DESCRIPTOR interface_desc;
+ WINUSB_PIPE_INFORMATION pipe_info;
+ uint8_t speed, i;
+ ULONG length;
- handle_priv->winusb_handle = winusb_handle;
-
- length = sizeof(speed);
- if (!WinUsb_QueryDeviceInformation(winusb_handle, DEVICE_SPEED, &length, &speed)) {
+
+ 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,
@@ -1290,55 +1343,135 @@ static int winusb_open(struct libusb_device_handle *dev_handle)
* 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)) {
+/*
+ if (!WinUsb_QueryInterfaceSettings(winusb_handle, 0, &interface_desc)) {
usbi_err(ctx, "could not get interface settings: %s", windows_error_str());
return LIBUSB_ERROR_IO;
- }
-
- for(i=0; i<interface_desc.bNumEndpoints; i++)
- {
- if (!WinUsb_QueryPipe(winusb_handle, 0, i, &pipe_info)) {
+ }
+
+ for(i=0; i<interface_desc.bNumEndpoints; i++)
+ {
+ if (!WinUsb_QueryPipe(winusb_handle, 0, i, &pipe_info)) {
usbi_err(ctx, "could not query pipe: %s", windows_error_str());
return LIBUSB_ERROR_IO;
- }
-
- if (pipe_info.PipeType == UsbdPipeTypeBulk && USB_ENDPOINT_DIRECTION_IN(pipe_info.PipeId)) {
- usbi_dbg("pipe %d: bulk In pipe", i);
-// bulk_in_pipe = pipe_info.PipeId;
- }
- else if(pipe_info.PipeType == UsbdPipeTypeBulk && USB_ENDPOINT_DIRECTION_OUT(pipe_info.PipeId)) {
- usbi_dbg("pipe %d: bulk Out pipe", i);
-// bulk_out_pipe = pipe_info.PipeId;
- }
- else if(pipe_info.PipeType == UsbdPipeTypeInterrupt) {
- usbi_dbg("pipe %d: interrupt pipe", i);
-// interrupt_pipe = pipe_info.PipeId;
- }
- else {
- usbi_dbg("%d: ceci n'est pas un(e) pipe", i);
- break;
- }
- }
+ }
+
+ if (pipe_info.PipeType == UsbdPipeTypeBulk && USB_ENDPOINT_DIRECTION_IN(pipe_info.PipeId)) {
+ usbi_dbg("pipe %d: bulk In pipe", i);
+// bulk_in_pipe = pipe_info.PipeId;
+ }
+ else if(pipe_info.PipeType == UsbdPipeTypeBulk && USB_ENDPOINT_DIRECTION_OUT(pipe_info.PipeId)) {
+ usbi_dbg("pipe %d: bulk Out pipe", i);
+// bulk_out_pipe = pipe_info.PipeId;
+ }
+ else if(pipe_info.PipeType == UsbdPipeTypeInterrupt) {
+ usbi_dbg("pipe %d: interrupt pipe", i);
+// interrupt_pipe = pipe_info.PipeId;
+ }
+ else {
+ usbi_dbg("%d: ceci n'est pas un(e) pipe", i);
+ break;
+ }
+ }
return LIBUSB_SUCCESS;
}
-
+*/
static void winusb_close(struct libusb_device_handle *dev_handle)
{
+ 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)
+ return;
- if (api_winusb_available)
- {
- // libusb_open zeroes the priv struct, which is different from INVALID_HANDLE_VALUE (-1)
- // However: http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2005-05/msg00448.html
- // "On any NT-derived platform 0 (zero) can never be a valid handle value" so we should be OK
- if ((handle_priv->winusb_handle != 0) && (handle_priv->winusb_handle != INVALID_HANDLE_VALUE)) {
- WinUsb_Free(handle_priv->winusb_handle);
+ if ((handle_priv->file_handle != 0) && (handle_priv->file_handle != INVALID_HANDLE_VALUE)) {
+ CloseHandle(handle_priv->file_handle);
+ }
+}
+
+/* Claim an interface. When claimed, the application can then perform
+ * I/O to an interface's endpoints.
+ *
+ * Return:
+ * - LIBUSB_ERROR_NOT_FOUND if the interface does not exist
+ * - LIBUSB_ERROR_BUSY if the interface is in use by another driver/app
+ * - LIBUSB_ERROR_NO_DEVICE if the device has been disconnected since it
+ * was opened
+ * - another LIBUSB_ERROR code on other failure
+ */
+static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ 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;
+
+/*
+ usbi_dbg("testing detached device: disconnect NOW!");
+ Sleep(2000);
+*/
+
+ // TODO
+ if (iface != 0) {
+ usbi_dbg("mutliple interfaces not supported yet");
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ }
+
+ if ((handle_priv->interface_handle[iface] != 0) && (handle_priv->interface_handle[iface] != INVALID_HANDLE_VALUE)) {
+ return LIBUSB_ERROR_BUSY;
+ }
+
+ if ((handle_priv->file_handle == 0) || (handle_priv->file_handle == INVALID_HANDLE_VALUE)) {
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ // The handle returned by WinUsb_Initialize is the first interface handle
+ if (!WinUsb_Initialize(handle_priv->file_handle, &handle_priv->interface_handle[0])) {
+ usbi_err(ctx, "could not claim interface 0: %s", windows_error_str());
+
+ switch(GetLastError()) {
+ case ERROR_BAD_COMMAND: // The device was disconnected
+ return LIBUSB_ERROR_NO_DEVICE;
+ default:
+ return LIBUSB_ERROR_ACCESS;
}
+
+ // TODO: check error for LIBUSB_ERROR_BUSY
+ handle_priv->interface_handle[0] = INVALID_HANDLE_VALUE;
+ return LIBUSB_ERROR_IO;
}
- if ((handle_priv->file_handle != 0) && (handle_priv->file_handle != INVALID_HANDLE_VALUE)) {
- CloseHandle(handle_priv->file_handle);
+ // TODO: for other interface handles, use WinUsb_GetAssociatedInterface
+
+ return LIBUSB_SUCCESS;
+}
+
+static int winusb_release_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ 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;
+
+ // TODO
+ if (iface != 0) {
+ usbi_dbg("mutliple interfaces not supported yet");
+ return LIBUSB_ERROR_NOT_SUPPORTED;
}
+
+ if ((handle_priv->file_handle == 0) || (handle_priv->file_handle == INVALID_HANDLE_VALUE)) {
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ // libusb_open zeroes the priv struct, which is different from INVALID_HANDLE_VALUE (-1)
+ // However: http://www.tech-archive.net/Archive/Development/microsoft.public.win32.programmer.kernel/2005-05/msg00448.html
+ // "On any NT-derived platform 0 (zero) can never be a valid handle value", therefore we should be OK
+ if ((handle_priv->interface_handle[iface] != 0) && (handle_priv->interface_handle[iface] != INVALID_HANDLE_VALUE)) {
+ WinUsb_Free(handle_priv->interface_handle[iface]);
+ } else {
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ return LIBUSB_SUCCESS;
}
diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h
index 76b31d8..c070fa8 100644
--- a/libusb/os/windows_usb.h
+++ b/libusb/os/windows_usb.h
@@ -80,11 +80,13 @@ static inline void windows_hcd_priv_release(struct windows_hcd_priv* p) {
safe_free(p->path);
}
+
// Nodes (Hubs & devices)
struct windows_device_priv {
struct libusb_device *parent_dev; // access to parent is required for usermode ops
ULONG connection_index; // also required for some usermode ops
char *path; // path used by Windows to reference the USB node
+ char *driver; // driver name (eg WinUSB, USBSTOR, HidUsb, etc)
uint8_t active_config;
USB_DEVICE_DESCRIPTOR dev_descriptor;
unsigned char **config_descriptor; // list of pointers to the cached config descriptors
@@ -94,6 +96,7 @@ 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->active_config = 0;
p->config_descriptor = NULL;
memset(&(p->dev_descriptor), 0, sizeof(USB_DEVICE_DESCRIPTOR));
@@ -102,6 +105,7 @@ 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]);
@@ -118,7 +122,7 @@ typedef void *WINUSB_INTERFACE_HANDLE, *PWINUSB_INTERFACE_HANDLE;
struct windows_device_handle_priv {
bool is_open;
HANDLE file_handle;
- WINUSB_INTERFACE_HANDLE winusb_handle;
+ WINUSB_INTERFACE_HANDLE interface_handle[USB_MAXINTERFACES];
};
struct windows_transfer_priv {