Revert "USB: gadget: adb: Queue read requests with length specified by client."
author黄涛 <huangtao@rock-chips.com>
Sat, 30 Jul 2011 14:45:29 +0000 (22:45 +0800)
committer黄涛 <huangtao@rock-chips.com>
Sat, 30 Jul 2011 14:45:29 +0000 (22:45 +0800)
This reverts commit 9bebaa516d632a1ac16aad0955dc8dd7897fdad9.

drivers/usb/gadget/f_adb.c

index f782796ce7d90dd033010b1d49f0ae274c1f953b..14e3fe5c06d27b4dc718411c3555f3a137cbd48b 100644 (file)
@@ -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;