diff options
author | Oliver Neukum <oliver@neukum.org> | 2009-09-09 10:12:48 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2009-09-23 06:46:16 -0700 |
commit | 7f1dc313d01f5f0f84c06051343a3b8623932d3c (patch) | |
tree | 762ae2c12f103f039a8215161172b0b52101c1c9 | |
parent | ce60c48871d2b3a15ab3fa2450e783bebb4ae407 (diff) | |
download | linux-7f1dc313d01f5f0f84c06051343a3b8623932d3c.tar.bz2 |
USB: CDC WDM driver doesn't support non-blocking reads
support for O_NONBLOCK in read and write path
by simply not waiting for data in read or availability
of the write urb in write but returning -EAGAIN
Signed-off-by: Oliver Neukum <oliver@neukum.org>
Tested-by: Marcel Holtmann <marcel@holtmann.org>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | drivers/usb/class/cdc-wdm.c | 30 |
1 files changed, 24 insertions, 6 deletions
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c index 8c64c018b676..3e564bfe17d1 100644 --- a/drivers/usb/class/cdc-wdm.c +++ b/drivers/usb/class/cdc-wdm.c @@ -313,8 +313,13 @@ static ssize_t wdm_write r = usb_autopm_get_interface(desc->intf); if (r < 0) goto outnp; - r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE, - &desc->flags)); + + if (!file->f_flags && O_NONBLOCK) + r = wait_event_interruptible(desc->wait, !test_bit(WDM_IN_USE, + &desc->flags)); + else + if (test_bit(WDM_IN_USE, &desc->flags)) + r = -EAGAIN; if (r < 0) goto out; @@ -377,7 +382,7 @@ outnl: static ssize_t wdm_read (struct file *file, char __user *buffer, size_t count, loff_t *ppos) { - int rv, cntr; + int rv, cntr = 0; int i = 0; struct wdm_device *desc = file->private_data; @@ -389,10 +394,23 @@ static ssize_t wdm_read if (desc->length == 0) { desc->read = 0; retry: + if (test_bit(WDM_DISCONNECTING, &desc->flags)) { + rv = -ENODEV; + goto err; + } i++; - rv = wait_event_interruptible(desc->wait, - test_bit(WDM_READ, &desc->flags)); + if (file->f_flags & O_NONBLOCK) { + if (!test_bit(WDM_READ, &desc->flags)) { + rv = cntr ? cntr : -EAGAIN; + goto err; + } + rv = 0; + } else { + rv = wait_event_interruptible(desc->wait, + test_bit(WDM_READ, &desc->flags)); + } + /* may have happened while we slept */ if (test_bit(WDM_DISCONNECTING, &desc->flags)) { rv = -ENODEV; goto err; @@ -448,7 +466,7 @@ retry: err: mutex_unlock(&desc->rlock); - if (rv < 0) + if (rv < 0 && rv != -EAGAIN) dev_err(&desc->intf->dev, "wdm_read: exit error\n"); return rv; } |