diff options
Diffstat (limited to 'drivers/usb/core/devio.c')
-rw-r--r-- | drivers/usb/core/devio.c | 63 |
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 | ||
1718 | static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg) | 1718 | static 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 | ||
1860 | static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg) | 1861 | static 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; |