1. seandroid
  2. Untitled project
  3. kernel/common

Commits

keunyoung  committed 95ec218

fix false disconnect due to a signal sent to the reading process

- In the current implementation, when a signal is sent to the reading process,
read is cancelled by calling usb_ep_dequeue, which lead into calling
acc_complete_out with ECONNRESET, but the current logic treats it as
disconnection, which makes the device inaccessible until cable is actually
disconnected.
- The fix calls disconnect only when ESHUTDOWN error is passed.
- If data has already arrived while trying cancelling, the data is marked
as available, and it will be read out on the next read. This is necessary
as USB bulk is assumed to guarantee no data loss.

Signed-off-by: keunyoung <keunyoung@google.com>

  • Participants
  • Parent commits 57320e6
  • Branches android-3.4

Comments (0)

Files changed (1)

File drivers/usb/gadget/f_accessory.c

View file
  • Ignore whitespace
 {
 	struct acc_dev *dev = _acc_dev;
 
-	if (req->status != 0)
+	if (req->status == -ESHUTDOWN) {
+		pr_debug("acc_complete_in set disconnected");
 		acc_set_disconnected(dev);
+	}
 
 	req_put(dev, &dev->tx_idle, req);
 
 	struct acc_dev *dev = _acc_dev;
 
 	dev->rx_done = 1;
-	if (req->status != 0)
+	if (req->status == -ESHUTDOWN) {
+		pr_debug("acc_complete_out set disconnected");
 		acc_set_disconnected(dev);
+	}
 
 	wake_up(&dev->read_wq);
 }
 
 	pr_debug("acc_read(%d)\n", count);
 
-	if (dev->disconnected)
+	if (dev->disconnected) {
+		pr_debug("acc_read disconnected");
 		return -ENODEV;
+	}
 
 	if (count > BULK_BUFFER_SIZE)
 		count = BULK_BUFFER_SIZE;
 		goto done;
 	}
 
+	if (dev->rx_done) {
+		// last req cancelled. try to get it.
+		req = dev->rx_req[0];
+		goto copy_data;
+	}
+
 requeue_req:
 	/* queue a request */
 	req = dev->rx_req[0];
 	ret = wait_event_interruptible(dev->read_wq, dev->rx_done);
 	if (ret < 0) {
 		r = ret;
-		usb_ep_dequeue(dev->ep_out, req);
+		ret = usb_ep_dequeue(dev->ep_out, req);
+		if (ret != 0) {
+			// cancel failed. There can be a data already received.
+			// it will be retrieved in the next read.
+			pr_debug("acc_read: cancelling failed %d", ret);
+		}
 		goto done;
 	}
+
+copy_data:
+	dev->rx_done = 0;
 	if (dev->online) {
 		/* If we got a 0-len packet, throw it back and try again. */
 		if (req->actual == 0)
 
 	pr_debug("acc_write(%d)\n", count);
 
-	if (!dev->online || dev->disconnected)
+	if (!dev->online || dev->disconnected) {
+		pr_debug("acc_write disconnected or not online");
 		return -ENODEV;
+	}
 
 	while (count > 0) {
 		if (!dev->online) {