Forráskód Böngészése

修复adb在windows上使用时卡住的问题

huangliang 1 éve
szülő
commit
c6140aac01
1 módosított fájl, 183 hozzáadás és 13 törlés
  1. 183 13
      linux/drivers/usb/gadget/function/f_adb.c

+ 183 - 13
linux/drivers/usb/gadget/function/f_adb.c

@@ -32,10 +32,10 @@
 #include <linux/usb/functionfs.h>
 #include "u_f.h"
 
-#define ADB_BULK_BUFFER_SIZE           4096
+#define ADB_BULK_BUFFER_SIZE           16384
 
 /* number of tx requests to allocate */
-#define TX_REQ_MAX 2
+#define TX_REQ_MAX 4
 #define DRIVER_NAME "adb"
 
 static const char adb_shortname[] = "android_adb";
@@ -56,10 +56,14 @@ struct adb_dev {
 	atomic_t open_excl;
 
 	struct list_head tx_idle;
+	struct list_head rx_idle;
+	struct list_head rx_used;
+
 	wait_queue_head_t read_wq;
 	wait_queue_head_t write_wq;
 	struct usb_request *rx_req;
 	int rx_done;
+	int cur_read_pos;
 };
 
 static struct usb_interface_descriptor adb_interface_desc = {
@@ -227,8 +231,23 @@ static void adb_complete_out(struct usb_ep *ep, struct usb_request *req)
 	struct adb_dev *dev = _adb_dev;
 
 	dev->rx_done = 1;
+	#if 0
 	if (req->status != 0 && req->status != -ECONNRESET)
 		dev->error = 1;
+	#else
+	if (req) {
+		if (req->status != 0){//printk("+++%s:%d+++req->status=%d\n", __func__, __LINE__, req->status);
+			adb_req_put(dev, &dev->rx_idle, req);
+			dev->error = 1;
+		} else {
+			if (req->actual > 0)
+				adb_req_put(dev, &dev->rx_used, req);
+			else {//printk("+++%s:%d+++ zero len \n", __func__, __LINE__);
+				adb_req_put(dev, &dev->rx_idle, req);
+			}
+		}
+	}
+	#endif
 
 	wake_up(&dev->read_wq);
 }
