ChangeSet 1.1673.8.64, 2004/03/31 13:35:04-08:00, [EMAIL PROTECTED]

[PATCH] USB: remove usb_interface.driver field

Remove usb_interface.driver, and along with it the "half bound" state
previously associated with drivers binding with claim() instead of probe().
This changes usb_driver_claim_interface() semantics slightly: drivers must
now be prepared to accept disconnect() callbacks.

Fixes more locking bugs, and a claim() oops that snuck in with a
recent patch.


 drivers/usb/core/devices.c |    4 +-
 drivers/usb/core/devio.c   |   88 ++++++++++++++++-----------------------------
 drivers/usb/core/message.c |   25 +++++++++++-
 drivers/usb/core/usb.c     |   87 ++++++++++++++------------------------------
 include/linux/usb.h        |   18 ++++++++-
 5 files changed, 102 insertions(+), 120 deletions(-)


diff -Nru a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
--- a/drivers/usb/core/devices.c        Wed Apr 14 14:34:40 2004
+++ b/drivers/usb/core/devices.c        Wed Apr 14 14:34:40 2004
@@ -247,7 +247,9 @@
                         class_decode(desc->bInterfaceClass),
                         desc->bInterfaceSubClass,
                         desc->bInterfaceProtocol,
-                        iface->driver ? iface->driver->name : "(none)");
+                        iface->dev.driver
+                               ? iface->dev.driver->name
+                               : "(none)");
        up_read(&usb_bus_type.subsys.rwsem);
        return start;
 }
diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
--- a/drivers/usb/core/devio.c  Wed Apr 14 14:34:40 2004
+++ b/drivers/usb/core/devio.c  Wed Apr 14 14:34:40 2004
@@ -704,9 +704,9 @@
        if ((ret = findintfif(ps->dev, gd.interface)) < 0)
                return ret;
        interface = ps->dev->actconfig->interface[ret];
-       if (!interface->driver)
+       if (!interface->dev.driver)
                return -ENODATA;
-       strcpy(gd.driver, interface->driver->name);
+       strncpy(gd.driver, interface->dev.driver->name, sizeof(gd.driver));
        if (copy_to_user(arg, &gd, sizeof(gd)))
                return -EFAULT;
        return 0;
@@ -725,26 +725,11 @@
 
 static int proc_resetdevice(struct dev_state *ps)
 {
-       int i, ret;
-
-       ret = usb_reset_device(ps->dev);
-       if (ret < 0)
-               return ret;
-
-       for (i = 0; i < ps->dev->actconfig->desc.bNumInterfaces; i++) {
-               struct usb_interface *intf = ps->dev->actconfig->interface[i];
-
-               /* Don't simulate interfaces we've claimed */
-               if (test_bit(i, &ps->ifclaimed))
-                       continue;
-
-               err ("%s - this function is broken", __FUNCTION__);
-               if (intf->driver && ps->dev) {
-                       usb_probe_interface (&intf->dev);
-               }
-       }
+       /* FIXME when usb_reset_device() is fixed we'll need to grab
+        * ps->dev->serialize before calling it.
+        */
+       return usb_reset_device(ps->dev);
 
-       return 0;
 }
 
 static int proc_setintf(struct dev_state *ps, void __user *arg)
@@ -758,7 +743,7 @@
        if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
                return ret;
        interface = ps->dev->actconfig->interface[ret];
-       if (interface->driver) {
+       if (interface->dev.driver) {
                if ((ret = checkintf(ps, ret)))
                        return ret;
        }
@@ -1141,58 +1126,51 @@
                }
        }
 
-       if (!ps->dev)
-               retval = -ENODEV;
-       else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
+       if (!ps->dev) {
+               if (buf)
+                       kfree(buf);
+               return -ENODEV;
+       }
+
+       down(&ps->dev->serialize);
+       if (ps->dev->state != USB_STATE_CONFIGURED)
+               retval = -ENODEV;
+       else if (!(ifp = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
                retval = -EINVAL;
-       else switch (ctrl.ioctl_code) {
+       else switch (ctrl.ioctl_code) {
 
-       /* disconnect kernel driver from interface, leaving it unbound.  */
-       /* maybe unbound - you get no guarantee it stays unbound */
-       case USBDEVFS_DISCONNECT:
-               /* this function is misdesigned - retained for compatibility */
-               lock_kernel();
-               driver = ifp->driver;
-               if (driver) {
-                       dbg ("disconnect '%s' from dev %d interface %d",
-                            driver->name, ps->dev->devnum, ctrl.ifno);
-                       usb_unbind_interface(&ifp->dev);
+       /* disconnect kernel driver from interface */
+       case USBDEVFS_DISCONNECT:
+               down_write(&usb_bus_type.subsys.rwsem);
+               if (ifp->dev.driver) {
+                       driver = to_usb_driver(ifp->dev.driver);
+                       dev_dbg (&ifp->dev, "disconnect by usbfs\n");
+                       usb_driver_release_interface(driver, ifp);
                } else
                        retval = -ENODATA;
-               unlock_kernel();
+               up_write(&usb_bus_type.subsys.rwsem);
                break;
 
        /* let kernel drivers try to (re)bind to the interface */
        case USBDEVFS_CONNECT:
-               lock_kernel();
-               retval = usb_probe_interface (&ifp->dev);
-               unlock_kernel();
+               bus_rescan_devices(ifp->dev.bus);
                break;
 
        /* talk directly to the interface's driver */
        default:
-               /* BKL used here to protect against changing the binding
-                * of this driver to this device, as well as unloading its
-                * driver module.
-                */
-               lock_kernel ();
-               driver = ifp->driver;
+               down_read(&usb_bus_type.subsys.rwsem);
+               if (ifp->dev.driver)
+                       driver = to_usb_driver(ifp->dev.driver);
                if (driver == 0 || driver->ioctl == 0) {
-                       unlock_kernel();
-                       retval = -ENOSYS;
+                       retval = -ENOTTY;
                } else {
-                       if (!try_module_get (driver->owner)) {
-                               unlock_kernel();
-                               retval = -ENOSYS;
-                               break;
-                       }
-                       unlock_kernel ();
                        retval = driver->ioctl (ifp, ctrl.ioctl_code, buf);
                        if (retval == -ENOIOCTLCMD)
                                retval = -ENOTTY;
-                       module_put (driver->owner);
                }
+               up_read(&usb_bus_type.subsys.rwsem);
        }
+       up(&ps->dev->serialize);
 
        /* cleanup and return */
        if (retval >= 0
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c        Wed Apr 14 14:34:40 2004
+++ b/drivers/usb/core/message.c        Wed Apr 14 14:34:40 2004
@@ -1176,15 +1176,34 @@
                        intf->dev.bus = &usb_bus_type;
                        intf->dev.dma_mask = dev->dev.dma_mask;
                        intf->dev.release = release_interface;
+                       device_initialize (&intf->dev);
                        sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
                                 dev->bus->busnum, dev->devpath,
                                 configuration,
                                 alt->desc.bInterfaceNumber);
+               }
+
+               /* Now that all interfaces are setup, probe() calls
+                * may claim() any interface that's not yet bound.
+                * Many class drivers need that: CDC, audio, video, etc.
+                */
+               for (i = 0; i < cp->desc.bNumInterfaces; ++i) {
+                       struct usb_interface *intf = cp->interface[i];
+                       struct usb_interface_descriptor *desc;
+
+                       desc = &intf->altsetting [0].desc;
                        dev_dbg (&dev->dev,
-                               "registering %s (config #%d, interface %d)\n",
+                               "adding %s (config #%d, interface %d)\n",
                                intf->dev.bus_id, configuration,
-                               alt->desc.bInterfaceNumber);
-                       device_register (&intf->dev);
+                               desc->bInterfaceNumber);
+                       ret = device_add (&intf->dev);
+                       if (ret != 0) {
+                               dev_err(&dev->dev,
+                                       "device_add(%s) --> %d\n",
+                                       intf->dev.bus_id,
+                                       ret);
+                               continue;
+                       }
                        usb_create_driverfs_intf_files (intf);
                }
        }
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c    Wed Apr 14 14:34:40 2004
+++ b/drivers/usb/core/usb.c    Wed Apr 14 14:34:40 2004
@@ -7,8 +7,7 @@
  * (C) Copyright Gregory P. Smith 1999
  * (C) Copyright Deti Fliegl 1999 (new USB architecture)
  * (C) Copyright Randy Dunlap 2000
- * (C) Copyright David Brownell 2000-2001 (kernel hotplug, usb_device_id,
-       more docs, etc)
+ * (C) Copyright David Brownell 2000-2004
  * (C) Copyright Yggdrasil Computing, Inc. 2000
  *     (usb_device_id matching changes by Adam J. Richter)
  * (C) Copyright Greg Kroah-Hartman 2002-2003
@@ -95,17 +94,11 @@
        if (!driver->probe)
                return error;
 
-       /* driver claim() doesn't yet affect dev->driver... */
-       if (intf->driver)
-               return error;
-
        id = usb_match_id (intf, driver->id_table);
        if (id) {
                dev_dbg (dev, "%s - got id\n", __FUNCTION__);
                error = driver->probe (intf, id);
        }
-       if (!error)
-               intf->driver = driver;
 
        return error;
 }
@@ -114,7 +107,7 @@
 int usb_unbind_interface(struct device *dev)
 {
        struct usb_interface *intf = to_usb_interface(dev);
-       struct usb_driver *driver = intf->driver;
+       struct usb_driver *driver = to_usb_driver(intf->dev.driver);
 
        /* release all urbs for this interface */
        usb_disable_interface(interface_to_usbdev(intf), intf);
@@ -127,7 +120,6 @@
                        intf->altsetting[0].desc.bInterfaceNumber,
                        0);
        usb_set_intfdata(intf, NULL);
-       intf->driver = NULL;
 
        return 0;
 }
@@ -290,7 +282,8 @@
 /**
  * usb_driver_claim_interface - bind a driver to an interface
  * @driver: the driver to be bound
- * @iface: the interface to which it will be bound
+ * @iface: the interface to which it will be bound; must be in the
+ *     usb device's active configuration
  * @priv: driver data associated with that interface
  *
  * This is used by usb device drivers that need to claim more than one
@@ -308,75 +301,52 @@
  */
 int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface 
*iface, void* priv)
 {
-       if (!iface || !driver)
-               return -EINVAL;
+       struct device *dev = &iface->dev;
 
-       if (iface->driver)
+       if (dev->driver)
                return -EBUSY;
 
-       /* FIXME should device_bind_driver() */
-       iface->driver = driver;
+       dev->driver = &driver->driver;
        usb_set_intfdata(iface, priv);
-       return 0;
-}
 
-/**
- * usb_interface_claimed - returns true iff an interface is claimed
- * @iface: the interface being checked
- *
- * This should be used by drivers to check other interfaces to see if
- * they are available or not.  If another driver has claimed the interface,
- * they may not claim it.  Otherwise it's OK to claim it using
- * usb_driver_claim_interface().
- *
- * Returns true (nonzero) iff the interface is claimed, else false (zero).
- */
-int usb_interface_claimed(struct usb_interface *iface)
-{
-       if (!iface)
-               return 0;
+       /* if interface was already added, bind now; else let
+        * the future device_add() bind it, bypassing probe()
+        */
+       if (!list_empty (&dev->bus_list))
+               device_bind_driver(dev);
 
-       return (iface->driver != NULL);
-} /* usb_interface_claimed() */
+       return 0;
+}
 
 /**
  * usb_driver_release_interface - unbind a driver from an interface
  * @driver: the driver to be unbound
  * @iface: the interface from which it will be unbound
  *
- * In addition to unbinding the driver, this re-initializes the interface
- * by selecting altsetting 0, the default alternate setting.
- * 
  * This can be used by drivers to release an interface without waiting
- * for their disconnect() methods to be called.
- *
- * When the USB subsystem disconnect()s a driver from some interface,
- * it automatically invokes this method for that interface.  That
- * means that even drivers that used usb_driver_claim_interface()
- * usually won't need to call this.
+ * for their disconnect() methods to be called.  In typical cases this
+ * also causes the driver disconnect() method to be called.
  *
  * This call is synchronous, and may not be used in an interrupt context.
- * Callers must own the driver model's usb bus writelock.  So driver
- * disconnect() entries don't need extra locking, but other call contexts
- * may need to explicitly claim that lock.
+ * Callers must own the usb_device serialize semaphore and the driver model's
+ * usb bus writelock.  So driver disconnect() entries don't need extra locking,
+ * but other call contexts may need to explicitly claim those locks.
  */
