Windows: Allow claiming any interface in composite device using WinUSB
authorPete Batard <pbatard@gmail.com>
Tue, 5 Oct 2010 11:50:13 +0000 (12:50 +0100)
committerPeter Stuge <peter@stuge.se>
Mon, 13 Jun 2011 20:01:43 +0000 (22:01 +0200)
Issue reported by Benjamin Dobell, see #48. The call to
WinUsb_QueryInterfaceSettings() is removed since it doesn't work
on any other interface but the first (a WinUSB limitation).

This allows the use of WinUSB.sys in lieu of the usbccgp.sys
"USB Generic Parent" default driver for composite devices.

libusb/os/windows_usb.c

index b999746..9498e14 100644 (file)
@@ -2504,21 +2504,42 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int i
        struct libusb_context *ctx = DEVICE_CTX(dev_handle->dev);
        struct windows_device_handle_priv *handle_priv = __device_handle_priv(dev_handle);
        struct windows_device_priv *priv = __device_priv(dev_handle->dev);
-       bool is_composite = (priv->apib->id == USB_API_COMPOSITE);
+       bool is_using_usbccgp = (priv->apib->id == USB_API_COMPOSITE);
        HANDLE file_handle, winusb_handle;
-       USB_INTERFACE_DESCRIPTOR if_desc;
        UCHAR policy;
        uint8_t endpoint_address;
        int i;
 
        CHECK_WINUSB_AVAILABLE;
 
-       // interfaces for composite devices are always independent, therefore
-       // "alt" interfaces are only found on non-composite
-       if ((!is_composite) && (iface != 0)) {
+       // If the device is composite, but using the default Windows composite parent driver (usbccgp)
+       // or if it's the first WinUSB interface, we get a handle through WinUsb_Initialize().
+       if ((is_using_usbccgp) || (iface == 0)) {
+               // composite device (independent interfaces) or interface 0
+               winusb_handle = handle_priv->interface_handle[iface].api_handle;
+               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].api_handle = INVALID_HANDLE_VALUE;
+
+                       switch(GetLastError()) {
+                       case ERROR_BAD_COMMAND: // The device was disconnected
+                               return LIBUSB_ERROR_NO_DEVICE;
+                       default:
+                               usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0));
+                               return LIBUSB_ERROR_ACCESS;
+                       }
+               }
+               handle_priv->interface_handle[iface].api_handle = winusb_handle;
+       } else {
+               // For all other interfaces, use WinUsb_GetAssociatedInterface()
                winusb_handle = handle_priv->interface_handle[0].api_handle;
-               // It is a requirement on Windows that to claim an interface >= 1
-               // on a non-composite WinUSB device, you must first have claimed interface 0
+               // It is a requirement for multiple interface devices using WinUSB that you
+               // must first claim the first interface before you claim any other
                if ((winusb_handle == 0) || (winusb_handle == INVALID_HANDLE_VALUE)) {
 #if defined(AUTO_CLAIM)
                        file_handle = handle_priv->interface_handle[0].dev_handle;
@@ -2549,35 +2570,7 @@ static int winusb_claim_interface(struct libusb_device_handle *dev_handle, int i
                                return LIBUSB_ERROR_ACCESS;
                        }
                }
-       } else {
-               // composite device (independent interfaces) or interface 0
-               winusb_handle = handle_priv->interface_handle[iface].api_handle;
-               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].api_handle = INVALID_HANDLE_VALUE;
-
-                       switch(GetLastError()) {
-                       case ERROR_BAD_COMMAND: // The device was disconnected
-                               return LIBUSB_ERROR_NO_DEVICE;
-                       default:
-                               usbi_err(ctx, "could not claim interface %d: %s", iface, windows_error_str(0));
-                               return LIBUSB_ERROR_ACCESS;
-                       }
-               }
-               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));
-       } else if (if_desc.bInterfaceNumber != iface) {
-               usbi_warn(ctx, "program assertion failed - WinUSB interface %d found at position %d",
-                       if_desc.bInterfaceNumber, iface);
-       }
-
        usbi_dbg("claimed interface %d", iface);
        handle_priv->active_interface = iface;