Driver core: move the static kobject out of struct driver
[pandora-kernel.git] / drivers / base / bus.c
index 61c6752..aa0c986 100644 (file)
@@ -3,6 +3,8 @@
  *
  * Copyright (c) 2002-3 Patrick Mochel
  * Copyright (c) 2002-3 Open Source Development Labs
+ * Copyright (c) 2007 Greg Kroah-Hartman <gregkh@suse.de>
+ * Copyright (c) 2007 Novell Inc.
  *
  * This file is released under the GPLv2
  *
 #include "power/power.h"
 
 #define to_bus_attr(_attr) container_of(_attr, struct bus_attribute, attr)
-#define to_bus(obj) container_of(obj, struct bus_type, subsys.kobj)
+#define to_bus(obj) container_of(obj, struct bus_type_private, subsys.kobj)
 
 /*
  * sysfs bindings for drivers
  */
 
 #define to_drv_attr(_attr) container_of(_attr, struct driver_attribute, attr)
-#define to_driver(obj) container_of(obj, struct device_driver, kobj)
 
 
 static int __must_check bus_rescan_devices_helper(struct device *dev,
                                                void *data);
 
+static struct bus_type *bus_get(struct bus_type *bus)
+{
+       if (bus) {
+               kset_get(&bus->p->subsys);
+               return bus;
+       }
+       return NULL;
+}
+
+static void bus_put(struct bus_type *bus)
+{
+       if (bus)
+               kset_put(&bus->p->subsys);
+}
+
 static ssize_t
 drv_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 {
        struct driver_attribute * drv_attr = to_drv_attr(attr);
-       struct device_driver * drv = to_driver(kobj);
+       struct driver_private *drv_priv = to_driver(kobj);
        ssize_t ret = -EIO;
 
        if (drv_attr->show)
-               ret = drv_attr->show(drv, buf);
+               ret = drv_attr->show(drv_priv->driver, buf);
        return ret;
 }
 
@@ -47,11 +63,11 @@ drv_attr_store(struct kobject * kobj, struct attribute * attr,
               const char * buf, size_t count)
 {
        struct driver_attribute * drv_attr = to_drv_attr(attr);
-       struct device_driver * drv = to_driver(kobj);
+       struct driver_private *drv_priv = to_driver(kobj);
        ssize_t ret = -EIO;
 
        if (drv_attr->store)
-               ret = drv_attr->store(drv, buf, count);
+               ret = drv_attr->store(drv_priv->driver, buf, count);
        return ret;
 }
 
@@ -60,25 +76,15 @@ static struct sysfs_ops driver_sysfs_ops = {
        .store  = drv_attr_store,
 };
 
-
-static void driver_release(struct kobject * kobj)
+static void driver_release(struct kobject *kobj)
 {
-       /*
-        * Yes this is an empty release function, it is this way because struct
-        * device is always a static object, not a dynamic one.  Yes, this is
-        * not nice and bad, but remember, drivers are code, reference counted
-        * by the module count, not a device, which is really data.  And yes,
-        * in the future I do want to have all drivers be created dynamically,
-        * and am working toward that goal, but it will take a bit longer...
-        *
-        * But do not let this example give _anyone_ the idea that they can
-        * create a release function without any code in it at all, to do that
-        * is almost always wrong.  If you have any questions about this,
-        * please send an email to <greg@kroah.com>
-        */
+       struct driver_private *drv_priv = to_driver(kobj);
+
+       pr_debug("%s: freeing %s\n", __FUNCTION__, kobject_name(kobj));
+       kfree(drv_priv);
 }
 
