]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/base/bus.c
[PATCH] Driver core: add proper symlinks for devices
[linux-2.6-omap-h63xx.git] / drivers / base / bus.c
index 29f6af554e715ed408f0f23e8da838284dbc9dc7..050d86d0b872880c11807e9ece9bfd8f6b793377 100644 (file)
@@ -133,6 +133,8 @@ static struct kobj_type ktype_bus = {
 decl_subsys(bus, &ktype_bus, NULL);
 
 
+#ifdef CONFIG_HOTPLUG
+
 /* Manually detach a device from its associated driver. */
 static int driver_helper(struct device *dev, void *data)
 {
@@ -186,6 +188,11 @@ static ssize_t driver_bind(struct device_driver *drv,
                up(&dev->sem);
                if (dev->parent)
                        up(&dev->parent->sem);
+
+               if (err > 0)            /* success */
+                       err = count;
+               else if (err == 0)      /* driver didn't accept device */
+                       err = -ENODEV;
        }
        put_device(dev);
        put_bus(bus);
@@ -193,6 +200,7 @@ static ssize_t driver_bind(struct device_driver *drv,
 }
 static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
 
+#endif
 
 static struct device * next_device(struct klist_iter * i)
 {
@@ -354,8 +362,7 @@ static void device_remove_attrs(struct bus_type * bus, struct device * dev)
  *     @dev:   device being added
  *
  *     - Add the device to its bus's list of devices.
- *     - Try to attach to driver.
- *     - Create link to device's physical location.
+ *     - Create link to device's bus.
  */
 int bus_add_device(struct device * dev)
 {
@@ -364,17 +371,32 @@ int bus_add_device(struct device * dev)
 
        if (bus) {
                pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
-               device_attach(dev);
-               klist_add_tail(&dev->knode_bus, &bus->klist_devices);
                error = device_add_attrs(bus, dev);
                if (!error) {
                        sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
+                       sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "subsystem");
                        sysfs_create_link(&dev->kobj, &dev->bus->subsys.kset.kobj, "bus");
                }
        }
        return error;
 }
 
+/**
+ *     bus_attach_device - add device to bus
+ *     @dev:   device tried to attach to a driver
+ *
+ *     - Try to attach to driver.
+ */
+void bus_attach_device(struct device * dev)
+{
+       struct bus_type * bus = dev->bus;
+
+       if (bus) {
+               device_attach(dev);
+               klist_add_tail(&dev->knode_bus, &bus->klist_devices);
+       }
+}
+
 /**
  *     bus_remove_device - remove device from bus
  *     @dev:   device to be removed
@@ -387,6 +409,7 @@ int bus_add_device(struct device * dev)
 void bus_remove_device(struct device * dev)
 {
        if (dev->bus) {
+               sysfs_remove_link(&dev->kobj, "subsystem");
                sysfs_remove_link(&dev->kobj, "bus");
                sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
                device_remove_attrs(dev->bus, dev);
@@ -533,6 +556,28 @@ void bus_rescan_devices(struct bus_type * bus)
        bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);
 }
 
+/**
+ * device_reprobe - remove driver for a device and probe for a new driver
+ * @dev: the device to reprobe
+ *
+ * This function detaches the attached driver (if any) for the given
+ * device and restarts the driver probing process.  It is intended
+ * to use if probing criteria changed during a devices lifetime and
+ * driver attachment should change accordingly.
+ */
+void device_reprobe(struct device *dev)
+{
+       if (dev->driver) {
+               if (dev->parent)        /* Needed for USB */
+                       down(&dev->parent->sem);
+               device_release_driver(dev);
+               if (dev->parent)
+                       up(&dev->parent->sem);
+       }
+
+       bus_rescan_devices_helper(dev, NULL);
+}
+EXPORT_SYMBOL_GPL(device_reprobe);
 
 struct bus_type * get_bus(struct bus_type * bus)
 {
@@ -702,14 +747,9 @@ EXPORT_SYMBOL_GPL(bus_for_each_dev);
 EXPORT_SYMBOL_GPL(bus_find_device);
 EXPORT_SYMBOL_GPL(bus_for_each_drv);
 
-EXPORT_SYMBOL_GPL(bus_add_device);
-EXPORT_SYMBOL_GPL(bus_remove_device);
 EXPORT_SYMBOL_GPL(bus_register);
 EXPORT_SYMBOL_GPL(bus_unregister);
 EXPORT_SYMBOL_GPL(bus_rescan_devices);
-EXPORT_SYMBOL_GPL(get_bus);
-EXPORT_SYMBOL_GPL(put_bus);
-EXPORT_SYMBOL_GPL(find_bus);
 
 EXPORT_SYMBOL_GPL(bus_create_file);
 EXPORT_SYMBOL_GPL(bus_remove_file);