Our current scheme for managing the lifetimes of interfaces based on 
their embedded struct device doesn't work.

As things stand:

        usb_parse_configuration() calls device_initialize() for
        every interface in every configuration, at the time the
        USB device is first created.

        usb_set_configuration() calls device_add() for each
        interface in the configuration being activated.

        It also calls usb_disable_device(), which in turn calls 
        device_del() for each interface in the configuration
        being deactivated.

        Finally, usb_release_dev() first calls usb_disable_device()
        and then usb_destroy_configuration(), which in turn calls 
        put_device() for every interface in every configuration.

Here's the problem: So long as the interface's embedded struct device has
a nonzero refcount (which it does until usb_destroy_configuration), it
will hold a reference to its parent usb_device.  Consequently
usb_release_dev() is never called, because the usb_device's refcount
never goes to 0!

The only solution I can see is to go back to the way things used to be.  
Don't use device_initialize() and put_device().  Instead call
device_register() and device_unregister() for each interface when its
configuration is activated and deactivated.

The problem with this is that we might end up re-registering an interface
while someone still holds a reference to an old incarnation.  That is, we
register an interface for config #1, someone grabs a reference to it, we
then switch to config #2 and deregister the interface, then we switch back
to config #1 and try to register it again, but there's still that
outstanding reference.  To rule out this possibility, when deactivating a
configuration we must wait until all the interfaces in that config have
been released.

Comments or complaints, anyone?

Alan Stern


--- 2.6/drivers/usb/core/config.c.orig  Tue Dec 16 16:41:44 2003
+++ 2.6/drivers/usb/core/config.c       Thu Dec 18 15:11:36 2003
@@ -70,13 +70,10 @@
        return buffer - buffer0;
 }
 
-static void usb_release_intf(struct device *dev)
+static void usb_free_intf(struct usb_interface *intf)
 {
-       struct usb_interface *intf;
        int j;
 
-       intf = to_usb_interface(dev);
-
        if (intf->altsetting) {
                for (j = 0; j < intf->num_altsetting; j++) {
                        struct usb_host_interface *as = &intf->altsetting[j];
@@ -303,8 +300,6 @@
                        return -ENOMEM;
                }
                memset(interface, 0, sizeof(struct usb_interface));
-               interface->dev.release = usb_release_intf;
-               device_initialize(&interface->dev);
 
                interface->num_altsetting = nalts[i];
                if (interface->num_altsetting > USB_MAXALTSETTING) {
@@ -395,7 +390,7 @@
                        struct usb_interface *ifp = cf->interface[i];
 
                        if (ifp)
-                               put_device(&ifp->dev);
+                               usb_free_intf(ifp);
                }
        }
        kfree(dev->config);
--- 2.6/drivers/usb/core/message.c.orig Mon Dec 15 12:02:38 2003
+++ 2.6/drivers/usb/core/message.c      Thu Dec 18 15:14:04 2003
@@ -804,12 +804,16 @@
        if (dev->actconfig) {
                for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++) {
                        struct usb_interface    *interface;
+                       struct completion       intf_completion;
 
                        /* remove this interface */
                        interface = dev->actconfig->interface[i];
                        dev_dbg (&dev->dev, "unregistering interface %s\n",
                                interface->dev.bus_id);
-                       device_del(&interface->dev);
+                       init_completion (&intf_completion);
+                       interface->dev.complete = &intf_completion;
+                       device_unregister (&interface->dev);
+                       wait_for_completion (&intf_completion);
                }
                dev->actconfig = 0;
                if (dev->state == USB_STATE_CONFIGURED)
@@ -1135,7 +1139,7 @@
                                "registering %s (config #%d, interface %d)\n",
                                intf->dev.bus_id, configuration,
                                desc->bInterfaceNumber);
-                       device_add (&intf->dev);
+                       device_register (&intf->dev);
                        usb_create_driverfs_intf_files (intf);
                }
        }



-------------------------------------------------------
This SF.net email is sponsored by: IBM Linux Tutorials.
Become an expert in LINUX or just sharpen your skills.  Sign up for IBM's
Free Linux Tutorials.  Learn everything from the bash shell to sys admin.
Click now! http://ads.osdn.com/?ad_id=1278&alloc_id=3371&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