summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/devio.c17
-rw-r--r--drivers/usb/host/xhci.c2
-rw-r--r--include/linux/usb.h5
-rw-r--r--include/linux/usbdevice_fs.h7
4 files changed, 31 insertions, 0 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 62679bc..0b387c1 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -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)
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index a979cd0..7648b2d 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -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);
diff --git a/include/linux/usb.h b/include/linux/usb.h
index f717fbd..d4f9de1 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -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
diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
index 15591d2..07b2cea 100644
--- a/include/linux/usbdevice_fs.h
+++ b/include/linux/usbdevice_fs.h
@@ -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 */
OpenPOWER on IntegriCloud