summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPete Batard <pbatard@gmail.com>2010-01-22 20:25:55 +0000
committerPete Batard <pbatard@gmail.com>2010-01-22 20:25:55 +0000
commitc7fa44ff83cba5d58c058510fced820fab906332 (patch)
treec9588901138dfc225599206af6bd1cb87250b3ba
parentf0d3526217ba42fdd6d4103753f805a6dcaa1561 (diff)
downloadlibusb-c7fa44ff83cba5d58c058510fced820fab906332.tar.gz
r103: HID part 3 (WIP)
- get_interface_details() now has an optional SP_DEVINFO_DATA parameter - usbi_handle_transfer_cancellation() now called from windows_cancel_transfer() - set_report/get_report (WIP) and improved HID support functions - better support for sync I/O in hid_submit_control_transfer - hid_abort_transfers
-rw-r--r--README_MSVC.txt4
-rw-r--r--libusb/os/windows_usb.c798
-rw-r--r--libusb/os/windows_usb.h56
3 files changed, 487 insertions, 371 deletions
diff --git a/README_MSVC.txt b/README_MSVC.txt
index 248d419..e557164 100644
--- a/README_MSVC.txt
+++ b/README_MSVC.txt
@@ -1,7 +1,7 @@
To compile libusb 1.0 using either Microsoft Visual Studio or the Windows DDK
-Note 1: For Visual Studio, two set of solution files are provided depending on
-whether you are running Visual Studio 2008 (MSVC9) or Visual Studio 2005
+Note 1: For Visual Studio, 3 sets of solution files are provided depending on
+whether you are running MSVC6, Visual Studio 2008 (MSVC9) or Visual Studio 2005
(MSVC8). For the DDK, the 'sources' file is located in libusb\os\.
Note 2: In the text below, (Win32) means "when producing 32 bit binaries" and
diff --git a/libusb/os/windows_usb.c b/libusb/os/windows_usb.c
index f37f36a..3c8b7f6 100644
--- a/libusb/os/windows_usb.c
+++ b/libusb/os/windows_usb.c
@@ -59,7 +59,7 @@ const GUID GUID_NULL = { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00,
const GUID GUID_HID = { 0x745A17A0, 0x74D3, 0x11D0, {0xB6, 0xFE, 0x00, 0xA0, 0xC9, 0x0F, 0x57, 0xDA} };
const GUID GUID_LIBUSB_WINUSB = { 0x78a1c341, 0x4539, 0x11d3, {0xb8, 0x8d, 0x00, 0xc0, 0x4f, 0xad, 0x51, 0x71} };
const GUID GUID_COMPOSITE = { 0x36fc9e60, 0xc465, 0x11cf, {0x80, 0x56, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} };
-const GUID GUID_MEDIA = { 0x4d36e96c, 0xe325, 0x11ce, {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18} };
+const GUID GUID_MEDIA_IF = { 0x6994AD04, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} };
// The 2 macros below are used in conjunction with safe loops.
#define LOOP_CHECK(fcall) { r=fcall; if (r != LIBUSB_SUCCESS) continue; }
@@ -90,7 +90,9 @@ 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);
+static int hid_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting);
static int hid_submit_control_transfer(struct usbi_transfer *itransfer);
+static int hid_abort_transfers(struct usbi_transfer *itransfer);
// Composite API prototypes
static int composite_init(struct libusb_context *ctx);
static int composite_exit(void);
@@ -242,6 +244,7 @@ static char* sanitize_path(const char* path)
*
* Parameters:
* dev_info: a pointer to a dev_info list
+ * dev_info_data: a pointer to an SP_DEVINFO_DATA to be filled (or NULL if not needed)
* guid: the GUID for which to retrieve interface details
* index: zero based index of the interface in the device info list
*
@@ -249,7 +252,8 @@ static char* sanitize_path(const char* path)
* structure returned and call this function repeatedly using the same guid (with an
* incremented index starting at zero) until all interfaces have been returned.
*/
-SP_DEVICE_INTERFACE_DETAIL_DATA *get_interface_details(struct libusb_context *ctx, HDEVINFO* dev_info, GUID guid, unsigned index)
+SP_DEVICE_INTERFACE_DETAIL_DATA *get_interface_details(struct libusb_context *ctx,
+ HDEVINFO *dev_info, SP_DEVINFO_DATA *dev_info_data, GUID guid, unsigned index)
{
SP_DEVICE_INTERFACE_DATA dev_interface_data;
SP_DEVICE_INTERFACE_DETAIL_DATA *dev_interface_details = NULL;
@@ -263,9 +267,25 @@ SP_DEVICE_INTERFACE_DETAIL_DATA *get_interface_details(struct libusb_context *ct
return NULL;
}
- dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
+ if (dev_info_data != NULL) {
+ dev_info_data->cbSize = sizeof(SP_DEVINFO_DATA);
+ if (!SetupDiEnumDeviceInfo(*dev_info, index, dev_info_data)) {
+ if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+ usbi_err(ctx, "Could not device info data for index %u: %s",
+ index, windows_error_str(0));
+ }
+ SetupDiDestroyDeviceInfoList(*dev_info);
+ *dev_info = INVALID_HANDLE_VALUE;
+ return NULL;
+ }
+ }
+ dev_interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if (!SetupDiEnumDeviceInterfaces(*dev_info, NULL, &guid, index, &dev_interface_data)) {
+ if (GetLastError() != ERROR_NO_MORE_ITEMS) {
+ usbi_err(ctx, "Could not obtain interface data for index %u: %s",
+ index, windows_error_str(0));
+ }
SetupDiDestroyDeviceInfoList(*dev_info);
*dev_info = INVALID_HANDLE_VALUE;
return NULL;
@@ -411,7 +431,7 @@ static int windows_init(struct libusb_context *ctx)
safe_free(dev_interface_details);
safe_free(*_hcd_cur);
- dev_interface_details = get_interface_details(ctx, &dev_info, guid, bus);
+ dev_interface_details = get_interface_details(ctx, &dev_info, NULL, guid, bus);
// safe loop: end of loop condition
if ((dev_interface_details == NULL) || (r != LIBUSB_SUCCESS))
break;
@@ -839,6 +859,12 @@ 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)
{
+enum libusb_hid_report_type {
+ HID_DEVICE_INTERFACE_GUID_INDEX = 0,
+ MEDIA_DEVICE_INTERFACE_GUID_INDEX = 1,
+ MAX_DEVICE_INTERFACE_GUID_INDEX = 2
+};
+
DEVINST child_devinst, parent_devinst;
unsigned i, j, max_guids, nb_paths, interface_number;
uint8_t api;
@@ -866,10 +892,10 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str
// Manually add the HID GUID as it cannot be read with DeviceInterfaceGUIDs reg key)
// NB the value returned by HidD_GetHidGuid, which is for interface class is different from GUID_HID
- HidD_GetHidGuid(&guid_table[0]);
- // TODO: figure out iface GUID for AUDIO
-// guid_table[1] = GUID_USBAUDIO;
- max_guids = 1;
+ HidD_GetHidGuid(&guid_table[HID_DEVICE_INTERFACE_GUID_INDEX]);
+ guid_table[MEDIA_DEVICE_INTERFACE_GUID_INDEX] = GUID_MEDIA_IF;
+ // TODO: use SetupDiClassGuidsFromName?
+ max_guids = MAX_DEVICE_INTERFACE_GUID_INDEX;
// First, retrieve all the device interface GUIDs
for (i = 0; ; i++)
@@ -926,28 +952,20 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str
for (j=0; j<max_guids; j++)
{
guid = guid_table[j];
+// usbi_dbg("GUID %d: %s", j, guid_to_string(guid_table[j]));
+
for (i = 0; ; i++)
{
safe_free(dev_interface_details);
- dev_interface_details = get_interface_details(ctx, &dev_info, guid, i);
+ dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, guid, i);
if (dev_interface_details == NULL)
break;
// usbi_dbg("device: %s", dev_interface_details->DevicePath);
- // For now, we weed out all non WinUSB interfaces (which can happen
- // with a mix of WinUSB and proprietary drivers on composite devices)
- // If other APIs are supported, other drivers need to be added
- 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;
- }
-
// HID devices (and possibly other classes) have an extra indirection
// for an USB path we can recognize
- if (j == 0) {
+ if (j == HID_DEVICE_INTERFACE_GUID_INDEX) {
if (CM_Get_Parent(&parent_devinst, dev_info_data.DevInst, 0) != CR_SUCCESS) {
usbi_warn(ctx, "could not retrieve HID parent info data for device %s, skipping: %s",
dev_interface_details->DevicePath, windows_error_str(0));
@@ -972,11 +990,8 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str
CLSIDFromString(guid_string_w, &class_guid);
// Attempt to read the driver string
- if(SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_SERVICE,
+ if(!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_SERVICE,
NULL, (BYTE*)driver, MAX_KEY_LENGTH, &size)) {
- usbi_dbg("driver: %s", driver);
- } else {
- usbi_dbg("driver: N/A, using ClassGUID: %s", guid_to_string(class_guid));
driver[0] = 0;
}
@@ -984,7 +999,7 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str
if ( (safe_strcmp(driver, usb_api_backend[api].driver_name) == 0)
|| (guid_eq(&class_guid, usb_api_backend[api].class_guid)) ) {
api_type[nb_paths] = api;
- if (j == 0) { // HID
+ if (j == HID_DEVICE_INTERFACE_GUID_INDEX) {
hid_path[nb_paths] = sanitize_path(path);
} else {
hid_path[nb_paths] = NULL;
@@ -1046,11 +1061,11 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str
// TODO: change this to debug?
usbi_warn(ctx, "failure to read interface number for %s. Using default value %d",
sanitized_short, interface_number);
- }
+ }
for (j=0; j<nb_paths; j++) {
if ( (safe_strncmp(sanitized_path[j], sanitized_short, strlen(sanitized_short)) == 0)
- || (safe_strcmp(hid_path[j], sanitized_short) == 0 ) ){
+ || (safe_strcmp(hid_path[j], sanitized_short) == 0 ) ) {
priv->usb_interface[interface_number].path = sanitized_path[j];
priv->usb_interface[interface_number].apib = &usb_api_backend[api_type[j]];
if ((api_type[j] == USB_API_HID) && (priv->hid == NULL)) {
@@ -1063,7 +1078,7 @@ static int set_composite_device(struct libusb_context *ctx, DEVINST devinst, str
safe_free(sanitized_short);
if (priv->usb_interface[interface_number].path == NULL) {
- usbi_warn(ctx, "interface_path[%d]: unable to retreive path - interface will be disabled",
+ usbi_warn(ctx, "interface_path[%d]: unhandled API - interface will be disabled",
interface_number);
continue;
}
@@ -1108,19 +1123,12 @@ static int set_hid_device(struct libusb_context *ctx, struct windows_device_priv
safe_free(dev_interface_details);
safe_free(sanitized_path);
- dev_interface_details = get_interface_details(ctx, &dev_info, guid, i);
+ dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, 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",
@@ -1183,19 +1191,12 @@ static int set_device_paths(struct libusb_context *ctx, struct discovered_devs *
safe_free(dev_interface_details);
safe_free(sanitized_path);
- dev_interface_details = get_interface_details(ctx, &dev_info, guid, i);
+ dev_interface_details = get_interface_details(ctx, &dev_info, &dev_info_data, 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;
- }
-
// The SPDRP_ADDRESS for USB devices should be the device port number on the hub
if ( (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data, SPDRP_ADDRESS,
&reg_type, (BYTE*)&port_nr, 4, &size))
@@ -1641,18 +1642,21 @@ static int windows_cancel_transfer(struct usbi_transfer *itransfer)
switch (transfer->type) {
case LIBUSB_TRANSFER_TYPE_CONTROL:
- return windows_abort_control(itransfer);
+ windows_abort_control(itransfer);
+ break;
case LIBUSB_TRANSFER_TYPE_BULK:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
- return windows_abort_transfers(itransfer);
+ windows_abort_transfers(itransfer);
+ break;
default:
usbi_err(ITRANSFER_CTX(itransfer), "unknown endpoint type %d", transfer->type);
- return LIBUSB_ERROR_INVALID_PARAM;
+ break;
}
+ return usbi_handle_transfer_cancellation(itransfer);
}
-static void windows_transfer_callback (struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
+static void windows_transfer_callback(struct usbi_transfer *itransfer, uint32_t io_result, uint32_t io_size)
{
int status;
@@ -1944,15 +1948,15 @@ const struct windows_usb_api_backend usb_api_backend[USB_API_MAX] = {
hid_open,
hid_close,
hid_claim_interface,
- unsupported_set_interface_altsetting,
+ hid_set_interface_altsetting,
hid_release_interface,
unsupported_clear_halt,
unsupported_reset_device,
unsupported_submit_bulk_transfer,
unsupported_submit_iso_transfer,
hid_submit_control_transfer,
- unsupported_abort_control,
- unsupported_abort_transfers,
+ hid_abort_transfers,
+ hid_abort_transfers,
},
};
@@ -2021,7 +2025,7 @@ static int winusb_open(struct libusb_device_handle *dev_handle)
return LIBUSB_ERROR_IO;
}
}
- handle_priv->interface_handle[i].winusb_file = file_handle;
+ handle_priv->interface_handle[i].dev_handle = file_handle;
}
}
@@ -2040,7 +2044,7 @@ static void winusb_close(struct libusb_device_handle *dev_handle)
for (i = 0; i < USB_MAXINTERFACES; i++) {
if (priv->usb_interface[i].apib->id == USB_API_WINUSB) {
- file_handle = handle_priv->interface_handle[i].winusb_file;
+ file_handle = handle_priv->interface_handle[i].dev_handle;
if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) {
CloseHandle(file_handle);
}
@@ -2062,20 +2066,20 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int i
CHECK_WINUSB_AVAILABLE;
- winusb_handle = handle_priv->interface_handle[iface].handle;
+ winusb_handle = handle_priv->interface_handle[iface].api_handle;
// interfaces for composite devices are always independent, therefore
// "alt" interfaces are only found on non-composite
if ((!is_composite) && (iface != 0)) {
// It is a requirement on Windows that to claim an interface >= 1
- // on a non-composite device, you must first have claimed interface 0
+ // on a non-composite WinUSB device, you must first have claimed interface 0
if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) {
return LIBUSB_ERROR_ACCESS;
}
if (!WinUsb_GetAssociatedInterface(winusb_handle, (UCHAR)iface-1,
- &handle_priv->interface_handle[iface].handle)) {
- handle_priv->interface_handle[iface].handle = INVALID_HANDLE_VALUE;
+ &handle_priv->interface_handle[iface].api_handle)) {
+ handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
switch(GetLastError()) {
case ERROR_NO_MORE_ITEMS: // invalid iface
return LIBUSB_ERROR_NOT_FOUND;
@@ -2090,14 +2094,14 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int i
}
} else {
// composite device (independent interfaces) or interface 0
- file_handle = handle_priv->interface_handle[iface].winusb_file;
+ file_handle = handle_priv->interface_handle[iface].dev_handle;
if ((file_handle == 0) || (file_handle == INVALID_HANDLE_VALUE)) {
return LIBUSB_ERROR_NOT_FOUND;
}
if (!WinUsb_Initialize(file_handle, &winusb_handle)) {
usbi_err(ctx, "could not access interface %d: %s", iface, windows_error_str(0));
- handle_priv->interface_handle[iface].handle = INVALID_HANDLE_VALUE;
+ handle_priv->interface_handle[iface].api_handle = INVALID_HANDLE_VALUE;
switch(GetLastError()) {
case ERROR_BAD_COMMAND: // The device was disconnected
@@ -2107,7 +2111,7 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int i
return LIBUSB_ERROR_ACCESS;
}
}
- handle_priv->interface_handle[iface].handle = winusb_handle;
+ handle_priv->interface_handle[iface].api_handle = winusb_handle;
}
if (!WinUsb_QueryInterfaceSettings(winusb_handle, 0, &if_desc)) {
usbi_err(ctx, "could not query interface settings for interface %d: %s", iface, windows_error_str(0));
@@ -2154,7 +2158,7 @@ static int winusb_release_interface(struct libusb_device_handle *dev_handle, int
CHECK_WINUSB_AVAILABLE;
- winusb_handle = handle_priv->interface_handle[iface].handle;
+ winusb_handle = handle_priv->interface_handle[iface].api_handle;
if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) {
return LIBUSB_ERROR_NOT_FOUND;
}
@@ -2173,8 +2177,10 @@ static int get_valid_interface(struct libusb_device_handle *dev_handle)
int i;
for (i=0; i<USB_MAXINTERFACES; i++) {
- if ( (handle_priv->interface_handle[i].handle != 0)
- && (handle_priv->interface_handle[i].handle != INVALID_HANDLE_VALUE)) {
+ if ( (handle_priv->interface_handle[i].dev_handle != 0)
+ && (handle_priv->interface_handle[i].dev_handle != INVALID_HANDLE_VALUE)
+ && (handle_priv->interface_handle[i].api_handle != 0)
+ && (handle_priv->interface_handle[i].api_handle != INVALID_HANDLE_VALUE)) {
return i;
}
}
@@ -2189,9 +2195,9 @@ static int interface_by_endpoint(struct windows_device_priv *priv,
{
int i, j;
for (i=0; i<USB_MAXINTERFACES; i++) {
- if (handle_priv->interface_handle[i].handle == INVALID_HANDLE_VALUE)
+ if (handle_priv->interface_handle[i].api_handle == INVALID_HANDLE_VALUE)
continue;
- if (handle_priv->interface_handle[i].handle == 0)
+ if (handle_priv->interface_handle[i].api_handle == 0)
continue;
if (priv->usb_interface[i].endpoint == NULL)
continue;
@@ -2240,7 +2246,7 @@ static int winusb_submit_control_transfer(struct usbi_transfer *itransfer)
}
usbi_dbg("will use interface %d", current_interface);
- winusb_handle = handle_priv->interface_handle[current_interface].handle;
+ winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
wfd = create_fd_for_poll(winusb_handle, _O_RDONLY);
if (wfd.fd < 0) {
@@ -2277,7 +2283,7 @@ static int winusb_set_interface_altsetting(struct libusb_device_handle *dev_hand
return LIBUSB_ERROR_INVALID_PARAM;
}
- winusb_handle = handle_priv->interface_handle[iface].handle;
+ winusb_handle = handle_priv->interface_handle[iface].api_handle;
if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) {
usbi_err(ctx, "interface must be claimed first");
return LIBUSB_ERROR_NOT_FOUND;
@@ -2315,7 +2321,7 @@ static int winusb_submit_bulk_transfer(struct usbi_transfer *itransfer)
usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
- winusb_handle = handle_priv->interface_handle[current_interface].handle;
+ winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
direction_in = transfer->endpoint & LIBUSB_ENDPOINT_IN;
wfd = create_fd_for_poll(winusb_handle, direction_in?_O_RDONLY:_O_WRONLY);
@@ -2369,7 +2375,7 @@ static int winusb_clear_halt(struct libusb_device_handle *dev_handle, unsigned c
}
usbi_dbg("matched endpoint %02X with interface %d", endpoint, current_interface);
- winusb_handle = handle_priv->interface_handle[current_interface].handle;
+ winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
if (!WinUsb_ResetPipe(winusb_handle, endpoint)) {
usbi_err(ctx, "WinUsb_ResetPipe failed: %s", windows_error_str(0));
@@ -2402,6 +2408,7 @@ static int winusb_abort_transfers(struct usbi_transfer *itransfer)
CHECK_WINUSB_AVAILABLE;
+ // TODO: why don't we use transfer_priv->interface_number here???
current_interface = interface_by_endpoint(priv, handle_priv, transfer->endpoint);
if (current_interface < 0) {
usbi_err(ctx, "unable to match endpoint to an open interface - cancelling abort");
@@ -2410,7 +2417,7 @@ static int winusb_abort_transfers(struct usbi_transfer *itransfer)
usbi_dbg("matched endpoint %02X with interface %d", transfer->endpoint, current_interface);
- winusb_handle = handle_priv->interface_handle[current_interface].handle;
+ winusb_handle = handle_priv->interface_handle[current_interface].api_handle;
if (!WinUsb_AbortPipe(winusb_handle, transfer->endpoint)) {
usbi_err(ctx, "WinUsb_AbortPipe failed: %s", windows_error_str(0));
@@ -2441,7 +2448,7 @@ static int winusb_reset_device(struct libusb_device_handle *dev_handle)
// Reset any available pipe (except control)
for (i=0; i<USB_MAXINTERFACES; i++) {
- winusb_handle = handle_priv->interface_handle[i].handle;
+ winusb_handle = handle_priv->interface_handle[i].api_handle;
for (wfd = handle_to_winfd(winusb_handle); wfd.fd > 0;)
{
// Cancel any pollable I/O
@@ -2477,186 +2484,23 @@ static int winusb_reset_device(struct libusb_device_handle *dev_handle)
/*
- * HID API functions
+ * Internal HID Support functions (from libusb-win32)
+ * Note that functions that complete data transfer synchronously must return
+ * LIBUSB_COMPLETED instead of LIBUSB_SUCCESS
*/
-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;
-
- HIDD_ATTRIBUTES hid_attributes;
- PHIDP_PREPARSED_DATA preparsed_data = NULL;
- HIDP_CAPS capabilities;
-
- HANDLE hid_handle = INVALID_HANDLE_VALUE;
- int i;
-
- CHECK_HID_AVAILABLE;
- if (priv->hid == NULL) {
- usbi_err(ctx, "program assertion failed - private HID structure is unitialized");
- return LIBUSB_ERROR_NOT_FOUND;
- }
-
- // 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) ) {
- hid_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)."
- */
- if (hid_handle == INVALID_HANDLE_VALUE) {
- usbi_warn(ctx, "could not open HID device in R/W mode (keyboard or mouse?) - trying without");
- // TODO: can we confirm KB/mouse?
- hid_handle = CreateFileA(priv->usb_interface[i].path, 0, FILE_SHARE_WRITE | FILE_SHARE_READ,
- NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
- if (hid_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].handle = hid_handle;
- }
- }
- if (hid_handle == INVALID_HANDLE_VALUE) {
- usbi_err(ctx, "unable to open HID device");
- return LIBUSB_ERROR_NO_DEVICE;
- }
-
- // TODO: more comprehensive error messages
- hid_attributes.Size = sizeof(hid_attributes);
- do {
- if(!HidD_GetAttributes(hid_handle, &hid_attributes)) {
- usbi_err(ctx, "HidD_GetAttributes() failed");
- break;
- }
-
- priv->hid->vid = hid_attributes.VendorID;
- priv->hid->pid = hid_attributes.ProductID;
-
- /* set the maximum available input buffer size */
- i = 32;
- while(HidD_SetNumInputBuffers(hid_handle, i))
- i *= 2;
-
- /* get the maximum input and output report size */
- if(!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) {
- usbi_err(ctx, "HidD_GetPreparsedData() failed");
- break;
- }
- if(HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) {
- usbi_err(ctx, "HidP_GetCaps() failed");
- break;
- }
- priv->hid->output_report_size = capabilities.OutputReportByteLength;
- priv->hid->input_report_size = capabilities.InputReportByteLength;
- priv->hid->feature_report_size = capabilities.FeatureReportByteLength;
-
- /* fetch string descriptors */
- HidD_GetManufacturerString(hid_handle, priv->hid->man_string,
- sizeof(priv->hid->man_string));
- HidD_GetProductString(hid_handle, priv->hid->prod_string,
- sizeof(priv->hid->prod_string));
- HidD_GetSerialNumberString(hid_handle, priv->hid->ser_string,
- sizeof(priv->hid->ser_string));
- } while(0);
-
- if(preparsed_data)
- HidD_FreePreparsedData(preparsed_data);
-
- 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].handle;
- if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) {
- CloseHandle(file_handle);
- }
- }
- }
-}
-
-static int hid_claim_interface(struct libusb_device_handle *dev_handle, int iface)
-{
- return LIBUSB_SUCCESS;
-}
-
-static int hid_release_interface(struct libusb_device_handle *dev_handle, int iface)
-{
- return LIBUSB_SUCCESS;
-}
+static int _hid_get_hid_descriptor(struct hid_device_priv* dev, void *data, int *size);
+static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, int *size);
static int _hid_wcslen(WCHAR *str)
{
- int ret = 0;
- while(*str && *str != 0x409) {
- ret++;
- str++;
+ int i = 0;
+ while (str[i] && (str[i] != 0x409)) {
+ i++;
}
- return ret;
+ return i;
}
-static int _hid_get_device_descriptor(struct hid_device_priv* dev, void *data, int size);
-static int _hid_get_config_descriptor(struct hid_device_priv* dev, void *data, int size);
-static int _hid_get_string_descriptor(struct hid_device_priv* dev, int index, void *data, int size);
-static int _hid_get_hid_descriptor(struct hid_device_priv* dev, void *data, int size);
-static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, int size);
-
-static int _hid_get_device_descriptor(struct hid_device_priv* dev, void *data, int size)
+static int _hid_get_device_descriptor(struct hid_device_priv* dev, void *data, int *size)
{
struct libusb_device_descriptor d;
@@ -2675,13 +2519,13 @@ static int _hid_get_device_descriptor(struct hid_device_priv* dev, void *data, i
d.iSerialNumber = _hid_wcslen(dev->ser_string) ? 3 : 0;
d.bNumConfigurations = 1;
- if(size > LIBUSB_DT_DEVICE_SIZE)
- size = LIBUSB_DT_DEVICE_SIZE;
- memcpy(data, &d, size);
- return size;
+ if (*size > LIBUSB_DT_DEVICE_SIZE)
+ *size = LIBUSB_DT_DEVICE_SIZE;
+ memcpy(data, &d, *size);
+ return LIBUSB_COMPLETED;
}
-static int _hid_get_config_descriptor(struct hid_device_priv* dev, void *data, int size)
+static int _hid_get_config_descriptor(struct hid_device_priv* dev, void *data, int *size)
{
char num_endpoints = 0;
int config_total_len = 0;
@@ -2690,10 +2534,11 @@ static int _hid_get_config_descriptor(struct hid_device_priv* dev, void *data, i
struct libusb_interface_descriptor *id;
struct libusb_hid_descriptor *hd;
struct libusb_endpoint_descriptor *ed;
+ int tmp_size;
- if(dev->input_report_size)
+ if (dev->input_report_size)
num_endpoints++;
- if(dev->output_report_size)
+ if (dev->output_report_size)
num_endpoints++;
config_total_len = LIBUSB_DT_CONFIG_SIZE + LIBUSB_DT_INTERFACE_SIZE
@@ -2727,9 +2572,10 @@ static int _hid_get_config_descriptor(struct hid_device_priv* dev, void *data, i
id->bInterfaceProtocol = 0;
id->iInterface = 0;
- _hid_get_hid_descriptor(dev, hd, LIBUSB_DT_HID_SIZE);
+ tmp_size = LIBUSB_DT_HID_SIZE;
+ _hid_get_hid_descriptor(dev, hd, &tmp_size);
- if(dev->input_report_size) {
+ if (dev->input_report_size) {
ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
ed->bEndpointAddress = HID_IN_EP;
@@ -2740,7 +2586,7 @@ static int _hid_get_config_descriptor(struct hid_device_priv* dev, void *data, i
ed++;
}
- if(dev->output_report_size) {
+ if (dev->output_report_size) {
ed->bLength = LIBUSB_DT_ENDPOINT_SIZE;
ed->bDescriptorType = LIBUSB_DT_ENDPOINT;
ed->bEndpointAddress = HID_OUT_EP;
@@ -2749,68 +2595,73 @@ static int _hid_get_config_descriptor(struct hid_device_priv* dev, void *data, i
ed->bInterval = 10;
}
- if(size > config_total_len)
- size = config_total_len;
- memcpy(data, tmp, size);
- return size;
+ if (*size > config_total_len)
+ *size = config_total_len;
+ memcpy(data, tmp, *size);
+ return LIBUSB_COMPLETED;
}
static int _hid_get_string_descriptor(struct hid_device_priv* dev, int index,
- void *data, int size)
+ void *data, int *size)
{
void *tmp = NULL;
int tmp_size = 0;
/* language ID, EN-US */
char string_langid[] = {
- 4,
- LIBUSB_DT_STRING,
0x09,
0x04
};
+ if ((*size < 2) || (*size > 255)) {
+ return LIBUSB_ERROR_OVERFLOW;
+ }
+
usbi_dbg("index = %d", index);
switch(index) {
case 0:
tmp = string_langid;
- tmp_size = 4;
+ tmp_size = sizeof(string_langid)+2;
break;
case 1:
tmp = dev->man_string;
- tmp_size = _hid_wcslen(dev->man_string) * sizeof(WCHAR);
+ tmp_size = (_hid_wcslen(dev->man_string)+1) * sizeof(WCHAR);
break;
case 2:
tmp = dev->prod_string;
- tmp_size = _hid_wcslen(dev->prod_string) * sizeof(WCHAR);
+ tmp_size = (_hid_wcslen(dev->prod_string)+1) * sizeof(WCHAR);
usbi_dbg("tmp_size = %d", tmp_size);
break;
case 3:
tmp = dev->ser_string;
- tmp_size = _hid_wcslen(dev->ser_string) * sizeof(WCHAR);
+ tmp_size = (_hid_wcslen(dev->ser_string)+1) * sizeof(WCHAR);
break;
default:
return LIBUSB_ERROR_INVALID_PARAM;
}
- if(!tmp_size)
+ if(!tmp_size) {
return LIBUSB_ERROR_INVALID_PARAM;
+ }
- // TODO: why is it needed to hack this?
- if(tmp_size > size)
- tmp_size = size;
- memcpy((char*)data+2, tmp, tmp_size);
- ((char*)data)[1] = LIBUSB_DT_STRING;
- ((char*)data)[0] = tmp_size+2;
- return tmp_size+2;
+ if (tmp_size < *size) {
+ *size = tmp_size;
+ }
+ // 2 byte header
+ ((uint8_t*)data)[0] = (uint8_t)*size;
+ ((uint8_t*)data)[1] = LIBUSB_DT_STRING;
+ memcpy((uint8_t*)data+2, tmp, *size-2);
+ return LIBUSB_COMPLETED;
}
-static int _hid_get_hid_descriptor(struct hid_device_priv* dev, void *data, int size)
+static int _hid_get_hid_descriptor(struct hid_device_priv* dev, void *data, int *size)
{
struct libusb_hid_descriptor d;
- char tmp[256];
- int report_len;
+ uint8_t tmp[MAX_HID_DESCRIPTOR_SIZE];
+ int report_len, tmp_size;
- report_len = _hid_get_report_descriptor(dev, tmp, sizeof(tmp));
+ tmp_size = sizeof(tmp);
+ report_len = _hid_get_report_descriptor(dev, tmp, &tmp_size);
d.bLength = LIBUSB_DT_HID_SIZE;
d.bDescriptorType = LIBUSB_DT_HID;
@@ -2820,15 +2671,15 @@ static int _hid_get_hid_descriptor(struct hid_device_priv* dev, void *data, int
d.bClassDescriptorType = LIBUSB_DT_REPORT;
d.wClassDescriptorLength = (uint16_t)report_len;
- if(size > LIBUSB_DT_HID_SIZE)
- size = LIBUSB_DT_HID_SIZE;
- memcpy(data, &d, size);
- return size;
+ if (*size > LIBUSB_DT_HID_SIZE)
+ *size = LIBUSB_DT_HID_SIZE;
+ memcpy(data, &d, *size);
+ return LIBUSB_COMPLETED;
}
-static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, int size)
+static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, int *size)
{
- unsigned char d[256];
+ uint8_t d[MAX_HID_DESCRIPTOR_SIZE];
int i = 0;
/* usage page (0xFFA0 == vendor defined) */
@@ -2838,7 +2689,7 @@ static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, i
/* start collection (application) */
d[i++] = 0xA1; d[i++] = 0x01;
/* input report */
- if(dev->input_report_size) {
+ if (dev->input_report_size) {
/* usage (vendor defined) */
d[i++] = 0x09; d[i++] = 0x01;
/* logical minimum (0) */
@@ -2848,12 +2699,12 @@ static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, i
/* report size (8 bits) */
d[i++] = 0x75; d[i++] = 0x08;
/* report count */
- d[i++] = 0x95; d[i++] = (unsigned char)dev->input_report_size - 1;
+ d[i++] = 0x95; d[i++] = (uint8_t)dev->input_report_size - 1;
/* input (data, variable, absolute) */
d[i++] = 0x81; d[i++] = 0x00;
}
/* output report */
- if(dev->output_report_size) {
+ if (dev->output_report_size) {
/* usage (vendor defined) */
d[i++] = 0x09; d[i++] = 0x02;
/* logical minimum (0) */
@@ -2863,21 +2714,21 @@ static int _hid_get_report_descriptor(struct hid_device_priv* dev, void *data, i
/* report size (8 bits) */
d[i++] = 0x75; d[i++] = 0x08;
/* report count */
- d[i++] = 0x95; d[i++] = (unsigned char)dev->output_report_size - 1;
+ d[i++] = 0x95; d[i++] = (uint8_t)dev->output_report_size - 1;
/* output (data, variable, absolute) */
d[i++] = 0x91; d[i++] = 0x00;
}
/* end collection */
d[i++] = 0xC0;
- if(size > i)
- size = i;
- memcpy(data, d, size);
- return size;
+ if (*size > i)
+ *size = i;
+ memcpy(data, d, *size);
+ return LIBUSB_COMPLETED;
}
static int _hid_get_descriptor(struct hid_device_priv* dev, HANDLE hid_handle, int recipient,
- int type, int index, void *data, int size)
+ int type, int index, void *data, int *size)
{
switch(type) {
case LIBUSB_DT_DEVICE:
@@ -2885,7 +2736,7 @@ static int _hid_get_descriptor(struct hid_device_priv* dev, HANDLE hid_handle, i
return _hid_get_device_descriptor(dev, data, size);
case LIBUSB_DT_CONFIG:
usbi_dbg("LIBUSB_DT_CONFIG");
- if(!index)
+ if (!index)
return _hid_get_config_descriptor(dev, data, size);
return LIBUSB_ERROR_INVALID_PARAM;
case LIBUSB_DT_STRING:
@@ -2893,111 +2744,132 @@ static int _hid_get_descriptor(struct hid_device_priv* dev, HANDLE hid_handle, i
return _hid_get_string_descriptor(dev, index, data, size);
case LIBUSB_DT_HID:
usbi_dbg("LIBUSB_DT_HID");
- if(!index)
+ if (!index)
return _hid_get_hid_descriptor(dev, data, size);
return LIBUSB_ERROR_INVALID_PARAM;
case LIBUSB_DT_REPORT:
usbi_dbg("LIBUSB_DT_REPORT");
- if(!index)
+ if (!index)
return _hid_get_report_descriptor(dev, data, size);
return LIBUSB_ERROR_INVALID_PARAM;
case LIBUSB_DT_PHYSICAL:
usbi_dbg("LIBUSB_DT_PHYSICAL");
- if(HidD_GetPhysicalDescriptor(hid_handle, data, size))
- return size;
+ if (HidD_GetPhysicalDescriptor(hid_handle, data, (ULONG)size))
+ return LIBUSB_COMPLETED;
return LIBUSB_ERROR_OTHER;
}
usbi_dbg("unsupported");
return LIBUSB_ERROR_INVALID_PARAM;
}
-static int _hid_get_report(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data, int size)
+static int _hid_get_report(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data,
+ int *size, OVERLAPPED* overlapped)
{
uint8_t buf[HID_MAX_REPORT_SIZE + 1];
- if(size >MAX_HID_REPORT_SIZE)
+ if (*size >MAX_HID_REPORT_SIZE)
return LIBUSB_ERROR_INVALID_PARAM;
buf[0] = (uint8_t)id;
- if(HidD_GetInputReport && HidD_GetInputReport(hid_handle, buf, size + 1))
- return size + 1;
-// TODO:
-// return winio_write_sync(hid_handle, buf, size + 1, USBI_DEFAULT_TIMEOUT);
- return -1;
+ *size += 1;
+ // Use ReadFile instead of HidD_GetInputReport for async I/O
+ if (!ReadFile(hid_handle, buf, *size, NULL, overlapped)) {
+ if(GetLastError() != ERROR_IO_PENDING) {
+ usbi_dbg("READFILE FAILED");
+ return LIBUSB_ERROR_IO;
+ }
+ usbi_dbg("IO_PENDING");
+ } else {
+ usbi_dbg("IO_SYNC");
+ return LIBUSB_COMPLETED;
+ }
+
+ return LIBUSB_SUCCESS;
}
-static int _hid_set_report(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data, int size)
+static int _hid_set_report(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data,
+ int *size, OVERLAPPED* overlapped)
{
uint8_t buf[HID_MAX_REPORT_SIZE + 1];
- if(size >MAX_HID_REPORT_SIZE)
+ if (*size >MAX_HID_REPORT_SIZE)
return LIBUSB_ERROR_INVALID_PARAM;
buf[0] = (uint8_t)id;
- memcpy(buf + 1, data, size);
+ memcpy(buf + 1, data, *size);
- if(HidD_SetOutputReport && HidD_SetOutputReport(hid_handle, buf, size + 1))
- return size + 1;
-// TODO:
-// return winio_write_sync(hid_handle, buf, size + 1, USBI_DEFAULT_TIMEOUT);
- return -1;
+ *size += 1;
+ // Une WriteFile instead of HidD_SetOutputReport for async I/O
+ if (!WriteFile(hid_handle, buf, *size, NULL, overlapped)) {
+ if (GetLastError() != ERROR_IO_PENDING) {
+ return LIBUSB_ERROR_IO;
+ }
+ } else {
+ return LIBUSB_COMPLETED;
+ }
+
+ return LIBUSB_SUCCESS;
}
-static int _hid_get_feature(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data, int size)
+static int _hid_get_feature(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data, int *size)
{
uint8_t buf[HID_MAX_REPORT_SIZE + 1];
- if(size >MAX_HID_REPORT_SIZE)
+ if (*size >MAX_HID_REPORT_SIZE)
return LIBUSB_ERROR_INVALID_PARAM;
buf[0] = (uint8_t)id;
- if(HidD_GetFeature(hid_handle, buf, size + 1))
- return size + 1;
+ *size += 1;
+ if (HidD_GetFeature(hid_handle, buf, *size)) {
+ return LIBUSB_COMPLETED;
+ }
return LIBUSB_ERROR_OTHER;
}
-static int _hid_set_feature(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data, int size)
+static int _hid_set_feature(struct hid_device_priv* dev, HANDLE hid_handle, int id, void *data, int *size)
{
uint8_t buf[HID_MAX_REPORT_SIZE + 1];
- if(size >MAX_HID_REPORT_SIZE)
+ if (*size >MAX_HID_REPORT_SIZE)
return LIBUSB_ERROR_INVALID_PARAM;
buf[0] = (uint8_t)id;
- memcpy(buf + 1, data, size);
+ memcpy(buf + 1, data, *size);
- if(HidD_SetFeature(hid_handle, buf, size + 1))
- return size + 1;
+ *size += 1;
+ if (HidD_SetFeature(hid_handle, buf, *size)) {
+ return LIBUSB_COMPLETED;
+ }
return LIBUSB_ERROR_OTHER;
}
static int _hid_class_request(struct hid_device_priv* dev, HANDLE hid_handle, int request_type,
- int request, int value, int index, void *data, int size)
+ int request, int value, int index, void *data, int *size, OVERLAPPED* overlapped)
{
int report_type = (value >> 8) & 0xFF;
int report_id = value & 0xFF;
- if(LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_INTERFACE)
+ if (LIBUSB_REQ_RECIPIENT(request_type) != LIBUSB_RECIPIENT_INTERFACE)
return LIBUSB_ERROR_INVALID_PARAM;
- if(LIBUSB_REQ_OUT(request_type)
+ if (LIBUSB_REQ_OUT(request_type)
&& request == HID_REQ_SET_REPORT
&& report_type == HID_REPORT_TYPE_OUTPUT)
- return _hid_set_report(dev, hid_handle, report_id, data, size);
+ return _hid_set_report(dev, hid_handle, report_id, data, size, overlapped);
- if(LIBUSB_REQ_IN(request_type)
+ if (LIBUSB_REQ_IN(request_type)
&& request == HID_REQ_GET_REPORT
&& report_type == HID_REPORT_TYPE_INPUT)
- return _hid_get_report(dev, hid_handle, report_id, data, size);
+ return _hid_get_report(dev, hid_handle, report_id, data, size, overlapped);
- if(LIBUSB_REQ_OUT(request_type)
+ if (LIBUSB_REQ_OUT(request_type)
&& request == HID_REQ_SET_REPORT
&& report_type == HID_REPORT_TYPE_FEATURE)
return _hid_set_feature(dev, hid_handle, report_id, data, size);
- if(LIBUSB_REQ_OUT(request_type)
+ if (LIBUSB_REQ_OUT(request_type)
&& request == HID_REQ_SET_REPORT
&& report_type == HID_REPORT_TYPE_FEATURE)
return _hid_get_feature(dev, hid_handle, report_id, data, size);
@@ -3005,6 +2877,221 @@ static int _hid_class_request(struct hid_device_priv* dev, HANDLE hid_handle, in
return LIBUSB_ERROR_INVALID_PARAM;
}
+
+/*
+ * 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;
+
+ HIDD_ATTRIBUTES hid_attributes;
+ PHIDP_PREPARSED_DATA preparsed_data = NULL;
+ HIDP_CAPS capabilities;
+
+ HANDLE hid_handle = INVALID_HANDLE_VALUE;
+ int i;
+
+ CHECK_HID_AVAILABLE;
+ if (priv->hid == NULL) {
+ usbi_err(ctx, "program assertion failed - private HID structure is unitialized");
+ return LIBUSB_ERROR_NOT_FOUND;
+ }
+
+ // 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) ) {
+ hid_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)."
+ */
+ if (hid_handle == INVALID_HANDLE_VALUE) {
+ usbi_warn(ctx, "could not open HID device in R/W mode (keyboard or mouse?) - trying without");
+ // TODO: can we confirm KB/mouse?
+ hid_handle = CreateFileA(priv->usb_interface[i].path, 0, FILE_SHARE_WRITE | FILE_SHARE_READ,
+ NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
+ if (hid_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].api_handle = hid_handle;
+ }
+ }
+
+ // TODO: more comprehensive error messages
+ hid_attributes.Size = sizeof(hid_attributes);
+ do {
+ if(!HidD_GetAttributes(hid_handle, &hid_attributes)) {
+ usbi_err(ctx, "HidD_GetAttributes() failed");
+ break;
+ }
+
+ priv->hid->vid = hid_attributes.VendorID;
+ priv->hid->pid = hid_attributes.ProductID;
+
+ /* set the maximum available input buffer size */
+ i = 32;
+ while(HidD_SetNumInputBuffers(hid_handle, i))
+ i *= 2;
+
+ /* get the maximum input and output report size */
+ if(!HidD_GetPreparsedData(hid_handle, &preparsed_data) || !preparsed_data) {
+ usbi_err(ctx, "HidD_GetPreparsedData() failed");
+ break;
+ }
+ if(HidP_GetCaps(preparsed_data, &capabilities) != HIDP_STATUS_SUCCESS) {
+ usbi_err(ctx, "HidP_GetCaps() failed");
+ break;
+ }
+ priv->hid->output_report_size = capabilities.OutputReportByteLength;
+ priv->hid->input_report_size = capabilities.InputReportByteLength;
+ priv->hid->feature_report_size = capabilities.FeatureReportByteLength;
+
+ /* fetch string descriptors */
+ HidD_GetManufacturerString(hid_handle, priv->hid->man_string,
+ sizeof(priv->hid->man_string));
+ HidD_GetProductString(hid_handle, priv->hid->prod_string,
+ sizeof(priv->hid->prod_string));
+ HidD_GetSerialNumberString(hid_handle, priv->hid->ser_string,
+ sizeof(priv->hid->ser_string));
+ } while(0);
+
+ if(preparsed_data)
+ HidD_FreePreparsedData(preparsed_data);
+
+ 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].api_handle;
+ if ( (file_handle != 0) && (file_handle != INVALID_HANDLE_VALUE)) {
+ CloseHandle(file_handle);
+ }
+ }
+ }
+}
+
+static int hid_claim_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ 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);
+
+ CHECK_HID_AVAILABLE;
+
+ // TODO: device disconected (return LIBUSB_ERROR_NO_DEVICE;)
+
+ if (priv->usb_interface[iface].path == NULL) {
+ return LIBUSB_ERROR_NOT_FOUND; // invalid iface
+ }
+
+ // We use dev_handle as a flag for interface claimed
+ if (handle_priv->interface_handle[iface].dev_handle == INTERFACE_CLAIMED) {
+ return LIBUSB_ERROR_BUSY; // already claimed
+ }
+
+ handle_priv->interface_handle[iface].dev_handle = INTERFACE_CLAIMED;
+
+ usbi_dbg("claimed interface %d", iface);
+ handle_priv->active_interface = iface;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int hid_release_interface(struct libusb_device_handle *dev_handle, int iface)
+{
+ 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);
+
+ CHECK_HID_AVAILABLE;
+
+ if (priv->usb_interface[iface].path == NULL) {
+ return LIBUSB_ERROR_NOT_FOUND; // invalid iface
+ }
+
+ if (handle_priv->interface_handle[iface].dev_handle != INTERFACE_CLAIMED) {
+ return LIBUSB_ERROR_NOT_FOUND; // invalid iface
+ }
+
+ handle_priv->interface_handle[iface].dev_handle = INVALID_HANDLE_VALUE;
+
+ return LIBUSB_SUCCESS;
+}
+
+static int hid_set_interface_altsetting(struct libusb_device_handle *dev_handle, int iface, int altsetting)
+{
+ struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
+
+ CHECK_HID_AVAILABLE;
+
+ if (altsetting > 255) {
+ return LIBUSB_ERROR_INVALID_PARAM;
+ }
+
+ if (altsetting != 0) {
+ usbi_err(ctx, "set interface altsetting not supported for altsetting >0");
+ return LIBUSB_ERROR_NOT_SUPPORTED;
+ }
+
+ return LIBUSB_SUCCESS;
+}
+
static int hid_submit_control_transfer(struct usbi_transfer *itransfer)
{
struct libusb_transfer *transfer = __USBI_TRANSFER_TO_LIBUSB_TRANSFER(itransfer);
@@ -3013,7 +3100,7 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer)
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);
WINUSB_SETUP_PACKET *setup = (WINUSB_SETUP_PACKET *) transfer->buffer;
- ULONG size;
+ int size;
HANDLE hid_handle;
int current_interface;
struct winfd wfd;
@@ -3047,7 +3134,7 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer)
}
usbi_dbg("will use interface %d", current_interface);
- hid_handle = handle_priv->interface_handle[current_interface].handle;
+ hid_handle = handle_priv->interface_handle[current_interface].api_handle;
wfd = create_fd_for_poll(hid_handle, _O_RDONLY);
if (wfd.fd < 0) {
@@ -3058,17 +3145,10 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer)
case LIBUSB_REQUEST_TYPE_STANDARD:
switch(setup->request) {
case LIBUSB_REQUEST_GET_DESCRIPTOR:
+ usbi_dbg("sent size: %d", size);
r = _hid_get_descriptor(priv->hid, hid_handle, LIBUSB_REQ_RECIPIENT(setup->request_type),
- (setup->value >> 8) & 0xFF, setup->value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size);
- if (r>=0) {
- // Force request to be completed synchronously
- // TODO: Move this further down -
- wfd.completed_synchronously = true;
- // http://msdn.microsoft.com/en-us/library/ms684342%28VS.85%29.aspx
- // set InternalHigh to the number of bytes transferred
- wfd.overlapped->InternalHigh = (DWORD)r;
- r = LIBUSB_SUCCESS;
- }
+ (setup->value >> 8) & 0xFF, setup->value & 0xFF, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size);
+ usbi_dbg("got size: %d", size);
break;
default:
break;
@@ -3076,19 +3156,51 @@ static int hid_submit_control_transfer(struct usbi_transfer *itransfer)
break;
case LIBUSB_REQUEST_TYPE_CLASS:
r =_hid_class_request(priv->hid, hid_handle, setup->request_type, setup->request, setup->value,
- setup->index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, size);
+ setup->index, transfer->buffer + LIBUSB_CONTROL_SETUP_SIZE, &size, wfd.overlapped);
break;
default:
break;
}
+ if (r == LIBUSB_COMPLETED) {
+ // Force request to be completed synchronously. Transferred size has been set by previous call
+ wfd.completed_synchronously = true;
+ // http://msdn.microsoft.com/en-us/library/ms684342%28VS.85%29.aspx
+ // set InternalHigh to the number of bytes transferred
+ wfd.overlapped->InternalHigh = (DWORD)size;
+ r = LIBUSB_SUCCESS;
+ }
+
+ if (r < 0) {
+ free_fd_for_poll(wfd.fd);
+ return LIBUSB_ERROR_IO;
+ }
+
// Use priv_transfer to store data needed for async polling
transfer_priv->pollable_fd = wfd;
transfer_priv->interface_number = (uint8_t)current_interface;
- return r;
+ return LIBUSB_SUCCESS;
}
+static int hid_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 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);
+ HANDLE hid_handle;
+ int current_interface;
+
+ CHECK_HID_AVAILABLE;
+
+ current_interface = transfer_priv->interface_number;
+ hid_handle = handle_priv->interface_handle[current_interface].api_handle;
+ CancelIo(hid_handle);
+
+ return LIBUSB_SUCCESS;
+}
/*
* Composite API functions
diff --git a/libusb/os/windows_usb.h b/libusb/os/windows_usb.h
index 2463ff8..58fc9b2 100644
--- a/libusb/os/windows_usb.h
+++ b/libusb/os/windows_usb.h
@@ -72,13 +72,19 @@ inline void upperize(char* str) {
#define MAX_CTRL_BUFFER_LENGTH 4096
#define MAX_USB_DEVICES 256
#define MAX_USB_STRING_LENGTH 128
-#define MAX_HID_REPORT_SIZE 1024
+#define MAX_HID_REPORT_SIZE 1024
+#define MAX_HID_DESCRIPTOR_SIZE 256
#define MAX_PATH_LENGTH 128
#define MAX_KEY_LENGTH 256
#define ERR_BUFFER_SIZE 256
#define GUID_STRING_LENGTH 40
+// Handle code for HID interface that have been claimed ("dibs")
+#define INTERFACE_CLAIMED ((HANDLE)0xD1B5)
+// Additional return code for HID operations that completed synchronously
+#define LIBUSB_COMPLETED (LIBUSB_SUCCESS + 1)
+
#define wchar_to_utf8_ms(wstr, str, strlen) WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, strlen, NULL, NULL)
// This is used to support multiple kernel drivers and USB APIs in Windows.
@@ -177,7 +183,6 @@ enum libusb_hid_report_type {
HID_REPORT_TYPE_FEATURE = 0x03
};
-
struct hid_device_priv {
uint16_t vid;
uint16_t pid;
@@ -248,8 +253,8 @@ static inline struct windows_device_priv *__device_priv(struct libusb_device *de
}
struct interface_handle_t {
- HANDLE winusb_file; // WinUSB needs an extra handle for the file
- HANDLE handle; // used by the API to communicate with the device
+ HANDLE dev_handle; // WinUSB needs an extra handle for the file
+ HANDLE api_handle; // used by the API to communicate with the device
};
struct windows_device_handle_priv {
@@ -273,7 +278,6 @@ struct windows_transfer_priv {
/*
* Windows DDK API definitions. Most of it copied from MinGW's includes
*/
-
typedef DWORD DEVNODE, DEVINST;
typedef DEVNODE *PDEVNODE, *PDEVINST;
typedef DWORD RETURN_TYPE;
@@ -287,23 +291,23 @@ typedef RETURN_TYPE CONFIGRET;
#define CMAPI DECLSPEC_IMPORT
#endif
-#define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE
-#define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG
-#define USB_STRING_DESCRIPTOR_TYPE LIBUSB_DT_STRING
-#define USB_INTERFACE_DESCRIPTOR_TYPE LIBUSB_DT_INTERFACE
-#define USB_ENDPOINT_DESCRIPTOR_TYPE LIBUSB_DT_ENDPOINT
-
-#define USB_REQUEST_GET_STATUS LIBUSB_REQUEST_GET_STATUS
-#define USB_REQUEST_CLEAR_FEATURE LIBUSB_REQUEST_CLEAR_FEATURE
-#define USB_REQUEST_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE
-#define USB_REQUEST_SET_ADDRESS LIBUSB_REQUEST_SET_ADDRESS
-#define USB_REQUEST_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR
-#define USB_REQUEST_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR
-#define USB_REQUEST_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION
-#define USB_REQUEST_SET_CONFIGURATION LIBUSB_REQUEST_SET_CONFIGURATION
-#define USB_REQUEST_GET_INTERFACE LIBUSB_REQUEST_GET_INTERFACE
-#define USB_REQUEST_SET_INTERFACE LIBUSB_REQUEST_SET_INTERFACE
-#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME
+#define USB_DEVICE_DESCRIPTOR_TYPE LIBUSB_DT_DEVICE
+#define USB_CONFIGURATION_DESCRIPTOR_TYPE LIBUSB_DT_CONFIG
+#define USB_STRING_DESCRIPTOR_TYPE LIBUSB_DT_STRING
+#define USB_INTERFACE_DESCRIPTOR_TYPE LIBUSB_DT_INTERFACE
+#define USB_ENDPOINT_DESCRIPTOR_TYPE LIBUSB_DT_ENDPOINT
+
+#define USB_REQUEST_GET_STATUS LIBUSB_REQUEST_GET_STATUS
+#define USB_REQUEST_CLEAR_FEATURE LIBUSB_REQUEST_CLEAR_FEATURE
+#define USB_REQUEST_SET_FEATURE LIBUSB_REQUEST_SET_FEATURE
+#define USB_REQUEST_SET_ADDRESS LIBUSB_REQUEST_SET_ADDRESS
+#define USB_REQUEST_GET_DESCRIPTOR LIBUSB_REQUEST_GET_DESCRIPTOR
+#define USB_REQUEST_SET_DESCRIPTOR LIBUSB_REQUEST_SET_DESCRIPTOR
+#define USB_REQUEST_GET_CONFIGURATION LIBUSB_REQUEST_GET_CONFIGURATION
+#define USB_REQUEST_SET_CONFIGURATION LIBUSB_REQUEST_SET_CONFIGURATION
+#define USB_REQUEST_GET_INTERFACE LIBUSB_REQUEST_GET_INTERFACE
+#define USB_REQUEST_SET_INTERFACE LIBUSB_REQUEST_SET_INTERFACE
+#define USB_REQUEST_SYNC_FRAME LIBUSB_REQUEST_SYNCH_FRAME
#define HCD_GET_ROOT_HUB_NAME 258
#define USB_GET_NODE_INFORMATION 258
@@ -316,16 +320,16 @@ typedef RETURN_TYPE CONFIGRET;
#endif
#ifndef METHOD_BUFFERED
-#define METHOD_BUFFERED 0
+#define METHOD_BUFFERED 0
#endif
#ifndef FILE_ANY_ACCESS
-#define FILE_ANY_ACCESS 0x00000000
+#define FILE_ANY_ACCESS 0x00000000
#endif
#ifndef FILE_DEVICE_UNKNOWN
-#define FILE_DEVICE_UNKNOWN 0x00000022
+#define FILE_DEVICE_UNKNOWN 0x00000022
#endif
#ifndef FILE_DEVICE_USB
-#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN
+#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN
#endif
#ifndef CTL_CODE