[PATCH v2 3/3] [media] mceusb: Show USB halt/stall error recovery

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

 



patch v2 revisions:
 . Limit patch to message changes only.

Update dev_err() messages to report status (including success) for each
step of USB RX HALT and TX HALT error recovery. If error recovery fails,
show the message:
        stuck RX HALT state requires USB Reset Device to clear
or
        stuck TX HALT state requires USB Reset Device to clear

This patch only affects RX and TX HALT error reporting.

The capability for mceusb to invoke USB reset device for itself is
deferred to a future patch. It's unsafe to perform usb_reset_device()
when and where the driver posts the "... requires USB Reset ..."
message.

Users can fix their mceusb device manually by issuing
ioctl(fd, USBDEVFS_RESET, 0) to the mceusb device, as in:
        $ sudo ./usbreset /dev/bus/usb/001/010

---

As seen on very rare occasions with mceusb device 2304:0225
        [59388.696941] mceusb 1-1.1.2:1.0: Error: urb status = -32 (RX HALT)
        [59388.698838] mceusb 1-1.1.2:1.0: rx clear halt error -32
the device can get into RX or TX HALT state where usb_clear_halt()
also fails and also returns -EPIPE (HALT/STALL). After which,
all further mceusb device control and data I/O fails with HALT/STALL.
Cause and problem replication conditions are still unknown.

Further troubleshooting revealed that usb_reset_device() successfully
restores mceusb device operation.

Of note is "modprobe -r mceusb" with "modprobe mceusb"
usb_reset_endpoint(), and usb_reset_configuration(), were all
unsuccessful.

Signed-off-by: A Sun <as1033x@xxxxxxxxxxx>
---
 drivers/media/rc/mceusb.c | 27 +++++++++++++++++++++------
 1 file changed, 21 insertions(+), 6 deletions(-)

diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index efffb1795..fffd826c6 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -765,7 +765,7 @@ static void mceusb_defer_kevent(struct mceusb_dev *ir, int kevent)
 {
 	set_bit(kevent, &ir->kevent_flags);
 	if (!schedule_work(&ir->kevent))
-		dev_err(ir->dev, "kevent %d may have been dropped", kevent);
+		dev_dbg(ir->dev, "kevent %d already scheduled", kevent);
 	else
 		dev_dbg(ir->dev, "kevent %d scheduled", kevent);
 }
@@ -1404,19 +1404,27 @@ static void mceusb_deferred_kevent(struct work_struct *work)
 		container_of(work, struct mceusb_dev, kevent);
 	int status;
 
+	dev_err(ir->dev, "kevent handler called (flags 0x%lx)",
+		ir->kevent_flags);
+
 	if (test_bit(EVENT_RX_HALT, &ir->kevent_flags)) {
 		usb_unlink_urb(ir->urb_in);
 		status = usb_clear_halt(ir->usbdev, ir->pipe_in);
+		dev_err(ir->dev, "rx clear halt status = %d", status);
 		if (status < 0) {
-			dev_err(ir->dev, "rx clear halt error %d",
-				status);
+			/*
+			 * Unable to clear RX halt/stall.
+			 * Will need to call usb_reset_device().
+			 */
+			dev_err(ir->dev,
+				"stuck RX HALT state requires USB Reset Device to clear");
 		}
 		clear_bit(EVENT_RX_HALT, &ir->kevent_flags);
 		if (status == 0) {
 			status = usb_submit_urb(ir->urb_in, GFP_KERNEL);
 			if (status < 0) {
 				dev_err(ir->dev,
-					"rx unhalt submit urb error %d",
+					"rx unhalt submit urb error = %d",
 					status);
 			}
 		}
@@ -1424,8 +1432,15 @@ static void mceusb_deferred_kevent(struct work_struct *work)
 
 	if (test_bit(EVENT_TX_HALT, &ir->kevent_flags)) {
 		status = usb_clear_halt(ir->usbdev, ir->pipe_out);
-		if (status < 0)
-			dev_err(ir->dev, "tx clear halt error %d", status);
+		dev_err(ir->dev, "tx clear halt status = %d", status);
+		if (status < 0) {
+			/*
+			 * Unable to clear TX halt/stall.
+			 * Will need to call usb_reset_device().
+			 */
+			dev_err(ir->dev,
+				"stuck TX HALT state requires USB Reset Device to clear");
+		}
 		clear_bit(EVENT_TX_HALT, &ir->kevent_flags);
 	}
 }
-- 
2.11.0




[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux