aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/gadget/f_accessory.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/gadget/f_accessory.c')
-rw-r--r--drivers/usb/gadget/f_accessory.c48
1 files changed, 36 insertions, 12 deletions
diff --git a/drivers/usb/gadget/f_accessory.c b/drivers/usb/gadget/f_accessory.c
index 092964c2b506..53e50b5e8612 100644
--- a/drivers/usb/gadget/f_accessory.c
+++ b/drivers/usb/gadget/f_accessory.c
@@ -261,8 +261,10 @@ static void acc_complete_in(struct usb_ep *ep, struct usb_request *req)
{
struct acc_dev *dev = _acc_dev;
- if (req->status != 0)
+ if (req->status == -ESHUTDOWN) {
+ pr_debug("acc_complete_in set disconnected");
acc_set_disconnected(dev);
+ }
req_put(dev, &dev->tx_idle, req);
@@ -274,8 +276,10 @@ static void acc_complete_out(struct usb_ep *ep, struct usb_request *req)
struct acc_dev *dev = _acc_dev;
dev->rx_done = 1;
- if (req->status != 0)
+ if (req->status == -ESHUTDOWN) {
+ pr_debug("acc_complete_out set disconnected");
acc_set_disconnected(dev);
+ }
wake_up(&dev->read_wq);
}
@@ -552,13 +556,16 @@ static ssize_t acc_read(struct file *fp, char __user *buf,
{
struct acc_dev *dev = fp->private_data;
struct usb_request *req;
- int r = count, xfer;
+ ssize_t r = count;
+ unsigned xfer;
int ret = 0;
- pr_debug("acc_read(%d)\n", count);
+ pr_debug("acc_read(%zu)\n", count);
- if (dev->disconnected)
+ if (dev->disconnected) {
+ pr_debug("acc_read disconnected");
return -ENODEV;
+ }
if (count > BULK_BUFFER_SIZE)
count = BULK_BUFFER_SIZE;
@@ -571,6 +578,12 @@ static ssize_t acc_read(struct file *fp, char __user *buf,
goto done;
}
+ if (dev->rx_done) {
+ // last req cancelled. try to get it.
+ req = dev->rx_req[0];
+ goto copy_data;
+ }
+
requeue_req:
/* queue a request */
req = dev->rx_req[0];
@@ -588,15 +601,23 @@ requeue_req:
ret = wait_event_interruptible(dev->read_wq, dev->rx_done);
if (ret < 0) {
r = ret;
- usb_ep_dequeue(dev->ep_out, req);
+ ret = usb_ep_dequeue(dev->ep_out, req);
+ if (ret != 0) {
+ // cancel failed. There can be a data already received.
+ // it will be retrieved in the next read.
+ pr_debug("acc_read: cancelling failed %d", ret);
+ }
goto done;
}
+
+copy_data:
+ dev->rx_done = 0;
if (dev->online) {
/* If we got a 0-len packet, throw it back and try again. */
if (req->actual == 0)
goto requeue_req;
- pr_debug("rx %p %d\n", req, req->actual);
+ pr_debug("rx %p %u\n", req, req->actual);
xfer = (req->actual < count) ? req->actual : count;
r = xfer;
if (copy_to_user(buf, req->buf, xfer))
@@ -605,7 +626,7 @@ requeue_req:
r = -EIO;
done:
- pr_debug("acc_read returning %d\n", r);
+ pr_debug("acc_read returning %zd\n", r);
return r;
}
@@ -614,13 +635,16 @@ static ssize_t acc_write(struct file *fp, const char __user *buf,
{
struct acc_dev *dev = fp->private_data;
struct usb_request *req = 0;
- int r = count, xfer;
+ ssize_t r = count;
+ unsigned xfer;
int ret;
- pr_debug("acc_write(%d)\n", count);
+ pr_debug("acc_write(%zu)\n", count);
- if (!dev->online || dev->disconnected)
+ if (!dev->online || dev->disconnected) {
+ pr_debug("acc_write disconnected or not online");
return -ENODEV;
+ }
while (count > 0) {
if (!dev->online) {
@@ -665,7 +689,7 @@ static ssize_t acc_write(struct file *fp, const char __user *buf,
if (req)
req_put(dev, &dev->tx_idle, req);
- pr_debug("acc_write returning %d\n", r);
+ pr_debug("acc_write returning %zd\n", r);
return r;
}