@@ -261,13 +280,22 @@ static int adb_create_bulk_endpoints(struct adb_dev *dev,
 	DBG(cdev, "usb_ep_autoconfig for adb ep_out got %s\n", ep->name);
 	ep->driver_data = dev;		/* claim the endpoint */
 	dev->ep_out = ep;
-
+#if 0
 	/* now allocate requests for our endpoints */
 	req = adb_request_new(dev->ep_out, ADB_BULK_BUFFER_SIZE);
 	if (!req)
 		goto fail;
 	req->complete = adb_complete_out;
 	dev->rx_req = req;
+#else
+	for (i = 0; i < TX_REQ_MAX; i++) {
+		req = adb_request_new(dev->ep_out, ADB_BULK_BUFFER_SIZE);
+		if (!req)
+			goto fail;
+		req->complete = adb_complete_out;
+		adb_req_put(dev, &dev->rx_idle, req);
+	}
+#endif
 
 	for (i = 0; i < TX_REQ_MAX; i++) {
 		req = adb_request_new(dev->ep_in, ADB_BULK_BUFFER_SIZE);
@@ -284,6 +312,109 @@ fail:
 	return -1;
 }
 
+static int adb_rx_submit(struct adb_dev *dev, struct usb_request *req)
+{
+	int ret, r;
+
+	dev->rx_done = 0;
+	ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC);
+	if (ret < 0) {
+		pr_debug("adb_read: failed to queue req %p (%d)\n", req, ret);
+		r = -EIO;
+		dev->error = 1;
+		goto done;
+	} else {
+		pr_debug("rx %p queue\n", req);
+	}
+done:
+	pr_debug("adb_read returning %d\n", r);
+	return r;
+}
+
+#if 1
+static ssize_t adb_read(struct file *fp, char __user *buf,
+				size_t count, loff_t *pos)
+{
+	struct adb_dev *dev = fp->private_data;
+	struct usb_request *req = NULL;
+	int r = 0, xfer, cur_actual = 0;
+	int ret;
+	//static int cur_pos = 0;
+	unsigned long flags;
+
+	pr_debug("adb_read(%d) \n", count);
+	if (!dev)
+		return -ENODEV;
+
+	if (count <= 0)
+		return 0;
+
+	if (adb_lock(&dev->read_excl))
+		return -EBUSY;
+
+	while (!(dev->online || dev->error)) {
+		pr_debug("adb_read: waiting for online state\n");
+		ret = wait_event_interruptible(dev->read_wq,
+				(dev->online || dev->error));
+		if (ret < 0) {
+			adb_unlock(&dev->read_excl);
+			return ret;
+		}
+	}
+	if (dev->error) {
+		r = -EIO;
+		goto done;
+	}
+
+	req = NULL;
+	ret = wait_event_interruptible(dev->read_wq, (req = adb_req_get(dev, &dev->rx_used)) != NULL);
+	if (ret < 0) {
+		r = ret;
+		if (req)
+			usb_ep_dequeue(dev->ep_out, req);
+		goto done;
+	}
+
+	if (!dev->error && req) {
+		if (req->actual > dev->cur_read_pos) {
+			cur_actual = req->actual - dev->cur_read_pos;
+			xfer = (cur_actual <= count) ? cur_actual : count;
+			r = xfer;
+			if (copy_to_user(buf, (req->buf + dev->cur_read_pos), xfer))
+				r = -EFAULT;
+
+		}
+		if (count >= cur_actual) {
+			adb_rx_submit(dev, req);//the req is read completely, return to the usb core
+			dev->cur_read_pos = 0;
+			while ((req = adb_req_get(dev, &dev->rx_idle))) {
+				req->length = ADB_BULK_BUFFER_SIZE;
+				adb_rx_submit(dev, req);
+			}
+		} else {
+			dev->cur_read_pos += count;
+			spin_lock_irqsave(&dev->lock, flags);//the request buffer isn't completely read ,return the req to the head of the list of rx_used
+			list_add(&req->list, &dev->rx_used);
+			spin_unlock_irqrestore(&dev->lock, flags);
+		}
+	} else {// IO error
+		if (dev->error)
+			r = -EIO;
+		if (dev->online == 0)
+			r = -ENODEV;
+		if (req) {
+			spin_lock_irqsave(&dev->lock, flags);
+			list_add(&req->list, &dev->rx_used);
+			spin_unlock_irqrestore(&dev->lock, flags);
+		}
+	}
+
+done:
+	adb_unlock(&dev->read_excl);
+	pr_debug("adb_read returning %d\n", r);
+	return r;
+}
+#else
 static ssize_t adb_read(struct file *fp, char __user *buf,
 				size_t count, loff_t *pos)
 {
@@ -292,7 +423,7 @@ static ssize_t adb_read(struct file *fp, char __user *buf,
 	int r = count, xfer;
 	int ret;
 
-	pr_debug("adb_read(%d)\n", count);
+	printk("adb_read(%d)\n", count);
 	if (!_adb_dev)
 		return -ENODEV;
 
@@ -304,7 +435,7 @@ static ssize_t adb_read(struct file *fp, char __user *buf,
 
 	/* we will block until we're online */
 	while (!(dev->online || dev->error)) {
-		pr_debug("adb_read: waiting for online state\n");
+		printk("adb_read: waiting for online state\n");
 		ret = wait_event_interruptible(dev->read_wq,
 				(dev->online || dev->error));
 		if (ret < 0) {
@@ -324,12 +455,12 @@ requeue_req:
 	dev->rx_done = 0;
 	ret = usb_ep_queue(dev->ep_out, req, GFP_ATOMIC);
 	if (ret < 0) {
-		pr_debug("adb_read: failed to queue req %p (%d)\n", req, ret);
+		printk("adb_read: failed to queue req %p (%d)\n", req, ret);
 		r = -EIO;
 		dev->error = 1;
 		goto done;
 	} else {
-		pr_debug("rx %p queue\n", req);
+		printk("rx %p queue\n", req);
 	}
 
 	/* wait for a request to complete */
@@ -346,7 +477,7 @@ requeue_req:
 		if (req->actual == 0)
 			goto requeue_req;
 
-		pr_debug("rx %p %d\n", req, req->actual);
+		printk("rx %p %d\n", req, req->actual);
 		xfer = (req->actual < count) ? req->actual : count;
 		if (copy_to_user(buf, req->buf, xfer))
 			r = -EFAULT;
@@ -356,9 +487,10 @@ requeue_req:
 
 done:
 	adb_unlock(&dev->read_excl);
-	pr_debug("adb_read returning %d\n", r);
+	printk("adb_read returning %d\n", r);
 	return r;
 }
+#endif
 
 static ssize_t adb_write(struct file *fp, const char __user *buf,
 				 size_t count, loff_t *pos)
@@ -522,8 +654,17 @@ adb_function_unbind(struct usb_configuration *c, struct usb_function *f)
 	dev->error = 1;
 
 	wake_up(&dev->read_wq);
-
+#if 0
 	adb_request_free(dev->rx_req, dev->ep_out);
+#else
+	while ((req = adb_req_get(dev, &dev->rx_idle)))
+		adb_request_free(req, dev->ep_out);
+	req = NULL;
+	while ((req = adb_req_get(dev, &dev->rx_used)))
+		adb_request_free(req, dev->ep_out);
+#endif
+	req = NULL;
+
 	while ((req = adb_req_get(dev, &dev->tx_idle)))
 		adb_request_free(req, dev->ep_in);
 }
@@ -534,8 +675,9 @@ static int adb_function_set_alt(struct usb_function *f,
 	struct adb_dev	*dev = func_to_adb(f);
 	struct usb_composite_dev *cdev = f->config->cdev;
 	int ret;
+	struct usb_request *req = NULL;
 
-	DBG(cdev, "adb_function_set_alt intf: %d alt: %d\n", intf, alt);
+	DBG(cdev, "adb_function_set_alt intf: %d alt: %d\n", intf, alt);printk("adb_function_set_alt intf: %d alt: %d\n", intf, alt);
 
 	ret = config_ep_by_speed(cdev->gadget, f, dev->ep_in);
 	if (ret)
@@ -556,18 +698,43 @@ static int adb_function_set_alt(struct usb_function *f,
 	}
 	dev->online = 1;
 
+	while ((req = adb_req_get(dev, &dev->rx_used))) {
+		adb_req_put(dev, &dev->rx_idle, req);
+	}
+	while ((req = adb_req_get(dev, &dev->rx_idle))) {
+		req->length = ADB_BULK_BUFFER_SIZE;
+		adb_rx_submit(dev, req);
+	}
+
 	/* readers may be blocked waiting for us to go online */
 	wake_up(&dev->read_wq);
 
 	return 0;
 }
 
+static void adb_function_suspend(struct usb_function *f)
+{
+	struct adb_dev	*dev = func_to_adb(f);
+	struct usb_composite_dev	*cdev = dev->cdev;
+
+	printk("adb_function_suspend cdev %p\n", cdev);
+	dev->online = 0;
+	dev->error = 1;
+	usb_ep_disable(dev->ep_in);
+	usb_ep_disable(dev->ep_out);
+
+	/* readers may be blocked waiting for us to go online */
+	wake_up(&dev->read_wq);
+
+	printk("%s suspend\n", dev->function.name);
+}
+
 static void adb_function_disable(struct usb_function *f)
 {
 	struct adb_dev	*dev = func_to_adb(f);
 	struct usb_composite_dev	*cdev = dev->cdev;
 
-	DBG(cdev, "adb_function_disable cdev %p\n", cdev);
+	DBG(cdev, "adb_function_disable cdev %p\n", cdev);printk("adb_function_disable cdev %p\n", cdev);
 	dev->online = 0;
 	dev->error = 1;
 	usb_ep_disable(dev->ep_in);
@@ -576,7 +743,7 @@ static void adb_function_disable(struct usb_function *f)
 	/* readers may be blocked waiting for us to go online */
 	wake_up(&dev->read_wq);
 
-	VDBG(cdev, "%s disabled\n", dev->function.name);
+	VDBG(cdev, "%s disabled\n", dev->function.name);printk("%s disabled\n", dev->function.name);
 }
 #if 0
 static int adb_bind_config(struct usb_configuration *c)
@@ -612,6 +779,8 @@ static int adb_setup(struct adb_dev *dev)
 	atomic_set(&dev->write_excl, 0);
 
 	INIT_LIST_HEAD(&dev->tx_idle);
+	INIT_LIST_HEAD(&dev->rx_idle);
+	INIT_LIST_HEAD(&dev->rx_used);
 
 	ret = misc_register(&adb_device);
 	if (ret)
@@ -728,6 +897,7 @@ struct usb_function *adb_alloc(struct usb_function_instance *fi)
 	dev->function.unbind = adb_function_unbind;
 	dev->function.set_alt = adb_function_set_alt;
 	dev->function.disable = adb_function_disable;
+	dev->function.suspend = adb_function_suspend;
 	dev->function.free_func = adb_free;
 
 	return &dev->function;