*
* 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;
}
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;
}
.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,
};
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;
}
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;
}
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;
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);
}
}
-static struct kobj_type ktype_bus = {
+static struct kobj_type bus_ktype = {
.sysfs_ops = &bus_sysfs_ops,
+};
+
+static int bus_uevent_filter(struct kset *kset, struct kobject *kobj)
+{
+ struct kobj_type *ktype = get_ktype(kobj);
+
+ if (ktype == &bus_ktype)
+ return 1;
+ return 0;
+}
+static struct kset_uevent_ops bus_uevent_ops = {
+ .filter = bus_uevent_filter,
};
-static decl_subsys(bus, &ktype_bus, NULL);
+static struct kset *bus_kset;
#ifdef CONFIG_HOTPLUG
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;
err = count;
}
put_device(dev);
- put_bus(bus);
+ bus_put(bus);
return err;
}
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;
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;
}
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);
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))
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;
}
/**
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);
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)
*/
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) {
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);
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;
}
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;
}
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;
}
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);
}
}
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.attr.owner = bus->owner;
- 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.attr.owner = bus->owner;
- 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; }
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.
*/
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;
- if ((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 */
return error;
out_unregister:
- kobject_unregister(&drv->kobj);
+ kobject_unregister(&priv->kobj);
out_put_bus:
- put_bus(bus);
+ bus_put(bus);
return error;
}
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);
}
}
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.
#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 */
if (bus->bus_attrs) {
for (i = 0; attr_name(bus->bus_attrs[i]); i++) {
- if ((error = bus_create_file(bus,&bus->bus_attrs[i])))
+ error = bus_create_file(bus,&bus->bus_attrs[i]);
+ if (error)
goto Err;
}
}
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.
int bus_register(struct bus_type * bus)
{
int retval;
+ struct bus_type_private *priv;
- BLOCKING_INIT_NOTIFIER_HEAD(&bus->bus_notifier);
+ priv = kzalloc(sizeof(struct bus_type_private), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
- retval = kobject_set_name(&bus->subsys.kobj, "%s", bus->name);
+ priv->bus = bus;
+ bus->p = priv;
+
+ BLOCKING_INIT_NOTIFIER_HEAD(&priv->bus_notifier);
+
+ 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;
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;
}
* @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;
}