|
@@ -1689,7 +1689,7 @@ static struct async *reap_as(struct usb_dev_state *ps)
|
|
|
for (;;) {
|
|
|
__set_current_state(TASK_INTERRUPTIBLE);
|
|
|
as = async_getcompleted(ps);
|
|
|
- if (as)
|
|
|
+ if (as || !connected(ps))
|
|
|
break;
|
|
|
if (signal_pending(current))
|
|
|
break;
|
|
@@ -1712,7 +1712,7 @@ static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
|
|
|
}
|
|
|
if (signal_pending(current))
|
|
|
return -EINTR;
|
|
|
- return -EIO;
|
|
|
+ return -ENODEV;
|
|
|
}
|
|
|
|
|
|
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)
|
|
|
struct async *as;
|
|
|
|
|
|
as = async_getcompleted(ps);
|
|
|
- retval = -EAGAIN;
|
|
|
if (as) {
|
|
|
retval = processcompl(as, (void __user * __user *)arg);
|
|
|
free_async(as);
|
|
|
+ } else {
|
|
|
+ retval = (connected(ps) ? -EAGAIN : -ENODEV);
|
|
|
}
|
|
|
return retval;
|
|
|
}
|
|
@@ -1854,7 +1855,7 @@ static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
|
|
|
}
|
|
|
if (signal_pending(current))
|
|
|
return -EINTR;
|
|
|
- return -EIO;
|
|
|
+ return -ENODEV;
|
|
|
}
|
|
|
|
|
|
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
|
|
|
int retval;
|
|
|
struct async *as;
|
|
|
|
|
|
- retval = -EAGAIN;
|
|
|
as = async_getcompleted(ps);
|
|
|
if (as) {
|
|
|
retval = processcompl_compat(as, (void __user * __user *)arg);
|
|
|
free_async(as);
|
|
|
+ } else {
|
|
|
+ retval = (connected(ps) ? -EAGAIN : -ENODEV);
|
|
|
}
|
|
|
return retval;
|
|
|
}
|
|
@@ -2038,7 +2040,8 @@ static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
|
|
|
{
|
|
|
__u32 caps;
|
|
|
|
|
|
- caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM;
|
|
|
+ caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
|
|
|
+ USBDEVFS_CAP_REAP_AFTER_DISCONNECT;
|
|
|
if (!ps->dev->bus->no_stop_on_short)
|
|
|
caps |= USBDEVFS_CAP_BULK_CONTINUATION;
|
|
|
if (ps->dev->bus->sg_tablesize)
|
|
@@ -2138,6 +2141,32 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
|
|
|
return -EPERM;
|
|
|
|
|
|
usb_lock_device(dev);
|
|
|
+
|
|
|
+ /* Reap operations are allowed even after disconnection */
|
|
|
+ switch (cmd) {
|
|
|
+ case USBDEVFS_REAPURB:
|
|
|
+ snoop(&dev->dev, "%s: REAPURB\n", __func__);
|
|
|
+ ret = proc_reapurb(ps, p);
|
|
|
+ goto done;
|
|
|
+
|
|
|
+ case USBDEVFS_REAPURBNDELAY:
|
|
|
+ snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
|
|
|
+ ret = proc_reapurbnonblock(ps, p);
|
|
|
+ goto done;
|
|
|
+
|
|
|
+#ifdef CONFIG_COMPAT
|
|
|
+ case USBDEVFS_REAPURB32:
|
|
|
+ snoop(&dev->dev, "%s: REAPURB32\n", __func__);
|
|
|
+ ret = proc_reapurb_compat(ps, p);
|
|
|
+ goto done;
|
|
|
+
|
|
|
+ case USBDEVFS_REAPURBNDELAY32:
|
|
|
+ snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
|
|
|
+ ret = proc_reapurbnonblock_compat(ps, p);
|
|
|
+ goto done;
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
if (!connected(ps)) {
|
|
|
usb_unlock_device(dev);
|
|
|
return -ENODEV;
|
|
@@ -2231,16 +2260,6 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
|
|
|
inode->i_mtime = CURRENT_TIME;
|
|
|
break;
|
|
|
|
|
|
- case USBDEVFS_REAPURB32:
|
|
|
- snoop(&dev->dev, "%s: REAPURB32\n", __func__);
|
|
|
- ret = proc_reapurb_compat(ps, p);
|
|
|
- break;
|
|
|
-
|
|
|
- case USBDEVFS_REAPURBNDELAY32:
|
|
|
- snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
|
|
|
- ret = proc_reapurbnonblock_compat(ps, p);
|
|
|
- break;
|
|
|
-
|
|
|
case USBDEVFS_IOCTL32:
|
|
|
snoop(&dev->dev, "%s: IOCTL32\n", __func__);
|
|
|
ret = proc_ioctl_compat(ps, ptr_to_compat(p));
|
|
@@ -2252,16 +2271,6 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
|
|
|
ret = proc_unlinkurb(ps, p);
|
|
|
break;
|
|
|
|
|
|
- case USBDEVFS_REAPURB:
|
|
|
- snoop(&dev->dev, "%s: REAPURB\n", __func__);
|
|
|
- ret = proc_reapurb(ps, p);
|
|
|
- break;
|
|
|
-
|
|
|
- case USBDEVFS_REAPURBNDELAY:
|
|
|
- snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
|
|
|
- ret = proc_reapurbnonblock(ps, p);
|
|
|
- break;
|
|
|
-
|
|
|
case USBDEVFS_DISCSIGNAL:
|
|
|
snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
|
|
|
ret = proc_disconnectsignal(ps, p);
|
|
@@ -2304,6 +2313,8 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
|
|
|
ret = proc_free_streams(ps, p);
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
+ done:
|
|
|
usb_unlock_device(dev);
|
|
|
if (ret >= 0)
|
|
|
inode->i_atime = CURRENT_TIME;
|