aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/core/devio.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/devio.c')
-rw-r--r--drivers/usb/core/devio.c63
1 files changed, 37 insertions, 26 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 0b59731c3021..66abdbcfbfa5 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1689,7 +1689,7 @@ static struct async *reap_as(struct usb_dev_state *ps)
1689 for (;;) { 1689 for (;;) {
1690 __set_current_state(TASK_INTERRUPTIBLE); 1690 __set_current_state(TASK_INTERRUPTIBLE);
1691 as = async_getcompleted(ps); 1691 as = async_getcompleted(ps);
1692 if (as) 1692 if (as || !connected(ps))
1693 break; 1693 break;
1694 if (signal_pending(current)) 1694 if (signal_pending(current))
1695 break; 1695 break;
@@ -1712,7 +1712,7 @@ static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
1712 } 1712 }
1713 if (signal_pending(current)) 1713 if (signal_pending(current))
1714 return -EINTR; 1714 return -EINTR;
1715 return -EIO; 1715 return -ENODEV;
1716} 1716}
1717 1717
1718static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg) 1718static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
@@ -1721,10 +1721,11 @@ static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
1721 struct async *as; 1721 struct async *as;
1722 1722
1723 as = async_getcompleted(ps); 1723 as = async_getcompleted(ps);
1724 retval = -EAGAIN;
1725 if (as) { 1724 if (as) {
1726 retval = processcompl(as, (void __user * __user *)arg); 1725 retval = processcompl(as, (void __user * __user *)arg);
1727 free_async(as); 1726 free_async(as);
1727 } else {
1728 retval = (connected(ps) ? -EAGAIN : -ENODEV);
1728 } 1729 }
1729 return retval; 1730 return retval;
1730} 1731}
@@ -1854,7 +1855,7 @@ static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
1854 } 1855 }
1855 if (signal_pending(current)) 1856 if (signal_pending(current))
1856 return -EINTR; 1857 return -EINTR;
1857 return -EIO; 1858 return -ENODEV;
1858} 1859}
1859 1860
1860static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg) 1861static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)
@@ -1862,11 +1863,12 @@ static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *ar
1862 int retval; 1863 int retval;
1863 struct async *as; 1864 struct async *as;
1864 1865
1865 retval = -EAGAIN;
1866 as = async_getcompleted(ps); 1866 as = async_getcompleted(ps);
1867 if (as) { 1867 if (as) {
1868 retval = processcompl_compat(as, (void __user * __user *)arg); 1868 retval = processcompl_compat(as, (void __user * __user *)arg);
1869 free_async(as); 1869 free_async(as);
1870 } else {
1871 retval = (connected(ps) ? -EAGAIN : -ENODEV);
1870 } 1872 }
1871 return retval; 1873 return retval;
1872} 1874}
@@ -2038,7 +2040,8 @@ static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
2038{ 2040{
2039 __u32 caps; 2041 __u32 caps;
2040 2042
2041 caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM; 2043 caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
2044 USBDEVFS_CAP_REAP_AFTER_DISCONNECT;
2042 if (!ps->dev->bus->no_stop_on_short) 2045 if (!ps->dev->bus->no_stop_on_short)
2043 caps |= USBDEVFS_CAP_BULK_CONTINUATION; 2046 caps |= USBDEVFS_CAP_BULK_CONTINUATION;
2044 if (ps->dev->bus->sg_tablesize) 2047 if (ps->dev->bus->sg_tablesize)
@@ -2138,6 +2141,32 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
2138 return -EPERM; 2141 return -EPERM;
2139 2142
2140 usb_lock_device(dev); 2143 usb_lock_device(dev);
2144
2145 /* Reap operations are allowed even after disconnection */
2146 switch (cmd) {
2147 case USBDEVFS_REAPURB:
2148 snoop(&dev->dev, "%s: REAPURB\n", __func__);
2149 ret = proc_reapurb(ps, p);
2150 goto done;
2151
2152 case USBDEVFS_REAPURBNDELAY:
2153 snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
2154 ret = proc_reapurbnonblock(ps, p);
2155 goto done;
2156
2157#ifdef CONFIG_COMPAT
2158 case USBDEVFS_REAPURB32:
2159 snoop(&dev->dev, "%s: REAPURB32\n", __func__);
2160 ret = proc_reapurb_compat(ps, p);
2161 goto done;
2162
2163 case USBDEVFS_REAPURBNDELAY32:
2164 snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
2165 ret = proc_reapurbnonblock_compat(ps, p);
2166 goto done;
2167#endif
2168 }
2169
2141 if (!connected(ps)) { 2170 if (!connected(ps)) {
2142 usb_unlock_device(dev); 2171 usb_unlock_device(dev);
2143 return -ENODEV; 2172 return -ENODEV;
@@ -2231,16 +2260,6 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
2231 inode->i_mtime = CURRENT_TIME; 2260 inode->i_mtime = CURRENT_TIME;
2232 break; 2261 break;
2233 2262
2234 case USBDEVFS_REAPURB32:
2235 snoop(&dev->dev, "%s: REAPURB32\n", __func__);
2236 ret = proc_reapurb_compat(ps, p);
2237 break;
2238
2239 case USBDEVFS_REAPURBNDELAY32:
2240 snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
2241 ret = proc_reapurbnonblock_compat(ps, p);
2242 break;
2243
2244 case USBDEVFS_IOCTL32: 2263 case USBDEVFS_IOCTL32:
2245 snoop(&dev->dev, "%s: IOCTL32\n", __func__); 2264 snoop(&dev->dev, "%s: IOCTL32\n", __func__);
2246 ret = proc_ioctl_compat(ps, ptr_to_compat(p)); 2265 ret = proc_ioctl_compat(ps, ptr_to_compat(p));
@@ -2252,16 +2271,6 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
2252 ret = proc_unlinkurb(ps, p); 2271 ret = proc_unlinkurb(ps, p);
2253 break; 2272 break;
2254 2273
2255 case USBDEVFS_REAPURB:
2256 snoop(&dev->dev, "%s: REAPURB\n", __func__);
2257 ret = proc_reapurb(ps, p);
2258 break;
2259
2260 case USBDEVFS_REAPURBNDELAY:
2261 snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
2262 ret = proc_reapurbnonblock(ps, p);
2263 break;
2264
2265 case USBDEVFS_DISCSIGNAL: 2274 case USBDEVFS_DISCSIGNAL:
2266 snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__); 2275 snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
2267 ret = proc_disconnectsignal(ps, p); 2276 ret = proc_disconnectsignal(ps, p);
@@ -2304,6 +2313,8 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
2304 ret = proc_free_streams(ps, p); 2313 ret = proc_free_streams(ps, p);
2305 break; 2314 break;
2306 } 2315 }
2316
2317 done:
2307 usb_unlock_device(dev); 2318 usb_unlock_device(dev);
2308 if (ret >= 0) 2319 if (ret >= 0)
2309 inode->i_atime = CURRENT_TIME; 2320 inode->i_atime = CURRENT_TIME;