-void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface 
*iface)
+void usb_driver_release_interface(struct usb_driver *driver,
+                                       struct usb_interface *iface)
 {
+       struct device *dev = &iface->dev;
+
        /* this should never happen, don't release something that's not ours */
-       if (!iface || !iface->driver || iface->driver != driver)
+       if (!dev->driver || dev->driver != &driver->driver)
                return;
 
-       if (iface->dev.driver) {
-               /* FIXME should be the ONLY case here */
-               device_release_driver(&iface->dev);
-               return;
-       }
+       /* don't disconnect from disconnect(), or before dev_add() */
+       if (!list_empty (&dev->driver_list) && !list_empty (&dev->bus_list))
+               device_release_driver(dev);
 
-       usb_set_interface(interface_to_usbdev(iface),
-                       iface->altsetting[0].desc.bInterfaceNumber,
-                       0);
+       dev->driver = NULL;
        usb_set_intfdata(iface, NULL);
-       iface->driver = NULL;
 }
 
 /**
@@ -1633,7 +1603,6 @@
 EXPORT_SYMBOL(usb_hub_tt_clear_buffer);
 
 EXPORT_SYMBOL(usb_driver_claim_interface);
-EXPORT_SYMBOL(usb_interface_claimed);
 EXPORT_SYMBOL(usb_driver_release_interface);
 EXPORT_SYMBOL(usb_match_id);
 EXPORT_SYMBOL(usb_find_interface);
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h       Wed Apr 14 14:34:40 2004
+++ b/include/linux/usb.h       Wed Apr 14 14:34:40 2004
@@ -31,6 +31,7 @@
 }
 
 struct usb_device;
+struct usb_driver;
 
 /*-------------------------------------------------------------------------*/
 
@@ -123,7 +124,6 @@
                                         * active alternate setting */
        unsigned num_altsetting;        /* number of alternate settings */
 
-       struct usb_driver *driver;      /* driver */
        int minor;                      /* minor number this interface is bound to */
        struct device dev;              /* interface specific device info */
        struct class_device *class_dev;
@@ -318,7 +318,21 @@
 /* used these for multi-interface device registration */
 extern int usb_driver_claim_interface(struct usb_driver *driver,
                        struct usb_interface *iface, void* priv);
-extern int usb_interface_claimed(struct usb_interface *iface);
+
+/**
+ * usb_interface_claimed - returns true iff an interface is claimed
+ * @iface: the interface being checked
+ *
+ * Returns true (nonzero) iff the interface is claimed, else false (zero).
+ * Callers must own the driver model's usb bus readlock.  So driver
+ * probe() entries don't need extra locking, but other call contexts
+ * may need to explicitly claim that lock.
+ *
+ */
+static int inline usb_interface_claimed(struct usb_interface *iface) {
+       return (iface->dev.driver != NULL);
+}
+
 extern void usb_driver_release_interface(struct usb_driver *driver,
                        struct usb_interface *iface);
 const struct usb_device_id *usb_match_id(struct usb_interface *interface,



-------------------------------------------------------
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_id70&alloc_id638&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