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 <lockwood@android.com>
diff --git a/drivers/usb/gadget/f_adb.c b/drivers/usb/gadget/f_adb.c
index 04dd451..7186cb6 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 @@
 	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 @@
 {
 	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 @@
 	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 @@
 
 	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 @@
 			return ret;
 		}
 	}
-
-	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;
-		}
+	if (dev->error) {
+		r = -EIO;
+		goto done;
 	}
 
-fail:
+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);
+	}
+
+	/* 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 @@
 
 	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 @@
 	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;