Hi,

        By playing with usb-ohci, I've managed to find a bug in
irda-usb. That may explain some of the problem I've seen and that I
was tracking.
        I did a quick analysis and came up with the patch attached
(that also clean up some related items). I still need to test it on
usb-uhci, and I will bake it off in the next weeks on my box before
sending it to Linus (unless Dag has comments on my comments).
        I welcome you to test the patch and tell me how it works for
you...

        Have fun...

        Jean
diff -u -p linux/include/net/irda/irda-usb.d9.h linux/include/net/irda/irda-usb.h
--- linux/include/net/irda/irda-usb.d9.h        Mon Sep 17 18:26:17 2001
+++ linux/include/net/irda/irda-usb.h   Thu Sep 20 14:02:17 2001
@@ -1,7 +1,7 @@
 /*****************************************************************************
  *
  * Filename:      irda-usb.h
- * Version:       0.9a
+ * Version:       0.9b
  * Description:   IrDA-USB Driver
  * Status:        Experimental 
  * Author:        Dag Brattli <[EMAIL PROTECTED]>
@@ -68,7 +68,7 @@
  * ourselves... See also following option. */
 #undef IU_BUG_KICK_TX
 /* Use the USB_ZERO_PACKET flag instead of sending empty frame (above)
- * Work only with usb-uhci.o so far. Please fix uhic.c and usb-ohci.c */
+ * Work only with usb-uhci.o and usb-ohci.c so far. Please fix uhic.c */
 #define IU_USE_USB_ZERO_FLAG
 /* Send speed command in case of timeout, just for trying to get things sane */
 #define IU_BUG_KICK_TIMEOUT
diff -u -p linux/drivers/net/irda/irda-usb.d9.c linux/drivers/net/irda/irda-usb.c
--- linux/drivers/net/irda/irda-usb.d9.c        Fri Sep 14 19:00:31 2001
+++ linux/drivers/net/irda/irda-usb.c   Thu Sep 20 14:21:41 2001
@@ -1,7 +1,7 @@
 /*****************************************************************************
  *
  * Filename:      irda-usb.c
- * Version:       0.9a
+ * Version:       0.9b
  * Description:   IrDA-USB Driver
  * Status:        Experimental 
  * Author:        Dag Brattli <[EMAIL PROTECTED]>
@@ -239,7 +239,7 @@ static void irda_usb_change_speed_xbofs(
                       frame, IRDA_USB_SPEED_MTU,
                       speed_bulk_callback, self);
        purb->transfer_buffer_length = USB_IRDA_HEADER;
-       purb->transfer_flags = USB_QUEUE_BULK;
+       purb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
        purb->timeout = MSECS_TO_JIFFIES(100);
 
        if ((ret = usb_submit_urb(purb))) {
@@ -275,7 +275,7 @@ static inline void irda_usb_send_empty(s
                       self->speed_buff, IRDA_USB_SPEED_MTU,
                       speed_bulk_callback, self);
        purb->transfer_buffer_length = 0;
-       purb->transfer_flags = USB_QUEUE_BULK;
+       purb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
        purb->timeout = MSECS_TO_JIFFIES(100);
 
        if ((ret = usb_submit_urb(purb))) {
@@ -397,11 +397,13 @@ static int irda_usb_hard_xmit(struct sk_
                       skb->data, IRDA_USB_MAX_MTU,
                       write_bulk_callback, skb);
        purb->transfer_buffer_length = skb->len;
-       purb->transfer_flags = USB_QUEUE_BULK;
+       /* Note : unlink *must* be Asynchronous because of the code in 
+        * irda_usb_net_timeout() -> call in irq - Jean II */
+       purb->transfer_flags = USB_QUEUE_BULK | USB_ASYNC_UNLINK;
 #ifdef IU_USE_USB_ZERO_FLAG
        /* This flag indicates that what we send is not a continuous stream
         * of data but separate frames. In this case, the USB layer will
-        * insert empty packet to separate our frames.
+        * insert empty packet as needed to separate our frames.
         * This flag was previously called USB_DISABLE_SPD - Jean II */
        purb->transfer_flags |= USB_ZERO_PACKET;
 #endif IU_USE_USB_ZERO_FLAG
