From: 黄涛 Date: Sat, 30 Jul 2011 14:45:29 +0000 (+0800) Subject: Revert "USB: gadget: adb: Queue read requests with length specified by client." X-Git-Tag: firefly_0821_release~9923 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=98585694964ceddfe7e88709d2d17046f9ce117b;p=firefly-linux-kernel-4.4.55.git Revert "USB: gadget: adb: Queue read requests with length specified by client." This reverts commit 9bebaa516d632a1ac16aad0955dc8dd7897fdad9. --- diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c index f782796ce7d9..14e3fe5c06d2 100644 --- a/drivers/usb/gadget/f_adb.c +++ b/drivers/usb/gadget/f_adb.c @@ -34,7 +34,8 @@ #define BULK_BUFFER_SIZE 4096 -/* number of tx requests to allocate */ +/* number of rx and tx requests to allocate */ +#define RX_REQ_MAX 4 #define TX_REQ_MAX 4 static const char shortname[] = "android_adb"; @@ -55,11 +56,16 @@ 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; - struct usb_request *rx_req; - int rx_done; + + /* the request we're currently reading from */ + struct usb_request *read_req; + unsigned char *read_buf; + unsigned read_count; }; static struct usb_interface_descriptor adb_interface_desc = { @@ -211,9 +217,12 @@ static void adb_complete_out(struct usb_ep *ep, struct usb_request *req) { struct adb_dev *dev = _adb_dev; - dev->rx_done = 1; - if (req->status != 0) + 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); } @@ -246,11 +255,13 @@ static int __init create_bulk_endpoints(struct adb_dev *dev, dev->ep_out = ep; /* now allocate requests for our endpoints */ - 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 < 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); + } for (i = 0; i < TX_REQ_MAX; i++) { req = adb_request_new(dev->ep_in, BULK_BUFFER_SIZE); @@ -278,9 +289,6 @@ 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; @@ -294,46 +302,79 @@ 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: - /* 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); - } + req->length = BULK_BUFFER_SIZE; + ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC); - /* 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 (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; + } } - 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: + +fail: _unlock(&dev->read_excl); DBG(cdev, "adb_read returning %d\n", r); return r; @@ -519,7 +560,8 @@ adb_function_unbind(struct usb_configuration *c, struct usb_function *f) spin_lock_irq(&dev->lock); - adb_request_free(dev->rx_req, dev->ep_out); + while ((req = req_get(dev, &dev->rx_idle))) + adb_request_free(req, dev->ep_out); while ((req = req_get(dev, &dev->tx_idle))) adb_request_free(req, dev->ep_in); @@ -599,6 +641,8 @@ 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;