From: Mike Lockwood Date: Sat, 19 Dec 2009 23:22:09 +0000 (-0500) Subject: USB: gadget: adb: Queue read requests with length specified by client. X-Git-Tag: firefly_0821_release~9833^2~5^2~283 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=290c1aaa5832fa7efd0f5016c855e2b925b068b2;p=firefly-linux-kernel-4.4.55.git USB: gadget: adb: Queue read requests with length specified by client. Previously we queued 4K requests rather than the count passed into read(). Signed-off-by: Mike Lockwood --- diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c index bc0444538df2..d1afe0ed1ec8 100644 --- a/drivers/usb/gadget/f_adb.c +++ b/drivers/usb/gadget/f_adb.c @@ -34,8 +34,7 @@ #define BULK_BUFFER_SIZE 4096 -/* number of rx and tx requests to allocate */ -#define RX_REQ_MAX 4 +/* number of tx requests to allocate */ #define TX_REQ_MAX 4 static const char shortname[] = "android_adb"; @@ -56,16 +55,11 @@ struct adb_dev { atomic_t open_excl; struct list_head tx_idle; - struct list_head rx_idle; - struct list_head rx_done; wait_queue_head_t read_wq; wait_queue_head_t write_wq; - - /* the request we're currently reading from */ - struct usb_request *read_req; - unsigned char *read_buf; - unsigned read_count; + struct usb_request *rx_req; + int rx_done; }; static struct usb_interface_descriptor adb_interface_desc = { @@ -217,12 +211,9 @@ static void adb_complete_out(struct usb_ep *ep, struct usb_request *req) { struct adb_dev *dev = _adb_dev; - if (req->status != 0) { + dev->rx_done = 1; + if (req->status != 0) dev->error = 1; - req_put(dev, &dev->rx_idle, req); - } else { - req_put(dev, &dev->rx_done, req); - } wake_up(&dev->read_wq); } @@ -255,13 +246,11 @@ static int __init create_bulk_endpoints(struct adb_dev *dev, dev->ep_out = ep; /* now allocate requests for our endpoints */ - for (i = 0; i < RX_REQ_MAX; i++) { - req = adb_request_new(dev->ep_out, BULK_BUFFER_SIZE); - if (!req) - goto fail; - req->complete = adb_complete_out; - req_put(dev, &dev->rx_idle, req); - } + req = adb_request_new(dev->ep_out, BULK_BUFFER_SIZE); + if (!req) + goto fail; + req->complete = adb_complete_out; + dev->rx_req = req; for (i = 0; i < TX_REQ_MAX; i++) { req = adb_request_new(dev->ep_in, BULK_BUFFER_SIZE); @@ -289,6 +278,9 @@ static ssize_t adb_read(struct file *fp, char __user *buf, DBG(cdev, "adb_read(%d)\n", count); + if (count > BULK_BUFFER_SIZE) + return -EINVAL; + if (_lock(&dev->read_excl)) return -EBUSY; @@ -302,79 +294,46 @@ static ssize_t adb_read(struct file *fp, char __user *buf, return ret; } } + if (dev->error) { + r = -EIO; + goto done; + } - while (count > 0) { - if (dev->error) { - DBG(cdev, "adb_read dev->error\n"); - r = -EIO; - break; - } - - /* if we have idle read requests, get them queued */ - while ((req = req_get(dev, &dev->rx_idle))) { requeue_req: - req->length = BULK_BUFFER_SIZE; - ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC); - - if (ret < 0) { - r = -EIO; - dev->error = 1; - req_put(dev, &dev->rx_idle, req); - goto fail; - } else { - DBG(cdev, "rx %p queue\n", req); - } - } - - /* if we have data pending, give it to userspace */ - if (dev->read_count > 0) { - if (dev->read_count < count) - xfer = dev->read_count; - else - xfer = count; - - if (copy_to_user(buf, dev->read_buf, xfer)) { - r = -EFAULT; - break; - } - dev->read_buf += xfer; - dev->read_count -= xfer; - buf += xfer; - count -= xfer; - - /* if we've emptied the buffer, release the request */ - if (dev->read_count == 0) { - req_put(dev, &dev->rx_idle, dev->read_req); - dev->read_req = 0; - } - continue; - } - - /* wait for a request to complete */ - req = 0; - ret = wait_event_interruptible(dev->read_wq, - ((req = req_get(dev, &dev->rx_done)) || dev->error)); - if (req != 0) { - /* if we got a 0-len one we need to put it back into - ** service. if we made it the current read req we'd - ** be stuck forever - */ - if (req->actual == 0) - goto requeue_req; - - dev->read_req = req; - dev->read_count = req->actual; - dev->read_buf = req->buf; - DBG(cdev, "rx %p %d\n", req, req->actual); - } - - if (ret < 0) { - r = ret; - break; - } + /* queue a request */ + req = dev->rx_req; + req->length = count; + dev->rx_done = 0; + ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC); + if (ret < 0) { + DBG(cdev, "adb_read: failed to queue req %p (%d)\n", req, ret); + r = -EIO; + dev->error = 1; + goto done; + } else { + DBG(cdev, "rx %p queue\n", req); } -fail: + /* wait for a request to complete */ + ret = wait_event_interruptible(dev->read_wq, dev->rx_done); + if (ret < 0) { + dev->error = 1; + r = ret; + goto done; + } + if (!dev->error) { + /* If we got a 0-len packet, throw it back and try again. */ + if (req->actual == 0) + goto requeue_req; + + DBG(cdev, "rx %p %d\n", req, req->actual); + xfer = (req->actual < count) ? req->actual : count; + if (copy_to_user(buf, req->buf, xfer)) + r = -EFAULT; + } else + r = -EIO; + +done: _unlock(&dev->read_excl); DBG(cdev, "adb_read returning %d\n", r); return r; @@ -560,8 +519,7 @@ adb_function_unbind(struct usb_configuration *c, struct usb_function *f) spin_lock_irq(&dev->lock); - while ((req = req_get(dev, &dev->rx_idle))) - adb_request_free(req, dev->ep_out); + adb_request_free(dev->rx_req, dev->ep_out); while ((req = req_get(dev, &dev->tx_idle))) adb_request_free(req, dev->ep_in); @@ -641,8 +599,6 @@ static int adb_bind_config(struct usb_configuration *c) atomic_set(&dev->read_excl, 0); atomic_set(&dev->write_excl, 0); - INIT_LIST_HEAD(&dev->rx_idle); - INIT_LIST_HEAD(&dev->rx_done); INIT_LIST_HEAD(&dev->tx_idle); dev->cdev = c->cdev;