diff options
| -rw-r--r-- | drivers/base/base.h | 8 | ||||
| -rw-r--r-- | drivers/base/bus.c | 71 | ||||
| -rw-r--r-- | drivers/base/dd.c | 24 | ||||
| -rw-r--r-- | drivers/base/driver.c | 40 | ||||
| -rw-r--r-- | drivers/base/module.c | 12 | ||||
| -rw-r--r-- | drivers/base/platform.c | 2 | ||||
| -rw-r--r-- | include/linux/device.h | 16 | 
7 files changed, 99 insertions, 74 deletions
diff --git a/drivers/base/base.h b/drivers/base/base.h index 05472360f6a..3b0f395552d 100644 --- a/drivers/base/base.h +++ b/drivers/base/base.h @@ -27,6 +27,14 @@ struct bus_type_private {  	struct bus_type *bus;  }; +struct driver_private { +	struct kobject kobj; +	struct klist klist_devices; +	struct klist_node knode_bus; +	struct module_kobject *mkobj; +	struct device_driver *driver; +}; +#define to_driver(obj) container_of(obj, struct driver_private, kobj)  /* initialisation functions */  extern int devices_init(void); diff --git a/drivers/base/bus.c b/drivers/base/bus.c index 04d3850ff4b..aa0c986c323 100644 --- a/drivers/base/bus.c +++ b/drivers/base/bus.c @@ -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   * @@ -24,7 +26,6 @@   */  #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, @@ -49,11 +50,11 @@ 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;  } @@ -62,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;  } @@ -75,22 +76,12 @@ 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 driver_ktype = { @@ -350,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;  }  /** @@ -384,7 +381,7 @@ int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,  		return -EINVAL;  	klist_iter_init_node(&bus->p->klist_drivers, &i, -			     start ? &start->knode_bus : NULL); +			     start ? &start->p->knode_bus : NULL);  	while ((drv = next_driver(&i)) && !error)  		error = fn(drv, data);  	klist_iter_exit(&i); @@ -620,7 +617,7 @@ static ssize_t driver_uevent_store(struct device_driver *drv,  	enum kobject_action action;  	if (kobject_action_type(buf, count, &action) == 0) -		kobject_uevent(&drv->kobj, action); +		kobject_uevent(&drv->p->kobj, action);  	return count;  }  static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store); @@ -632,19 +629,29 @@ static DRIVER_ATTR(uevent, S_IWUSR, NULL, driver_uevent_store);   */  int bus_add_driver(struct device_driver *drv)  { -	struct bus_type * bus = bus_get(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->p->drivers_kset; -	drv->kobj.ktype = &driver_ktype; -	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; @@ -653,7 +660,7 @@ int bus_add_driver(struct device_driver *drv)  		if (error)  			goto out_unregister;  	} -	klist_add_tail(&drv->knode_bus, &bus->p->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); @@ -676,7 +683,7 @@ int bus_add_driver(struct device_driver *drv)  	return error;  out_unregister: -	kobject_unregister(&drv->kobj); +	kobject_unregister(&priv->kobj);  out_put_bus:  	bus_put(bus);  	return error; @@ -699,11 +706,11 @@ void bus_remove_driver(struct device_driver * drv)  	remove_bind_files(drv);  	driver_remove_attrs(drv->bus, drv);  	driver_remove_file(drv, &driver_attr_uevent); -	klist_remove(&drv->knode_bus); +	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); +	kobject_unregister(&drv->p->kobj);  	bus_put(drv->bus);  } diff --git a/drivers/base/dd.c b/drivers/base/dd.c index 7bf0e674c97..87a348ce818 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c @@ -11,6 +11,8 @@   *   *	Copyright (c) 2002-5 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   */ @@ -23,8 +25,6 @@  #include "base.h"  #include "power/power.h" -#define to_drv(node) container_of(node, struct device_driver, kobj.entry) -  static void driver_bound(struct device *dev)  { @@ -41,20 +41,20 @@ static void driver_bound(struct device *dev)  		blocking_notifier_call_chain(&dev->bus->p->bus_notifier,  					     BUS_NOTIFY_BOUND_DRIVER, dev); -	klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); +	klist_add_tail(&dev->knode_driver, &dev->driver->p->klist_devices);  }  static int driver_sysfs_add(struct device *dev)  {  	int ret; -	ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, +	ret = sysfs_create_link(&dev->driver->p->kobj, &dev->kobj,  			  kobject_name(&dev->kobj));  	if (ret == 0) { -		ret = sysfs_create_link(&dev->kobj, &dev->driver->kobj, +		ret = sysfs_create_link(&dev->kobj, &dev->driver->p->kobj,  					"driver");  		if (ret) -			sysfs_remove_link(&dev->driver->kobj, +			sysfs_remove_link(&dev->driver->p->kobj,  					kobject_name(&dev->kobj));  	}  	return ret; @@ -65,7 +65,7 @@ static void driver_sysfs_remove(struct device *dev)  	struct device_driver *drv = dev->driver;  	if (drv) { -		sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); +		sysfs_remove_link(&drv->p->kobj, kobject_name(&dev->kobj));  		sysfs_remove_link(&dev->kobj, "driver");  	}  } @@ -339,15 +339,15 @@ void driver_detach(struct device_driver * drv)  	struct device * dev;  	for (;;) { -		spin_lock(&drv->klist_devices.k_lock); -		if (list_empty(&drv->klist_devices.k_list)) { -			spin_unlock(&drv->klist_devices.k_lock); +		spin_lock(&drv->p->klist_devices.k_lock); +		if (list_empty(&drv->p->klist_devices.k_list)) { +			spin_unlock(&drv->p->klist_devices.k_lock);  			break;  		} -		dev = list_entry(drv->klist_devices.k_list.prev, +		dev = list_entry(drv->p->klist_devices.k_list.prev,  				struct device, knode_driver.n_node);  		get_device(dev); -		spin_unlock(&drv->klist_devices.k_lock); +		spin_unlock(&drv->p->klist_devices.k_lock);  		if (dev->parent)	/* Needed for USB */  			down(&dev->parent->sem); diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 633ae1d70e1..5aacff208f2 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -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   * @@ -15,7 +17,6 @@  #include "base.h"  #define to_dev(node) container_of(node, struct device, driver_list) -#define to_drv(obj) container_of(obj, struct device_driver, kobj)  static struct device * next_device(struct klist_iter * i) @@ -44,7 +45,7 @@ int driver_for_each_device(struct device_driver * drv, struct device * start,  	if (!drv)  		return -EINVAL; -	klist_iter_init_node(&drv->klist_devices, &i, +	klist_iter_init_node(&drv->p->klist_devices, &i,  			     start ? &start->knode_driver : NULL);  	while ((dev = next_device(&i)) && !error)  		error = fn(dev, data); @@ -80,7 +81,7 @@ struct device * driver_find_device(struct device_driver *drv,  	if (!drv)  		return NULL; -	klist_iter_init_node(&drv->klist_devices, &i, +	klist_iter_init_node(&drv->p->klist_devices, &i,  			     (start ? &start->knode_driver : NULL));  	while ((dev = next_device(&i)))  		if (match(dev, data) && get_device(dev)) @@ -100,7 +101,7 @@ int driver_create_file(struct device_driver * drv, struct driver_attribute * att  {  	int error;  	if (get_driver(drv)) { -		error = sysfs_create_file(&drv->kobj, &attr->attr); +		error = sysfs_create_file(&drv->p->kobj, &attr->attr);  		put_driver(drv);  	} else  		error = -EINVAL; @@ -117,7 +118,7 @@ int driver_create_file(struct device_driver * drv, struct driver_attribute * att  void driver_remove_file(struct device_driver * drv, struct driver_attribute * attr)  {  	if (get_driver(drv)) { -		sysfs_remove_file(&drv->kobj, &attr->attr); +		sysfs_remove_file(&drv->p->kobj, &attr->attr);  		put_driver(drv);  	}  } @@ -143,7 +144,7 @@ int driver_add_kobj(struct device_driver *drv, struct kobject *kobj,  	if (!name)  		return -ENOMEM; -	return kobject_add_ng(kobj, &drv->kobj, "%s", name); +	return kobject_add_ng(kobj, &drv->p->kobj, "%s", name);  }  EXPORT_SYMBOL_GPL(driver_add_kobj); @@ -153,7 +154,15 @@ EXPORT_SYMBOL_GPL(driver_add_kobj);   */  struct device_driver * get_driver(struct device_driver * drv)  { -	return drv ? to_drv(kobject_get(&drv->kobj)) : NULL; +	if (drv) { +		struct driver_private *priv; +		struct kobject *kobj; + +		kobj = kobject_get(&drv->p->kobj); +		priv = to_driver(kobj); +		return priv->driver; +	} +	return NULL;  } @@ -163,7 +172,7 @@ struct device_driver * get_driver(struct device_driver * drv)   */  void put_driver(struct device_driver * drv)  { -	kobject_put(&drv->kobj); +	kobject_put(&drv->p->kobj);  }  static int driver_add_groups(struct device_driver *drv, @@ -174,10 +183,10 @@ static int driver_add_groups(struct device_driver *drv,  	if (groups) {  		for (i = 0; groups[i]; i++) { -			error = sysfs_create_group(&drv->kobj, groups[i]); +			error = sysfs_create_group(&drv->p->kobj, groups[i]);  			if (error) {  				while (--i >= 0) -					sysfs_remove_group(&drv->kobj, +					sysfs_remove_group(&drv->p->kobj,  							   groups[i]);  				break;  			} @@ -193,7 +202,7 @@ static void driver_remove_groups(struct device_driver *drv,  	if (groups)  		for (i = 0; groups[i]; i++) -			sysfs_remove_group(&drv->kobj, groups[i]); +			sysfs_remove_group(&drv->p->kobj, groups[i]);  } @@ -214,7 +223,6 @@ int driver_register(struct device_driver * drv)  	    (drv->bus->shutdown && drv->shutdown)) {  		printk(KERN_WARNING "Driver '%s' needs updating - please use bus_type methods\n", drv->name);  	} -	klist_init(&drv->klist_devices, NULL, NULL);  	ret = bus_add_driver(drv);  	if (ret)  		return ret; @@ -250,8 +258,12 @@ void driver_unregister(struct device_driver * drv)  struct device_driver *driver_find(const char *name, struct bus_type *bus)  {  	struct kobject *k = kset_find_obj(bus->p->drivers_kset, name); -	if (k) -		return to_drv(k); +	struct driver_private *priv; + +	if (k) { +		priv = to_driver(k); +		return priv->driver; +	}  	return NULL;  } diff --git a/drivers/base/module.c b/drivers/base/module.c index cad07be5de1..103be9cacb0 100644 --- a/drivers/base/module.c +++ b/drivers/base/module.c @@ -50,7 +50,7 @@ void module_add_driver(struct module *mod, struct device_driver *drv)  		if (mkobj) {  			mk = container_of(mkobj, struct module_kobject, kobj);  			/* remember our module structure */ -			drv->mkobj = mk; +			drv->p->mkobj = mk;  			/* kset_find_obj took a reference */  			kobject_put(mkobj);  		} @@ -60,11 +60,11 @@ void module_add_driver(struct module *mod, struct device_driver *drv)  		return;  	/* Don't check return codes; these calls are idempotent */ -	no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module"); +	no_warn = sysfs_create_link(&drv->p->kobj, &mk->kobj, "module");  	driver_name = make_driver_name(drv);  	if (driver_name) {  		module_create_drivers_dir(mk); -		no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj, +		no_warn = sysfs_create_link(mk->drivers_dir, &drv->p->kobj,  					    driver_name);  		kfree(driver_name);  	} @@ -78,12 +78,12 @@ void module_remove_driver(struct device_driver *drv)  	if (!drv)  		return; -	sysfs_remove_link(&drv->kobj, "module"); +	sysfs_remove_link(&drv->p->kobj, "module");  	if (drv->owner)  		mk = &drv->owner->mkobj; -	else if (drv->mkobj) -		mk = drv->mkobj; +	else if (drv->p->mkobj) +		mk = drv->p->mkobj;  	if (mk && mk->drivers_dir) {  		driver_name = make_driver_name(drv);  		if (driver_name) { diff --git a/drivers/base/platform.c b/drivers/base/platform.c index d56a05f94f6..bdd59e8358f 100644 --- a/drivers/base/platform.c +++ b/drivers/base/platform.c @@ -499,7 +499,7 @@ int __init_or_module platform_driver_probe(struct platform_driver *drv,  	 */  	spin_lock(&platform_bus_type.p->klist_drivers.k_lock);  	drv->probe = NULL; -	if (code == 0 && list_empty(&drv->driver.klist_devices.k_list)) +	if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))  		retval = -ENODEV;  	drv->driver.probe = platform_drv_probe_fail;  	spin_unlock(&platform_bus_type.p->klist_drivers.k_lock); diff --git a/include/linux/device.h b/include/linux/device.h index 721ee318d57..92ba3a87462 100644 --- a/include/linux/device.h +++ b/include/linux/device.h @@ -32,6 +32,7 @@  struct device;  struct device_driver; +struct driver_private;  struct class;  struct class_device;  struct bus_type; @@ -113,16 +114,11 @@ extern struct kset *bus_get_kset(struct bus_type *bus);  extern struct klist *bus_get_device_klist(struct bus_type *bus);  struct device_driver { -	const char		* name; -	struct bus_type		* bus; - -	struct kobject		kobj; -	struct klist		klist_devices; -	struct klist_node	knode_bus; +	const char		*name; +	struct bus_type		*bus; -	struct module		* owner; -	const char 		* mod_name;	/* used for built-in modules */ -	struct module_kobject	* mkobj; +	struct module		*owner; +	const char 		*mod_name;	/* used for built-in modules */  	int	(*probe)	(struct device * dev);  	int	(*remove)	(struct device * dev); @@ -130,6 +126,8 @@ struct device_driver {  	int	(*suspend)	(struct device * dev, pm_message_t state);  	int	(*resume)	(struct device * dev);  	struct attribute_group **groups; + +	struct driver_private *p;  };  |