-static struct kobj_type ktype_driver = {
+static struct kobj_type driver_ktype = {
        .sysfs_ops      = &driver_sysfs_ops,
        .release        = driver_release,
 };
@@ -93,11 +99,11 @@ static ssize_t
 bus_attr_show(struct kobject * kobj, struct attribute * attr, char * buf)
 {
        struct bus_attribute * bus_attr = to_bus_attr(attr);
-       struct bus_type * bus = to_bus(kobj);
+       struct bus_type_private *bus_priv = to_bus(kobj);
        ssize_t ret = 0;
 
        if (bus_attr->show)
-               ret = bus_attr->show(bus, buf);
+               ret = bus_attr->show(bus_priv->bus, buf);
        return ret;
 }
 
@@ -106,11 +112,11 @@ bus_attr_store(struct kobject * kobj, struct attribute * attr,
               const char * buf, size_t count)
 {
        struct bus_attribute * bus_attr = to_bus_attr(attr);
-       struct bus_type * bus = to_bus(kobj);
+       struct bus_type_private *bus_priv = to_bus(kobj);
        ssize_t ret = 0;
 
        if (bus_attr->store)
-               ret = bus_attr->store(bus, buf, count);
+               ret = bus_attr->store(bus_priv->bus, buf, count);
        return ret;
 }
 
@@ -122,9 +128,9 @@ static struct sysfs_ops bus_sysfs_ops = {
 int bus_create_file(struct bus_type * bus, struct bus_attribute * attr)
 {
        int error;
-       if (get_bus(bus)) {
-               error = sysfs_create_file(&bus->subsys.kobj, &attr->attr);
-               put_bus(bus);
+       if (bus_get(bus)) {
+               error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr);
+               bus_put(bus);
        } else
                error = -EINVAL;
        return error;
@@ -132,9 +138,9 @@ 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.kobj, &attr->attr);
-               put_bus(bus);
+       if (bus_get(bus)) {
+               sysfs_remove_file(&bus->p->subsys.kobj, &attr->attr);
+               bus_put(bus);
        }
 }
 
@@ -155,7 +161,7 @@ static struct kset_uevent_ops bus_uevent_ops = {
        .filter = bus_uevent_filter,
 };
 
-static decl_subsys(bus, &bus_ktype, &bus_uevent_ops);
+static struct kset *bus_kset;
 
 
 #ifdef CONFIG_HOTPLUG
@@ -172,7 +178,7 @@ static int driver_helper(struct device *dev, void *data)
 static ssize_t driver_unbind(struct device_driver *drv,
                             const char *buf, size_t count)
 {
-       struct bus_type *bus = get_bus(drv->bus);
+       struct bus_type *bus = bus_get(drv->bus);
        struct device *dev;
        int err = -ENODEV;
 
@@ -186,7 +192,7 @@ static ssize_t driver_unbind(struct device_driver *drv,
                err = count;
        }
        put_device(dev);
-       put_bus(bus);
+       bus_put(bus);
        return err;
 }
 static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
@@ -199,7 +205,7 @@ static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
 static ssize_t driver_bind(struct device_driver *drv,
                           const char *buf, size_t count)
 {
-       struct bus_type *bus = get_bus(drv->bus);
+       struct bus_type *bus = bus_get(drv->bus);
        struct device *dev;
        int err = -ENODEV;
 
@@ -219,23 +225,23 @@ static ssize_t driver_bind(struct device_driver *drv,
                        err = -ENODEV;
        }
        put_device(dev);
-       put_bus(bus);
+       bus_put(bus);
        return err;
 }
 static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
 
 static ssize_t show_drivers_autoprobe(struct bus_type *bus, char *buf)
 {
-       return sprintf(buf, "%d\n", bus->drivers_autoprobe);
+       return sprintf(buf, "%d\n", bus->p->drivers_autoprobe);
 }
 
 static ssize_t store_drivers_autoprobe(struct bus_type *bus,
                                       const char *buf, size_t count)
 {
        if (buf[0] == '0')
-               bus->drivers_autoprobe = 0;
+               bus->p->drivers_autoprobe = 0;
        else
-               bus->drivers_autoprobe = 1;
+               bus->p->drivers_autoprobe = 1;
        return count;
 }
 
@@ -289,7 +295,7 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start,
        if (!bus)
                return -EINVAL;
 
-       klist_iter_init_node(&bus->klist_devices, &i,
+       klist_iter_init_node(&bus->p->klist_devices, &i,
                             (start ? &start->knode_bus : NULL));
        while ((dev = next_device(&i)) && !error)
                error = fn(dev, data);
@@ -322,7 +328,7 @@ struct device * bus_find_device(struct bus_type *bus,
        if (!bus)
                return NULL;
 
-       klist_iter_init_node(&bus->klist_devices, &i,
+       klist_iter_init_node(&bus->p->klist_devices, &i,
                             (start ? &start->knode_bus : NULL));
        while ((dev = next_device(&i)))
                if (match(dev, data) && get_device(dev))
@@ -335,7 +341,13 @@ struct device * bus_find_device(struct bus_type *bus,
 static struct device_driver * next_driver(struct klist_iter * i)
 {
        struct klist_node * n = klist_next(i);
-       return n ? container_of(n, struct device_driver, knode_bus) : NULL;
+       struct driver_private *drv_priv;
+
+       if (n) {
+               drv_priv = container_of(n, struct driver_private, knode_bus);
+               return drv_priv->driver;
+       }
+       return NULL;
 }
 
 /**
@@ -368,8 +380,8 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
        if (!bus)
                return -EINVAL;
 
-       klist_iter_init_node(&bus->klist_drivers, &i,
-                            start ? &start->knode_bus : NULL);
+       klist_iter_init_node(&bus->p->klist_drivers, &i,
+                            start ? &start->p->knode_bus : NULL);
        while ((drv = next_driver(&i)) && !error)
                error = fn(drv, data);
        klist_iter_exit(&i);
@@ -409,7 +421,7 @@ static void device_remove_attrs(struct bus_type * bus, struct device * dev)
 static int make_deprecated_bus_links(struct device *dev)
 {
        return sysfs_create_link(&dev->kobj,
-                                &dev->bus->subsys.kobj, "bus");
+                                &dev->bus->p->subsys.kobj, "bus");
 }
 
 static void remove_deprecated_bus_links(struct device *dev)
@@ -430,7 +442,7 @@ static inline void remove_deprecated_bus_links(struct device *dev) { }
  */
 int bus_add_device(struct device * dev)
 {
-       struct bus_type * bus = get_bus(dev->bus);
+       struct bus_type * bus = bus_get(dev->bus);
        int error = 0;
 
        if (bus) {
@@ -438,12 +450,12 @@ int bus_add_device(struct device * dev)
                error = device_add_attrs(bus, dev);
                if (error)
                        goto out_put;
-               error = sysfs_create_link(&bus->devices.kobj,
+               error = sysfs_create_link(&bus->p->devices_kset->kobj,
                                                &dev->kobj, dev->bus_id);
                if (error)
                        goto out_id;
                error = sysfs_create_link(&dev->kobj,
-                               &dev->bus->subsys.kobj, "subsystem");
+                               &dev->bus->p->subsys.kobj, "subsystem");
                if (error)
                        goto out_subsys;
                error = make_deprecated_bus_links(dev);
@@ -455,11 +467,11 @@ int bus_add_device(struct device * dev)
 out_deprecated:
        sysfs_remove_link(&dev->kobj, "subsystem");
 out_subsys:
-       sysfs_remove_link(&bus->devices.kobj, dev->bus_id);
+       sysfs_remove_link(&bus->p->devices_kset->kobj, dev->bus_id);
 out_id:
        device_remove_attrs(bus, dev);
 out_put:
-       put_bus(dev->bus);
+       bus_put(dev->bus);
        return error;
 }
 
@@ -477,11 +489,11 @@ void bus_attach_device(struct device * dev)
 
        if (bus) {
                dev->is_registered = 1;
-               if (bus->drivers_autoprobe)
+               if (bus->p->drivers_autoprobe)
                        ret = device_attach(dev);
                WARN_ON(ret < 0);
                if (ret >= 0)
-                       klist_add_tail(&dev->knode_bus, &bus->klist_devices);
+                       klist_add_tail(&dev->knode_bus, &bus->p->klist_devices);
                else
                        dev->is_registered = 0;
        }
@@ -501,7 +513,7 @@ void bus_remove_device(struct device * dev)
        if (dev->bus) {
                sysfs_remove_link(&dev->kobj, "subsystem");
                remove_deprecated_bus_links(dev);
-               sysfs_remove_link(&dev->bus->devices.kobj, dev->bus_id);
+               sysfs_remove_link(&dev->bus->p->devices_kset->kobj, dev->bus_id);
                device_remove_attrs(dev->bus, dev);
                if (dev->is_registered) {
                        dev->is_registered = 0;
@@ -509,7 +521,7 @@ void bus_remove_device(struct device * dev)
                }
                pr_debug("bus %s: remove device %s\n", dev->bus->name, dev->bus_id);
                device_release_driver(dev);
-               put_bus(dev->bus);
+               bus_put(dev->bus);
        }
 }
 
@@ -568,32 +580,29 @@ static void remove_bind_files(struct device_driver *drv)
        driver_remove_file(drv, &driver_attr_unbind);
 }
 
+static BUS_ATTR(drivers_probe, S_IWUSR, NULL, store_drivers_probe);
+static BUS_ATTR(drivers_autoprobe, S_IWUSR | S_IRUGO,
+               show_drivers_autoprobe, store_drivers_autoprobe);
+
 static int add_probe_files(struct bus_type *bus)
 {
        int retval;
 
-       bus->drivers_probe_attr.attr.name = "drivers_probe";
-       bus->drivers_probe_attr.attr.mode = S_IWUSR;
-       bus->drivers_probe_attr.store = store_drivers_probe;
-       retval = bus_create_file(bus, &bus->drivers_probe_attr);
+       retval = bus_create_file(bus, &bus_attr_drivers_probe);
        if (retval)
                goto out;
 
-       bus->drivers_autoprobe_attr.attr.name = "drivers_autoprobe";
-       bus->drivers_autoprobe_attr.attr.mode = S_IWUSR | S_IRUGO;
-       bus->drivers_autoprobe_attr.show = show_drivers_autoprobe;
-       bus->drivers_autoprobe_attr.store = store_drivers_autoprobe;
-       retval = bus_create_file(bus, &bus->drivers_autoprobe_attr);
+       retval = bus_create_file(bus, &bus_attr_drivers_autoprobe);
        if (retval)
-               bus_remove_file(bus, &bus->drivers_probe_attr);
+               bus_remove_file(bus, &bus_attr_drivers_probe);
 out:
        return retval;
 }
 
 static void remove_probe_files(struct bus_type *bus)
 {
-       bus_remove_file(bus, &bus->drivers_autoprobe_attr);
-       bus_remove_file(bus, &bus->drivers_probe_attr);
+       bus_remove_file(bus, &bus_attr_drivers_autoprobe);
+       bus_remove_file(bus, &bus_attr_drivers_probe);
 }
 #else
 static inline int add_bind_files(struct device_driver *drv) { return 0; }
@@ -602,6 +611,17 @@ static inline int add_probe_files(struct bus_type *bus) { return 0; }
 static inline void remove_probe_files(struct bus_type *bus) {}
 #endif
 
+static ssize_t driver_uevent_store(struct device_driver *drv,
+                                  const char *buf, size_t count)
+{
+       enum kobject_action action;
+
+       if (kobject_action_type(buf, count, &action) == 0)
+               kobject_uevent(&drv->p->kobj, action);
+       return count;
+}
+static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);
+
 /**
  *     bus_add_driver - Add a driver to the bus.
  *     @drv:   driver.
@@ -609,29 +629,45 @@ static inline void remove_probe_files(struct bus_type *bus) {}
  */
 int bus_add_driver(struct device_driver *drv)
 {
-       struct bus_type * bus = get_bus(drv->bus);
+       struct bus_type *bus;
+       struct driver_private *priv;
        int error = 0;
 
+       bus = bus_get(drv->bus);
        if (!bus)
                return -EINVAL;
 
        pr_debug("bus %s: add driver %s\n", bus->name, drv->name);
-       error = kobject_set_name(&drv->kobj, "%s", drv->name);
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       error = kobject_set_name(&priv->kobj, "%s", drv->name);
        if (error)
                goto out_put_bus;
-       drv->kobj.kset = &bus->drivers;
-       error = kobject_register(&drv->kobj);
+       priv->kobj.kset = bus->p->drivers_kset;
+       priv->kobj.ktype = &driver_ktype;
+       klist_init(&priv->klist_devices, NULL, NULL);
+       priv->driver = drv;
+       drv->p = priv;
+       error = kobject_register(&priv->kobj);
        if (error)
                goto out_put_bus;
 
-       if (drv->bus->drivers_autoprobe) {
+       if (drv->bus->p->drivers_autoprobe) {
                error = driver_attach(drv);
                if (error)
                        goto out_unregister;
        }
-       klist_add_tail(&drv->knode_bus, &bus->klist_drivers);
+       klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);
        module_add_driver(drv->owner, drv);
 
+       error = driver_create_file(drv, &driver_attr_uevent);
+       if (error) {
+               printk(KERN_ERR "%s: uevent attr (%s) failed\n",
+                       __FUNCTION__, drv->name);
+       }
        error = driver_add_attrs(bus, drv);
        if (error) {
                /* How the hell do we get out of this pickle? Give up */
@@ -647,9 +683,9 @@ int bus_add_driver(struct device_driver *drv)
 
        return error;
 out_unregister:
-       kobject_unregister(&drv->kobj);
+       kobject_unregister(&priv->kobj);
 out_put_bus:
-       put_bus(bus);
+       bus_put(bus);
        return error;
 }
 
@@ -669,12 +705,13 @@ void bus_remove_driver(struct device_driver * drv)
 
        remove_bind_files(drv);
        driver_remove_attrs(drv->bus, drv);
-       klist_remove(&drv->knode_bus);
+       driver_remove_file(drv, &driver_attr_uevent);
+       klist_remove(&drv->p->knode_bus);
        pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
        driver_detach(drv);
        module_remove_driver(drv);
-       kobject_unregister(&drv->kobj);
-       put_bus(drv->bus);
+       kobject_unregister(&drv->p->kobj);
+       bus_put(drv->bus);
 }
 
 
@@ -729,18 +766,6 @@ int device_reprobe(struct device *dev)
 }
 EXPORT_SYMBOL_GPL(device_reprobe);
 
-struct bus_type *get_bus(struct bus_type *bus)
-{
-       return bus ? container_of(subsys_get(&bus->subsys),
-                               struct bus_type, subsys) : NULL;
-}
-
-void put_bus(struct bus_type * bus)
-{
-       subsys_put(&bus->subsys);
-}
-
-
 /**
  *     find_bus - locate bus by name.
  *     @name:  name of bus.
@@ -753,7 +778,7 @@ void put_bus(struct bus_type * bus)
 #if 0
 struct bus_type * find_bus(char * name)
 {
-       struct kobject * k = kset_find_obj(&bus_subsys.kset, name);
+       struct kobject * k = kset_find_obj(bus_kset, name);
        return k ? to_bus(k) : NULL;
 }
 #endif  /*  0  */
@@ -808,6 +833,17 @@ static void klist_devices_put(struct klist_node *n)
        put_device(dev);
 }
 
+static ssize_t bus_uevent_store(struct bus_type *bus,
+                               const char *buf, size_t count)
+{
+       enum kobject_action action;
+
+       if (kobject_action_type(buf, count, &action) == 0)
+               kobject_uevent(&bus->p->subsys.kobj, action);
+       return count;
+}
+static BUS_ATTR(uevent, S_IWUSR, NULL, bus_uevent_store);
+
 /**
  *     bus_register - register a bus with the system.
  *     @bus:   bus.
@@ -819,35 +855,50 @@ static void klist_devices_put(struct klist_node *n)
 int bus_register(struct bus_type * bus)
 {
        int retval;
+       struct bus_type_private *priv;
+
+       priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->bus = bus;
+       bus->p = priv;
 
-       BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);
+       BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
 
-       retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name);
+       retval = kobject_set_name(&priv->subsys.kobj, "%s", bus->name);
        if (retval)
                goto out;
 
-       subsys_set_kset(bus, bus_subsys);
-       retval = subsystem_register(&bus->subsys);
+       priv->subsys.kobj.kset = bus_kset;
+       priv->subsys.kobj.ktype = &bus_ktype;
+       priv->drivers_autoprobe = 1;
+
+       retval = kset_register(&priv->subsys);
        if (retval)
                goto out;
 
-       kobject_set_name(&bus->devices.kobj, "devices");
-       bus->devices.kobj.parent = &bus->subsys.kobj;
-       retval = kset_register(&bus->devices);
+       retval = bus_create_file(bus, &bus_attr_uevent);
        if (retval)
+               goto bus_uevent_fail;
+
+       priv->devices_kset = kset_create_and_add("devices", NULL,
+                                                &priv->subsys.kobj);
+       if (!priv->devices_kset) {
+               retval = -ENOMEM;
                goto bus_devices_fail;
+       }
 
-       kobject_set_name(&bus->drivers.kobj, "drivers");
-       bus->drivers.kobj.parent = &bus->subsys.kobj;
-       bus->drivers.ktype = &ktype_driver;
-       retval = kset_register(&bus->drivers);
-       if (retval)
+       priv->drivers_kset = kset_create_and_add("drivers", NULL,
+                                                &priv->subsys.kobj);
+       if (!priv->drivers_kset) {
+               retval = -ENOMEM;
                goto bus_drivers_fail;
+       }
 
-       klist_init(&bus->klist_devices, klist_devices_get, klist_devices_put);
-       klist_init(&bus->klist_drivers, NULL, NULL);
+       klist_init(&priv->klist_devices, klist_devices_get, klist_devices_put);
+       klist_init(&priv->klist_drivers, NULL, NULL);
 
-       bus->drivers_autoprobe = 1;
        retval = add_probe_files(bus);
        if (retval)
                goto bus_probe_files_fail;
@@ -862,11 +913,14 @@ int bus_register(struct bus_type * bus)
 bus_attrs_fail:
        remove_probe_files(bus);
 bus_probe_files_fail:
-       kset_unregister(&bus->drivers);
+       kset_unregister(bus->p->drivers_kset);
 bus_drivers_fail:
-       kset_unregister(&bus->devices);
+       kset_unregister(bus->p->devices_kset);
 bus_devices_fail:
-       subsystem_unregister(&bus->subsys);
+       bus_remove_file(bus, &bus_attr_uevent);
+bus_uevent_fail:
+       kset_unregister(&bus->p->subsys);
+       kfree(bus->p);
 out:
        return retval;
 }
@@ -876,33 +930,50 @@ out:
  *     @bus:   bus.
  *
  *     Unregister the child subsystems and the bus itself.
- *     Finally, we call put_bus() to release the refcount
+ *     Finally, we call bus_put() to release the refcount
  */
 void bus_unregister(struct bus_type * bus)
 {
        pr_debug("bus %s: unregistering\n", bus->name);
        bus_remove_attrs(bus);
        remove_probe_files(bus);
-       kset_unregister(&bus->drivers);
-       kset_unregister(&bus->devices);
-       subsystem_unregister(&bus->subsys);
+       kset_unregister(bus->p->drivers_kset);
+       kset_unregister(bus->p->devices_kset);
+       bus_remove_file(bus, &bus_attr_uevent);
+       kset_unregister(&bus->p->subsys);
+       kfree(bus->p);
 }
 
 int bus_register_notifier(struct bus_type *bus, struct notifier_block *nb)
 {
-       return blocking_notifier_chain_register(&bus->bus_notifier, nb);
+       return blocking_notifier_chain_register(&bus->p->bus_notifier, nb);
 }
 EXPORT_SYMBOL_GPL(bus_register_notifier);
 
 int bus_unregister_notifier(struct bus_type *bus, struct notifier_block *nb)
 {
-       return blocking_notifier_chain_unregister(&bus->bus_notifier, nb);
+       return blocking_notifier_chain_unregister(&bus->p->bus_notifier, nb);
 }
 EXPORT_SYMBOL_GPL(bus_unregister_notifier);
 
+struct kset *bus_get_kset(struct bus_type *bus)
+{
+       return &bus->p->subsys;
+}
+EXPORT_SYMBOL_GPL(bus_get_kset);
+
+struct klist *bus_get_device_klist(struct bus_type *bus)
+{
+       return &bus->p->klist_devices;
+}
+EXPORT_SYMBOL_GPL(bus_get_device_klist);
+
 int __init buses_init(void)
 {
-       return subsystem_register(&bus_subsys);
+       bus_kset = kset_create_and_add("bus", &bus_uevent_ops, NULL);
+       if (!bus_kset)
+               return -ENOMEM;
+       return 0;
 }