Skip to content

Commit

Permalink
usb: cdc-wdm: make reset work with blocking IO
Browse files Browse the repository at this point in the history
Add a flag to tell wdm_read/wdm_write that a reset is in progress,
and wake any blocking read/write before taking the mutexes.  This
allows the device to reset without waiting for blocking IO to
finish.

Signed-off-by: Bjørn Mork <bjorn@mork.no>
Acked-by: Oliver Neukum <oneukum@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Bjørn Mork authored and Greg Kroah-Hartman committed Feb 10, 2012
1 parent 7483948 commit 8804420
Showing 1 changed file with 17 additions and 4 deletions.
21 changes: 17 additions & 4 deletions drivers/usb/class/cdc-wdm.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_POLL_RUNNING 6
#define WDM_RESPONDING 7
#define WDM_SUSPENDING 8
#define WDM_RESETTING 9

#define WDM_MAX 16

Expand Down Expand Up @@ -340,6 +341,10 @@ static ssize_t wdm_write
else
if (test_bit(WDM_IN_USE, &desc->flags))
r = -EAGAIN;

if (test_bit(WDM_RESETTING, &desc->flags))
r = -EIO;

if (r < 0) {
kfree(buf);
goto out;
Expand Down Expand Up @@ -419,6 +424,10 @@ static ssize_t wdm_read
rv = -ENODEV;
goto err;
}
if (test_bit(WDM_RESETTING, &desc->flags)) {
rv = -EIO;
goto err;
}
usb_mark_last_busy(interface_to_usbdev(desc->intf));
if (rv < 0) {
rv = -ERESTARTSYS;
Expand Down Expand Up @@ -859,20 +868,23 @@ static int wdm_pre_reset(struct usb_interface *intf)
{
struct wdm_device *desc = usb_get_intfdata(intf);

mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
kill_urbs(desc);

/*
* we notify everybody using poll of
* an exceptional situation
* must be done before recovery lest a spontaneous
* message from the device is lost
*/
spin_lock_irq(&desc->iuspin);
set_bit(WDM_RESETTING, &desc->flags); /* inform read/write */
set_bit(WDM_READ, &desc->flags); /* unblock read */
clear_bit(WDM_IN_USE, &desc->flags); /* unblock write */
desc->rerr = -EINTR;
spin_unlock_irq(&desc->iuspin);
wake_up_all(&desc->wait);
mutex_lock(&desc->rlock);
mutex_lock(&desc->wlock);
kill_urbs(desc);
cancel_work_sync(&desc->rxwork);
return 0;
}

Expand All @@ -881,6 +893,7 @@ static int wdm_post_reset(struct usb_interface *intf)
struct wdm_device *desc = usb_get_intfdata(intf);
int rv;

clear_bit(WDM_RESETTING, &desc->flags);
rv = recover_from_urb_loss(desc);
mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
Expand Down

0 comments on commit 8804420

Please sign in to comment.