]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
usbdevfs: Add a USBDEVFS_GET_CAPABILITIES ioctl
authorHans de Goede <hdegoede@redhat.com>
Wed, 4 Jul 2012 07:18:02 +0000 (09:18 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 6 Jul 2012 17:53:19 +0000 (10:53 -0700)
There are a few (new) usbdevfs capabilities which an application cannot
discover in any other way then checking the kernel version. There are 3
problems with this:
1) It is just not very pretty.
2) Given the tendency of enterprise distros to backport stuff it is not
reliable.
3) As discussed in length on the mailinglist, USBDEVFS_URB_BULK_CONTINUATION
does not work as it should when combined with USBDEVFS_URB_SHORT_NOT_OK
(which is its intended use) on devices attached to an XHCI controller.
So the availability of these features can be host controller dependent,
making depending on them based on the kernel version not a good idea.

This patch besides adding the new ioctl also adds flags for the following
existing capabilities:

USBDEVFS_CAP_ZERO_PACKET,        available since 2.6.31
USBDEVFS_CAP_BULK_CONTINUATION,  available since 2.6.32, except for XHCI
USBDEVFS_CAP_NO_PACKET_SIZE_LIM, available since 3.3

Note that this patch only does not advertise the USBDEVFS_URB_BULK_CONTINUATION
cap for XHCI controllers, bulk transfers with this flag set will still be
accepted when submitted to XHCI controllers.

Returning -EINVAL for them would break existing apps, and in most cases the
troublesome scenario wrt USBDEVFS_URB_SHORT_NOT_OK urbs on XHCI controllers
will never get hit, so this would break working use cases.

The disadvantage of not returning -EINVAL is that cases were it is causing
real trouble may go undetected / the cause of the trouble may be unclear,
but this is the best we can do.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Acked-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/core/devio.c
drivers/usb/host/xhci.c
include/linux/usb.h
include/linux/usbdevice_fs.h

index 62679bc031fb02a1378fe10b5809365511edc7e9..0b387c1a8b7e614e890aa805fc755b8b70b9025f 100644 (file)
@@ -1824,6 +1824,20 @@ static int proc_release_port(struct dev_state *ps, void __user *arg)
        return usb_hub_release_port(ps->dev, portnum, ps);
 }
 
+static int proc_get_capabilities(struct dev_state *ps, void __user *arg)
+{
+       __u32 caps;
+
+       caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM;
+       if (!ps->dev->bus->no_stop_on_short)
+               caps |= USBDEVFS_CAP_BULK_CONTINUATION;
+
+       if (put_user(caps, (__u32 __user *)arg))
+               return -EFAULT;
+
+       return 0;
+}
+
 /*
  * NOTE:  All requests here that have interface numbers as parameters
  * are assuming that somehow the configuration has been prevented from
@@ -1994,6 +2008,9 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
                snoop(&dev->dev, "%s: RELEASE_PORT\n", __func__);
                ret = proc_release_port(ps, p);
                break;
+       case USBDEVFS_GET_CAPABILITIES:
+               ret = proc_get_capabilities(ps, p);
+               break;
        }
        usb_unlock_device(dev);
        if (ret >= 0)
index a979cd0dbe0f8f61970c694b2821643fd8f5a09b..7648b2d4b268182b4e9097db1bab61b97b86a0d4 100644 (file)
@@ -4450,6 +4450,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
 
        /* Accept arbitrarily long scatter-gather lists */
        hcd->self.sg_tablesize = ~0;
+       /* XHCI controllers don't stop the ep queue on short packets :| */
+       hcd->self.no_stop_on_short = 1;
 
        if (usb_hcd_is_primary_hcd(hcd)) {
                xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
index f717fbdaee8e1726ef6e1ce08ce9175b4765b205..d4f9de1acd45cfd933895361a09de941d8b1a3a2 100644 (file)
@@ -331,6 +331,11 @@ struct usb_bus {
        u8 otg_port;                    /* 0, or number of OTG/HNP port */
        unsigned is_b_host:1;           /* true during some HNP roleswitches */
        unsigned b_hnp_enable:1;        /* OTG: did A-Host enable HNP? */
+       unsigned no_stop_on_short:1;    /*
+                                        * Quirk: some controllers don't stop
+                                        * the ep queue on a short transfer
+                                        * with the URB_SHORT_NOT_OK flag set.
+                                        */
        unsigned sg_tablesize;          /* 0 or largest number of sg list entries */
 
        int devnum_next;                /* Next open device number in
index 15591d2ea4004a86599e940ec4583bb12a1be341..07b2ceaaad709f2165ee5f6ad568a049fe7f68a5 100644 (file)
@@ -125,6 +125,11 @@ struct usbdevfs_hub_portinfo {
        char port [127];        /* e.g. port 3 connects to device 27 */
 };
 
+/* Device capability flags */
+#define USBDEVFS_CAP_ZERO_PACKET               0x01
+#define USBDEVFS_CAP_BULK_CONTINUATION         0x02
+#define USBDEVFS_CAP_NO_PACKET_SIZE_LIM                0x04
+
 #ifdef __KERNEL__
 #ifdef CONFIG_COMPAT
 #include <linux/compat.h>
@@ -204,4 +209,6 @@ struct usbdevfs_ioctl32 {
 #define USBDEVFS_CONNECT           _IO('U', 23)
 #define USBDEVFS_CLAIM_PORT        _IOR('U', 24, unsigned int)
 #define USBDEVFS_RELEASE_PORT      _IOR('U', 25, unsigned int)
+#define USBDEVFS_GET_CAPABILITIES  _IOR('U', 26, __u32)
+
 #endif /* _LINUX_USBDEVICE_FS_H */