VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / drivers / base / bus.c
index b40af6a..1270140 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
- * 
+ *
  * This file is released under the GPLv2
  *
  */
 #include "base.h"
 #include "power/power.h"
 
-#define to_dev(node) container_of(node,struct device,bus_list)
-#define to_drv(node) container_of(node,struct device_driver,kobj.entry)
+#define to_dev(node) container_of(node, struct device, bus_list)
+#define to_drv(node) container_of(node, struct device_driver, kobj.entry)
 
-#define to_bus_attr(_attr) container_of(_attr,struct bus_attribute,attr)
-#define to_bus(obj) container_of(obj,struct bus_type,subsys.kset.kobj)
+#define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
+#define to_bus(obj) container_of(obj, struct bus_type, subsys.kset.kobj)
 
 /*
  * sysfs bindings for drivers
  */
 
-#define to_drv_attr(_attr) container_of(_attr,struct driver_attribute,attr)
+#define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr)
 #define to_driver(obj) container_of(obj, struct device_driver, kobj)
 
 
@@ -39,12 +39,12 @@ drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
        ssize_t ret = 0;
 
        if (drv_attr->show)
-               ret = drv_attr->show(drv,buf);
+               ret = drv_attr->show(drv, buf);
        return ret;
 }
 
 static ssize_t
