On Wed, 4 Oct 2006, Martin Christoph wrote:

> Alan Stern wrote:
> 
> > It's not at all obvious what the problem is.  It would help to have a USB
> > trace showing the new Pad working correctly.  I don't know if the 2.6.15
> > version of usbmon is capable of doing that, but it's worth a try.  
> > Otherwise you could use a USB sniffer program for Windows to get the
> > equivalent data.
> 
> Thank you for your reply. With Kernel 2.6.15 i obtained the attached traces 
> while plugging the new
> Pad in and out.
> 
> The difference to Kernel 2.6.18 is that after the last message (which 
> appeares to be the same as in
> Kernel 2.6.15 usbmon output) comes something similar to this in an endless 
> loop:
> 
> d5f2dc40 2958985986 C Ii:093:01 -32 0
> d5f2dc40 2958986000 S Ii:093:01 -115 8 <
> d5ac9f40 2958986007 C Ii:093:02 -32 0
> d5ac9f40 2958986010 S Ii:093:02 -115 6 <
> d5f2dc40 2958993974 C Ii:093:01 -32 0
> d5f2dc40 2958993988 S Ii:093:01 -115 8 <
> d5ac9f40 2958993995 C Ii:093:02 -32 0
> d5ac9f40 2958993999 S Ii:093:02 -115 6 <
> d5f2dc40 2959001968 C Ii:093:01 -32 0
> d5f2dc40 2959001982 S Ii:093:01 -115 8 <
> d5ac9f40 2959001988 C Ii:093:02 -32 0
> d5ac9f40 2959001992 S Ii:093:02 -115 6 <
> 
> Syslog produces an output like that:
> Sep 25 14:40:04 testimage kernel: drivers/usb/input/hid-core.c: input irq 
> status -32 received
> Sep 25 14:40:08 testimage last message repeated 1083 times

Now the problem is obvious.  The USB HID driver doesn't have any way to 
clear a halt condition on the interrupt-IN endpoint.

Of course, there's no reason for the device to halt the endpoint in the 
first place.  Nevertheless, it does so.

Try the patch below, and send in another usbmon listing together with the 
dmesg log if it doesn't work.

Alan Stern



Index: usb-2.6/drivers/usb/input/hid.h
===================================================================
--- usb-2.6.orig/drivers/usb/input/hid.h
+++ usb-2.6/drivers/usb/input/hid.h
@@ -384,6 +384,7 @@ struct hid_control_fifo {
 #define HID_IN_RUNNING         3
 #define HID_RESET_PENDING      4
 #define HID_SUSPENDED          5
+#define HID_CLEAR_HALT         6
 
 struct hid_input {
        struct list_head list;
Index: usb-2.6/drivers/usb/input/hid-core.c
===================================================================
--- usb-2.6.orig/drivers/usb/input/hid-core.c
+++ usb-2.6/drivers/usb/input/hid-core.c
@@ -935,20 +935,29 @@ static void hid_retry_timeout(unsigned l
                hid_io_error(hid);
 }
 
-/* Workqueue routine to reset the device */
+/* Workqueue routine to reset the device or clear a halt */
 static void hid_reset(void *_hid)
 {
        struct hid_device *hid = (struct hid_device *) _hid;
-       int rc_lock, rc;
+       int rc_lock, rc = 0;
 
-       dev_dbg(&hid->intf->dev, "resetting device\n");
-       rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf);
-       if (rc_lock >= 0) {
-               rc = usb_reset_composite_device(hid->dev, hid->intf);
-               if (rc_lock)
-                       usb_unlock_device(hid->dev);
+       if (test_bit(HID_CLEAR_HALT, &hid->iofl)) {
+               dev_dbg(&hid->intf->dev, "clear halt\n");
+               rc = usb_clear_halt(hid->dev, hid->urbin->pipe);
+               clear_bit(HID_CLEAR_HALT, &hid->iofl);
+               hid_start_in(hid);
+       }
+
+       else if (test_bit(HID_RESET_PENDING, &hid->iofl)) {
+               dev_dbg(&hid->intf->dev, "resetting device\n");
+               rc = rc_lock = usb_lock_device_for_reset(hid->dev, hid->intf);
+               if (rc_lock >= 0) {
+                       rc = usb_reset_composite_device(hid->dev, hid->intf);
+                       if (rc_lock)
+                               usb_unlock_device(hid->dev);
+               }
+               clear_bit(HID_RESET_PENDING, &hid->iofl);
        }
-       clear_bit(HID_RESET_PENDING, &hid->iofl);
 
        switch (rc) {
        case 0:
@@ -990,9 +999,8 @@ static void hid_io_error(struct hid_devi
 
                /* Retries failed, so do a port reset */
                if (!test_and_set_bit(HID_RESET_PENDING, &hid->iofl)) {
-                       if (schedule_work(&hid->reset_work))
-                               goto done;
-                       clear_bit(HID_RESET_PENDING, &hid->iofl);
+                       schedule_work(&hid->reset_work);
+                       goto done;
                }
        }
 
@@ -1016,6 +1024,10 @@ static void hid_irq_in(struct urb *urb, 
                        hid->retry_delay = 0;
                        hid_input_report(HID_INPUT_REPORT, urb, 1, regs);
                        break;
+               case -EPIPE:            /* stall */
+                       set_bit(HID_CLEAR_HALT, &hid->iofl);
+                       schedule_work(&hid->reset_work);
+                       return;
                case -ECONNRESET:       /* unlink */
                case -ENOENT:
                case -ESHUTDOWN:        /* unplug */


-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys -- and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
linux-usb-devel@lists.sourceforge.net
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to