Re: btusb_intr_complete returns -EPIPE

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 2014-10-06 at 18:33 +0530, Naveen Kumar Parna wrote:
> Thank you very much. I will try that patch.

Then please try.

	Regards
		Oliver

>From f9f74591abed07ee71c46d443dd10176d05096c5 Mon Sep 17 00:00:00 2001
From: Oliver Neukum <oneukum@xxxxxxx>
Date: Mon, 6 Oct 2014 15:27:54 +0200
Subject: [PATCH] btusb: clear halt if intr in stalls

Use a work queue for clearing a halt.

Signed-off-by: Oliver Neukum <oneukum@xxxxxxx>
---
 drivers/bluetooth/btusb.c | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 292c38e..65a2c6b 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -273,6 +273,7 @@ struct btusb_data {
 
 	struct work_struct work;
 	struct work_struct waker;
+	struct work_struct intr_in_work;
 
 	struct usb_anchor tx_anchor;
 	struct usb_anchor intr_anchor;
@@ -314,14 +315,15 @@ static void btusb_intr_complete(struct urb *urb)
 	struct hci_dev *hdev = urb->context;
 	struct btusb_data *data = hci_get_drvdata(hdev);
 	int err;
+	int status = urb->status;
 
 	BT_DBG("%s urb %p status %d count %d", hdev->name,
-					urb, urb->status, urb->actual_length);
+					urb, status, urb->actual_length);
 
 	if (!test_bit(HCI_RUNNING, &hdev->flags))
 		return;
 
-	if (urb->status == 0) {
+	if (status == 0) {
 		hdev->stat.byte_rx += urb->actual_length;
 
 		if (hci_recv_fragment(hdev, HCI_EVENT_PKT,
@@ -330,6 +332,10 @@ static void btusb_intr_complete(struct urb *urb)
 			BT_ERR("%s corrupted event packet", hdev->name);
 			hdev->stat.err_rx++;
 		}
+	} else if (status == -EPIPE) {
+		usb_mark_last_busy(data->udev);
+		schedule_work(&data->intr_in_work);
+		return;
 	}
 
 	if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
@@ -971,6 +977,29 @@ static void btusb_waker(struct work_struct *work)
 	usb_autopm_put_interface(data->intf);
 }
 
+static void clear_halt_intr_in(struct work_struct *work)
+{
+	struct btusb_data *data = container_of(work, struct btusb_data, waker);
+	int err;
+
+	err = usb_autopm_get_interface(data->intf);
+	if (err < 0)
+		return;
+
+	err = usb_clear_halt(data->udev,
+			     usb_rcvbulkpipe(data->udev,
+					     data->intr_ep->bEndpointAddress));
+	if (err < 0)
+		return;
+
+	if (!test_bit(BTUSB_INTR_RUNNING, &data->flags))
+		return;
+
+	btusb_submit_intr_urb(data->hdev, GFP_ATOMIC);
+
+	usb_autopm_put_interface(data->intf);
+}
+
 static int btusb_setup_bcm92035(struct hci_dev *hdev)
 {
 	struct sk_buff *skb;
@@ -1759,6 +1788,7 @@ static int btusb_probe(struct usb_interface *intf,
 
 	INIT_WORK(&data->work, btusb_work);
 	INIT_WORK(&data->waker, btusb_waker);
+	INIT_WORK(&data->intr_in_work, clear_halt_intr_in);
 	spin_lock_init(&data->txlock);
 
 	init_usb_anchor(&data->tx_anchor);
-- 
1.8.4.5


[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux