On Thu, 8 Apr 2004, Marcel Holtmann wrote:

> Hi Alan,
> 
> many thanks for looking at the problem.

You're welcome.

>  I am not an expert when it comes
> to USB internals, but from your explanation I ask myself why we don't
> have an unlink function that will wait until the last reference to the
> URB is gone. Why do we have to do it in the driver itself?

I feel the same way.  The API works as designed, but the design itself
should be improved.  A function very much like the one I added to your
driver will probably go into the USB core, but I don't know when.  
Another change I would like to see would be to have separate
usb_unlink_urb functions for synchronous and asynchronous; that would
affect so many drivers that it's not likely to happen any time soon.

> > By the way, I noticed a couple of other little things in the driver that
> > could be improved.  The first is _urb_alloc() -- it should call
> > usb_init_urb() rather than initializing the URB by hand.  The second was
> > the test of the HCI_RUNNING flags bit in the hci_usb_{t,r}x_complete()  
> > functions.  Those tests should be made while holding hci->completion_lock
> > for proper synchronization.  Otherwise you can have a race on an SMP
> > system in which hci_usb_rx_complete() finds the bit is set; then on
> > another processor hci_usb_close() clears the bit, grabs & releases the
> > lock, and unlinks all the active URBs; then the first processor acquires
> > the lock and resubmits the URB.
> 
> Good points. Do you have a patch for me?

Here's a combined patch.  Would you like to submit these changes to Greg?

Alan Stern



===== drivers/bluetooth/hci_usb.c 1.42 vs edited =====
--- 1.42/drivers/bluetooth/hci_usb.c    Tue Mar 30 17:57:21 2004
+++ edited/drivers/bluetooth/hci_usb.c  Fri Apr  9 11:28:24 2004
@@ -109,8 +109,7 @@
                                sizeof(struct usb_iso_packet_descriptor) * isoc, gfp);
        if (_urb) {
                memset(_urb, 0, sizeof(*_urb));
-               _urb->urb.count = (atomic_t)ATOMIC_INIT(1);
-               spin_lock_init(&_urb->urb.lock);
+               usb_init_urb(&_urb->urb);
        }
        return _urb;
 }
@@ -341,6 +340,14 @@
        return 0;
 }
 
+static void inline wait_for_urb(struct urb *urb)
+{
+       while (atomic_read(&urb->count) > 1) {
+               current->state = TASK_UNINTERRUPTIBLE;
+               schedule_timeout((5 * HZ + 999) / 1000);
+       }
+}
+
 static void hci_usb_unlink_urbs(struct hci_usb *husb)
 {
        int i;
@@ -357,6 +364,7 @@
                        BT_DBG("%s unlinking _urb %p type %d urb %p", 
                                        husb->hdev->name, _urb, _urb->type, urb);
                        usb_unlink_urb(urb);
+                       wait_for_urb(urb);
                        _urb_queue_tail(__completed_q(husb, _urb->type), _urb);
                }
 
@@ -699,11 +707,11 @@
        BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb,
                        _urb->type, urb->status, count, urb->transfer_flags);
 
-       if (!test_bit(HCI_RUNNING, &hdev->flags))
-               return;
-
        read_lock(&husb->completion_lock);
 
+       if (!test_bit(HCI_RUNNING, &hdev->flags))
+               goto done;
+
        if (urb->status || !count)
                goto resubmit;
 
@@ -739,6 +747,7 @@
        BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb,
                        _urb->type, err);
 
+done:
        read_unlock(&husb->completion_lock);
 }
 



-------------------------------------------------------
This SF.Net email is sponsored by: IBM Linux Tutorials
Free Linux tutorial presented by Daniel Robbins, President and CEO of
GenToo technologies. Learn everything from fundamentals to system
administration.http://ads.osdn.com/?ad_id=1470&alloc_id=3638&op=click
_______________________________________________
[EMAIL PROTECTED]
To unsubscribe, use the last form field at:
https://lists.sourceforge.net/lists/listinfo/linux-usb-devel

Reply via email to