@@ -563,20 +565,19 @@ static void irda_usb_net_timeout(struct 
                WARNING("%s: Empty change timed out, urb->status=%d, 
urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);
 
                switch (purb->status) {
-               case -ECONNABORTED:             /* -103 */
-               case -ECONNRESET:               /* -104 */
-               case -ENOENT:                   /* -2 */
-                       purb->status = USB_ST_NOERROR;
-                       done = 1;
-                       break;
                case USB_ST_URB_PENDING:        /* -EINPROGRESS == -115 */
                        usb_unlink_urb(purb);
                        /* Note : above will *NOT* call netif_wake_queue()
                         * in completion handler - Jean II */
                        done = 1;
                        break;
-               default:
-                       /* ??? */
+               case -ECONNABORTED:             /* -103 */
+               case -ECONNRESET:               /* -104 */
+               case -ETIMEDOUT:                /* -110 */
+               case -ENOENT:                   /* -2 (urb unlinked by us)  */
+               default:                        /* ??? - Play safe */
+                       purb->status = USB_ST_NOERROR;
+                       done = 1;
                        break;
                }
        }
@@ -588,22 +589,22 @@ static void irda_usb_net_timeout(struct 
                WARNING("%s: Speed change timed out, urb->status=%d, 
urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);
 
                switch (purb->status) {
+               case USB_ST_URB_PENDING:        /* -EINPROGRESS == -115 */
+                       usb_unlink_urb(purb);
+                       /* Note : above will  *NOT* call netif_wake_queue()
+                        * in completion handler, we will come back here.
+                        * Jean II */
+                       done = 1;
+                       break;
                case -ECONNABORTED:             /* -103 */
                case -ECONNRESET:               /* -104 */
-               case -ENOENT:                   /* -2 */
+               case -ETIMEDOUT:                /* -110 */
+               case -ENOENT:                   /* -2 (urb unlinked by us)  */
+               default:                        /* ??? - Play safe */
                        purb->status = USB_ST_NOERROR;
                        netif_wake_queue(self->netdev);
                        done = 1;
                        break;
-               case USB_ST_URB_PENDING:        /* -EINPROGRESS == -115 */
-                       usb_unlink_urb(purb);
-                       /* Note : above will call netif_wake_queue()
-                        * in completion handler - Jean II */
-                       done = 1;
-                       break;
-               default:
-                       /* ??? */
-                       break;
                }
        }
 
@@ -627,9 +628,22 @@ static void irda_usb_net_timeout(struct 
 #endif IU_BUG_KICK_TIMEOUT
 
                switch (purb->status) {
+               case USB_ST_URB_PENDING:        /* -EINPROGRESS == -115 */
+                       usb_unlink_urb(purb);
+                       /* Note : above will  *NOT* call netif_wake_queue()
+                        * in completion handler, because purb->status will
+                        * be -ENOENT. We will fix that at the next watchdog,
+                        * leaving more time to USB to recover...
+                        * Also, we are in interrupt, so we need to have
+                        * USB_ASYNC_UNLINK to work properly...
+                        * Jean II */
+                       done = 1;
+                       break;
                case -ECONNABORTED:             /* -103 */
                case -ECONNRESET:               /* -104 */
-               case -ENOENT:                   /* -2 */
+               case -ETIMEDOUT:                /* -110 */
+               case -ENOENT:                   /* -2 (urb unlinked by us)  */
+               default:                        /* ??? - Play safe */
                        if(skb != NULL) {
                                dev_kfree_skb_any(skb);
                                purb->context = NULL;
@@ -638,15 +652,6 @@ static void irda_usb_net_timeout(struct 
                        netif_wake_queue(self->netdev);
                        done = 1;
                        break;
-               case USB_ST_URB_PENDING:        /* -EINPROGRESS == -115 */
-                       usb_unlink_urb(purb);
-                       /* Note : above will call netif_wake_queue()
-                        * in completion handler - Jean II */
-                       done = 1;
-                       break;
-               default:
-                       /* ??? */
-                       break;
                }
        }
 
@@ -740,6 +745,8 @@ static void irda_usb_submit(struct irda_
                      skb->data, skb->truesize,
                       irda_usb_receive, skb);
        purb->transfer_flags = USB_QUEUE_BULK;
+       /* Note : unlink *must* be synchronous because of the code in 
+        * irda_usb_net_close() -> free the skb - Jean II */
        purb->status = USB_ST_NOERROR;
        purb->next = NULL;      /* Don't auto resubmit URBs */
        

Reply via email to