diff options
Diffstat (limited to 'drivers/base/driver.c')
| -rw-r--r-- | drivers/base/driver.c | 104 | 
1 files changed, 18 insertions, 86 deletions
diff --git a/drivers/base/driver.c b/drivers/base/driver.c index b631f7c5945..9e29943e56c 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -15,6 +15,7 @@  #include <linux/errno.h>  #include <linux/slab.h>  #include <linux/string.h> +#include <linux/sysfs.h>  #include "base.h"  static struct device *next_device(struct klist_iter *i) @@ -80,7 +81,7 @@ struct device *driver_find_device(struct device_driver *drv,  	struct klist_iter i;  	struct device *dev; -	if (!drv) +	if (!drv || !drv->p)  		return NULL;  	klist_iter_init_node(&drv->p->klist_devices, &i, @@ -123,92 +124,16 @@ void driver_remove_file(struct device_driver *drv,  }  EXPORT_SYMBOL_GPL(driver_remove_file); -/** - * driver_add_kobj - add a kobject below the specified driver - * @drv: requesting device driver - * @kobj: kobject to add below this driver - * @fmt: format string that names the kobject - * - * You really don't want to do this, this is only here due to one looney - * iseries driver, go poke those developers if you are annoyed about - * this... - */ -int driver_add_kobj(struct device_driver *drv, struct kobject *kobj, -		    const char *fmt, ...) +int driver_add_groups(struct device_driver *drv, +		      const struct attribute_group **groups)  { -	va_list args; -	char *name; -	int ret; - -	va_start(args, fmt); -	name = kvasprintf(GFP_KERNEL, fmt, args); -	va_end(args); - -	if (!name) -		return -ENOMEM; - -	ret = kobject_add(kobj, &drv->p->kobj, "%s", name); -	kfree(name); -	return ret; +	return sysfs_create_groups(&drv->p->kobj, groups);  } -EXPORT_SYMBOL_GPL(driver_add_kobj); -/** - * get_driver - increment driver reference count. - * @drv: driver. - */ -struct device_driver *get_driver(struct device_driver *drv) +void driver_remove_groups(struct device_driver *drv, +			  const struct attribute_group **groups)  { -	if (drv) { -		struct driver_private *priv; -		struct kobject *kobj; - -		kobj = kobject_get(&drv->p->kobj); -		priv = to_driver(kobj); -		return priv->driver; -	} -	return NULL; -} -EXPORT_SYMBOL_GPL(get_driver); - -/** - * put_driver - decrement driver's refcount. - * @drv: driver. - */ -void put_driver(struct device_driver *drv) -{ -	kobject_put(&drv->p->kobj); -} -EXPORT_SYMBOL_GPL(put_driver); - -static int driver_add_groups(struct device_driver *drv, -			     const struct attribute_group **groups) -{ -	int error = 0; -	int i; - -	if (groups) { -		for (i = 0; groups[i]; i++) { -			error = sysfs_create_group(&drv->p->kobj, groups[i]); -			if (error) { -				while (--i >= 0) -					sysfs_remove_group(&drv->p->kobj, -							   groups[i]); -				break; -			} -		} -	} -	return error; -} - -static void driver_remove_groups(struct device_driver *drv, -				 const struct attribute_group **groups) -{ -	int i; - -	if (groups) -		for (i = 0; groups[i]; i++) -			sysfs_remove_group(&drv->p->kobj, groups[i]); +	sysfs_remove_groups(&drv->p->kobj, groups);  }  /** @@ -234,7 +159,6 @@ int driver_register(struct device_driver *drv)  	other = driver_find(drv->name, drv->bus);  	if (other) { -		put_driver(other);  		printk(KERN_ERR "Error: Driver '%s' is already registered, "  			"aborting...\n", drv->name);  		return -EBUSY; @@ -244,8 +168,12 @@ int driver_register(struct device_driver *drv)  	if (ret)  		return ret;  	ret = driver_add_groups(drv, drv->groups); -	if (ret) +	if (ret) {  		bus_remove_driver(drv); +		return ret; +	} +	kobject_uevent(&drv->p->kobj, KOBJ_ADD); +  	return ret;  }  EXPORT_SYMBOL_GPL(driver_register); @@ -275,7 +203,9 @@ EXPORT_SYMBOL_GPL(driver_unregister);   * Call kset_find_obj() to iterate over list of drivers on   * a bus to find driver by name. Return driver if found.   * - * Note that kset_find_obj increments driver's reference count. + * This routine provides no locking to prevent the driver it returns + * from being unregistered or unloaded while the caller is using it. + * The caller is responsible for preventing this.   */  struct device_driver *driver_find(const char *name, struct bus_type *bus)  { @@ -283,6 +213,8 @@ struct device_driver *driver_find(const char *name, struct bus_type *bus)  	struct driver_private *priv;  	if (k) { +		/* Drop reference added by kset_find_obj() */ +		kobject_put(k);  		priv = to_driver(k);  		return priv->driver;  	}  | 