-drv_attr_store(struct kobject * kobj, struct attribute * attr, 
+drv_attr_store(struct kobject * kobj, struct attribute * attr,
               const char * buf, size_t count)
 {
        struct driver_attribute * drv_attr = to_drv_attr(attr);
@@ -52,7 +52,7 @@ drv_attr_store(struct kobject * kobj, struct attribute * attr,
        ssize_t ret = 0;
 
        if (drv_attr->store)
-               ret = drv_attr->store(drv,buf,count);
+               ret = drv_attr->store(drv, buf, count);
        return ret;
 }
 
@@ -87,12 +87,12 @@ bus_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
        ssize_t ret = 0;
 
        if (bus_attr->show)
-               ret = bus_attr->show(bus,buf);
+               ret = bus_attr->show(bus, buf);
        return ret;
 }
 
 static ssize_t
-bus_attr_store(struct kobject * kobj, struct attribute * attr, 
+bus_attr_store(struct kobject * kobj, struct attribute * attr,
               const char * buf, size_t count)
 {
        struct bus_attribute * bus_attr = to_bus_attr(attr);
@@ -100,7 +100,7 @@ bus_attr_store(struct kobject * kobj, struct attribute * attr,
        ssize_t ret = 0;
 
        if (bus_attr->store)
-               ret = bus_attr->store(bus,buf,count);
+               ret = bus_attr->store(bus, buf, count);
        return ret;
 }
 
@@ -113,7 +113,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
 {
        int error;
        if (get_bus(bus)) {
-               error = sysfs_create_file(&bus->subsys.kset.kobj,&attr->attr);
+               error = sysfs_create_file(&bus->subsys.kset.kobj, &attr->attr);
                put_bus(bus);
        } else
                error = -EINVAL;
@@ -123,7 +123,7 @@ int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
 void bus_remove_file(struct bus_type * bus, struct bus_attribute * attr)
 {
        if (get_bus(bus)) {
-               sysfs_remove_file(&bus->subsys.kset.kobj,&attr->attr);
+               sysfs_remove_file(&bus->subsys.kset.kobj, &attr->attr);
                put_bus(bus);
        }
 }
@@ -133,7 +133,7 @@ static struct kobj_type ktype_bus = {
 
 };
 
-decl_subsys(bus,&ktype_bus,NULL);
+decl_subsys(bus, &ktype_bus, NULL);
 
 /**
  *     bus_for_each_dev - device iterator.
@@ -151,10 +151,10 @@ decl_subsys(bus,&ktype_bus,NULL);
  *
  *     NOTE: The device that returns a non-zero value is not retained
  *     in any way, nor is its refcount incremented. If the caller needs
- *     to retain this data, it should do, and increment the reference 
+ *     to retain this data, it should do, and increment the reference
  *     count in the supplied callback.
  */
-int bus_for_each_dev(struct bus_type * bus, struct device * start, 
+int bus_for_each_dev(struct bus_type * bus, struct device * start,
                     void * data, int (*fn)(struct device *, void *))
 {
        struct device *dev;
@@ -170,7 +170,7 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start,
        down_read(&bus->subsys.rwsem);
        list_for_each_entry_continue(dev, head, bus_list) {
                get_device(dev);
-               error = fn(dev,data);
+               error = fn(dev, data);
                put_device(dev);
                if (error)
                        break;
@@ -193,7 +193,7 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start,
  *     and return it. If @start is not NULL, we use it as the head
  *     of the list.
  *
- *     NOTE: we don't return the driver that returns a non-zero 
+ *     NOTE: we don't return the driver that returns a non-zero
  *     value, nor do we leave the reference count incremented for that
  *     driver. If the caller needs to know that info, it must set it
  *     in the callback. It must also be sure to increment the refcount
@@ -216,7 +216,7 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
        down_read(&bus->subsys.rwsem);
        list_for_each_entry_continue(drv, head, kobj.entry) {
                get_driver(drv);
-               error = fn(drv,data);
+               error = fn(drv, data);
                put_driver(drv);
                if(error)
                        break;
@@ -233,8 +233,8 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
  *     Allow manual attachment of a driver to a deivce.
  *     Caller must have already set @dev->driver.
  *
- *     Note that this does not modify the bus reference count 
- *     nor take the bus's rwsem. Please verify those are accounted 
+ *     Note that this does not modify the bus reference count
+ *     nor take the bus's rwsem. Please verify those are accounted
  *     for before calling this. (It is ok to call with no other effort
  *     from a driver's probe() method.)
  */
@@ -242,9 +242,9 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
 void device_bind_driver(struct device * dev)
 {
        pr_debug("bound device '%s' to driver '%s'\n",
-                dev->bus_id,dev->driver->name);
-       list_add_tail(&dev->driver_list,&dev->driver->devices);
-       sysfs_create_link(&dev->driver->kobj,&dev->kobj,
+                dev->bus_id, dev->driver->name);
+       list_add_tail(&dev->driver_list, &dev->driver->devices);
+       sysfs_create_link(&dev->driver->kobj, &dev->kobj,
                          kobject_name(&dev->kobj));
 }
 
@@ -255,18 +255,18 @@ void device_bind_driver(struct device * dev)
  *     @drv:   driver.
  *
  *     First, we call the bus's match function, which should compare
- *     the device IDs the driver supports with the device IDs of the 
- *     device. Note we don't do this ourselves because we don't know 
+ *     the device IDs the driver supports with the device IDs of the
+ *     device. Note we don't do this ourselves because we don't know
  *     the format of the ID structures, nor what is to be considered
  *     a match and what is not.
- *     
- *     If we find a match, we call @drv->probe(@dev) if it exists, and 
+ *
+ *     If we find a match, we call @drv->probe(@dev) if it exists, and
  *     call attach() above.
  */
 static int bus_match(struct device * dev, struct device_driver * drv)
 {
        int error = -ENODEV;
-       if (dev->bus->match(dev,drv)) {
+       if (dev->bus->match(dev, drv)) {
                dev->driver = drv;
                if (drv->probe) {
                        if ((error = drv->probe(dev))) {
@@ -285,7 +285,7 @@ static int bus_match(struct device * dev, struct device_driver * drv)
  *     device_attach - try to attach device to a driver.
  *     @dev:   device.
  *
- *     Walk the list of drivers that the bus has and call bus_match() 
+ *     Walk the list of drivers that the bus has and call bus_match()
  *     for each pair. If a compatible pair is found, break out and return.
  */
 static int device_attach(struct device * dev)
@@ -300,15 +300,15 @@ static int device_attach(struct device * dev)
        }
 
        if (bus->match) {
-               list_for_each(entry,&bus->drivers.list) {
+               list_for_each(entry, &bus->drivers.list) {
                        struct device_driver * drv = to_drv(entry);
-                       error = bus_match(dev,drv);
-                       if (!error )  
+                       error = bus_match(dev, drv);
+                       if (!error)
                                /* success, driver matched */
-                               return 1; 
-                       if (error != -ENODEV) 
+                               return 1;
+                       if (error != -ENODEV)
                                /* driver matched but the probe failed */
-                               printk(KERN_WARNING 
+                               printk(KERN_WARNING
                                    "%s: probe of %s failed with error %d\n",
                                    drv->name, dev->bus_id, error);
                }
@@ -327,7 +327,7 @@ static int device_attach(struct device * dev)
  *     If bus_match() returns 0 and the @dev->driver is set, we've found
  *     a compatible pair.
  *
- *     Note that we ignore the -ENODEV error from bus_match(), since it's 
+ *     Note that we ignore the -ENODEV error from bus_match(), since it's
  *     perfectly valid for a driver not to bind to any devices.
  */
 void driver_attach(struct device_driver * drv)
@@ -339,13 +339,13 @@ void driver_attach(struct device_driver * drv)
        if (!bus->match)
                return;
 
-       list_for_each(entry,&bus->devices.list) {
-               struct device * dev = container_of(entry,struct device,bus_list);
+       list_for_each(entry, &bus->devices.list) {
+               struct device * dev = container_of(entry, struct device, bus_list);
                if (!dev->driver) {
-                       error = bus_match(dev,drv);
+                       error = bus_match(dev, drv);
                        if (error && (error != -ENODEV))
                                /* driver matched but the probe failed */
-                               printk(KERN_WARNING 
+                               printk(KERN_WARNING
                                    "%s: probe of %s failed with error %d\n",
                                    drv->name, dev->bus_id, error);
                }
@@ -367,7 +367,7 @@ void device_release_driver(struct device * dev)
 {
        struct device_driver * drv = dev->driver;
        if (drv) {
-               sysfs_remove_link(&drv->kobj,kobject_name(&dev->kobj));
+               sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
                list_del_init(&dev->driver_list);
                device_detach_shutdown(dev);
                if (drv->remove)
@@ -385,13 +385,44 @@ void device_release_driver(struct device * dev)
 static void driver_detach(struct device_driver * drv)
 {
        struct list_head * entry, * next;
-       list_for_each_safe(entry,next,&drv->devices) {
-               struct device * dev = container_of(entry,struct device,driver_list);
+       list_for_each_safe(entry, next, &drv->devices) {
+               struct device * dev = container_of(entry, struct device, driver_list);
                device_release_driver(dev);
        }
-       
 }
 
+static int device_add_attrs(struct bus_type * bus, struct device * dev)
+{
+       int error = 0;
+       int i;
+
+       if (bus->dev_attrs) {
+               for (i = 0; attr_name(bus->dev_attrs[i]); i++) {
+                       error = device_create_file(dev,&bus->dev_attrs[i]);
+                       if (error)
+                               goto Err;
+               }
+       }
+ Done:
+       return error;
+ Err:
+       while (--i >= 0)
+               device_remove_file(dev,&bus->dev_attrs[i]);
+       goto Done;
+}
+
+
+static void device_remove_attrs(struct bus_type * bus, struct device * dev)
+{
+       int i;
+
+       if (bus->dev_attrs) {
+               for (i = 0; attr_name(bus->dev_attrs[i]); i++)
+                       device_remove_file(dev,&bus->dev_attrs[i]);
+       }
+}
+
+
 /**
  *     bus_add_device - add device to bus
  *     @dev:   device being added
@@ -407,11 +438,12 @@ int bus_add_device(struct device * dev)
 
        if (bus) {
                down_write(&dev->bus->subsys.rwsem);
-               pr_debug("bus %s: add device %s\n",bus->name,dev->bus_id);
-               list_add_tail(&dev->bus_list,&dev->bus->devices.list);
+               pr_debug("bus %s: add device %s\n", bus->name, dev->bus_id);
+               list_add_tail(&dev->bus_list, &dev->bus->devices.list);
                device_attach(dev);
                up_write(&dev->bus->subsys.rwsem);
-               sysfs_create_link(&bus->devices.kobj,&dev->kobj,dev->bus_id);
+               device_add_attrs(bus, dev);
+               sysfs_create_link(&bus->devices.kobj, &dev->kobj, dev->bus_id);
        }
        return error;
 }
@@ -428,9 +460,10 @@ int bus_add_device(struct device * dev)
 void bus_remove_device(struct device * dev)
 {
        if (dev->bus) {
-               sysfs_remove_link(&dev->bus->devices.kobj,dev->bus_id);
+               sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
+               device_remove_attrs(dev->bus, dev);
                down_write(&dev->bus->subsys.rwsem);
-               pr_debug("bus %s: remove device %s\n",dev->bus->name,dev->bus_id);
+               pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
                device_release_driver(dev);
                list_del_init(&dev->bus_list);
                up_write(&dev->bus->subsys.rwsem);
@@ -438,6 +471,37 @@ void bus_remove_device(struct device * dev)
        }
 }
 
+static int driver_add_attrs(struct bus_type * bus, struct device_driver * drv)
+{
+       int error = 0;
+       int i;
+
+       if (bus->drv_attrs) {
+               for (i = 0; attr_name(bus->drv_attrs[i]); i++) {
+                       error = driver_create_file(drv, &bus->drv_attrs[i]);
+                       if (error)
+                               goto Err;
+               }
+       }
+ Done:
+       return error;
+ Err:
+       while (--i >= 0)
+               driver_remove_file(drv, &bus->drv_attrs[i]);
+       goto Done;
+}
+
+
+static void driver_remove_attrs(struct bus_type * bus, struct device_driver * drv)
+{
+       int i;
+
+       if (bus->drv_attrs) {
+               for (i = 0; attr_name(bus->drv_attrs[i]); i++)
+                       driver_remove_file(drv, &bus->drv_attrs[i]);
+       }
+}
+
 
 /**
  *     bus_add_driver - Add a driver to the bus.
@@ -450,8 +514,8 @@ int bus_add_driver(struct device_driver * drv)
        int error = 0;
 
        if (bus) {
-               pr_debug("bus %s: add driver %s\n",bus->name,drv->name);
-               error = kobject_set_name(&drv->kobj,drv->name);
+               pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
+               error = kobject_set_name(&drv->kobj, drv->name);
                if (error) {
                        put_bus(bus);
                        return error;
@@ -466,6 +530,7 @@ int bus_add_driver(struct device_driver * drv)
                driver_attach(drv);
                up_write(&bus->subsys.rwsem);
 
+               driver_add_attrs(bus, drv);
        }
        return error;
 }
@@ -483,8 +548,9 @@ int bus_add_driver(struct device_driver * drv)
 void bus_remove_driver(struct device_driver * drv)
 {
        if (drv->bus) {
+               driver_remove_attrs(drv->bus, drv);
                down_write(&drv->bus->subsys.rwsem);
-               pr_debug("bus %s: remove driver %s\n",drv->bus->name,drv->name);
+               pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
                driver_detach(drv);
                up_write(&drv->bus->subsys.rwsem);
                kobject_unregister(&drv->kobj);
@@ -526,7 +592,7 @@ int bus_rescan_devices(struct bus_type * bus)
 
 struct bus_type * get_bus(struct bus_type * bus)
 {
-       return bus ? container_of(subsys_get(&bus->subsys),struct bus_type,subsys) : NULL;
+       return bus ? container_of(subsys_get(&bus->subsys), struct bus_type, subsys) : NULL;
 }
 
 void put_bus(struct bus_type * bus)
@@ -541,33 +607,70 @@ void put_bus(struct bus_type * bus)
  *
  *     Call kset_find_obj() to iterate over list of buses to
  *     find a bus by name. Return bus if found.
+ *
+ *     Note that kset_find_obj increments bus' reference count.
  */
 
 struct bus_type * find_bus(char * name)
 {
-       struct kobject * k = kset_find_obj(&bus_subsys.kset,name);
+       struct kobject * k = kset_find_obj(&bus_subsys.kset, name);
        return k ? to_bus(k) : NULL;
 }
 
+
+/**
+ *     bus_add_attrs - Add default attributes for this bus.
+ *     @bus:   Bus that has just been registered.
+ */
+
+static int bus_add_attrs(struct bus_type * bus)
+{
+       int error = 0;
+       int i;
+
+       if (bus->bus_attrs) {
+               for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
+                       if ((error = bus_create_file(bus,&bus->bus_attrs[i])))
+                               goto Err;
+               }
+       }
+ Done:
+       return error;
+ Err:
+       while (--i >= 0)
+               bus_remove_file(bus,&bus->bus_attrs[i]);
+       goto Done;
+}
+
+static void bus_remove_attrs(struct bus_type * bus)
+{
+       int i;
+
+       if (bus->bus_attrs) {
+               for (i = 0; attr_name(bus->bus_attrs[i]); i++)
+                       bus_remove_file(bus,&bus->bus_attrs[i]);
+       }
+}
+
 /**
  *     bus_register - register a bus with the system.
  *     @bus:   bus.
  *
  *     Once we have that, we registered the bus with the kobject
  *     infrastructure, then register the children subsystems it has:
- *     the devices and drivers that belong to the bus. 
+ *     the devices and drivers that belong to the bus.
  */
 int bus_register(struct bus_type * bus)
 {
        int retval;
 
-       retval = kobject_set_name(&bus->subsys.kset.kobj,bus->name);
+       retval = kobject_set_name(&bus->subsys.kset.kobj, bus->name);
        if (retval)
                goto out;
 
-       subsys_set_kset(bus,bus_subsys);
+       subsys_set_kset(bus, bus_subsys);
        retval = subsystem_register(&bus->subsys);
-       if (retval) 
+       if (retval)
                goto out;
 
        kobject_set_name(&bus->devices.kobj, "devices");
@@ -582,8 +685,9 @@ int bus_register(struct bus_type * bus)
        retval = kset_register(&bus->drivers);
        if (retval)
                goto bus_drivers_fail;
+       bus_add_attrs(bus);
 
-       pr_debug("bus type '%s' registered\n",bus->name);
+       pr_debug("bus type '%s' registered\n", bus->name);
        return 0;
 
 bus_drivers_fail:
@@ -596,7 +700,7 @@ out:
 
 
 /**
- *     bus_unregister - remove a bus from the system 
+ *     bus_unregister - remove a bus from the system
  *     @bus:   bus.
  *
  *     Unregister the child subsystems and the bus itself.
@@ -604,7 +708,8 @@ out:
  */
 void bus_unregister(struct bus_type * bus)
 {
-       pr_debug("bus %s: unregistering\n",bus->name);
+       pr_debug("bus %s: unregistering\n", bus->name);
+       bus_remove_attrs(bus);
        kset_unregister(&bus->drivers);
        kset_unregister(&bus->devices);
        subsystem_unregister(&bus->subsys);