X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fbase%2Fcore.c;h=8c2cc2648f5a5c0ec330df4991f75b6be07131ae;hb=0df6cbb7d8a0a8fea69138e9e463671a8ad99f16;hp=3eeac5a785811561e3b41c0453590f9968b68e2c;hpb=0599ad53fee2d084f9ba26247d7452f06a40d298;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/base/core.c b/drivers/base/core.c index 3eeac5a..8c2cc26 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -21,12 +21,16 @@ #include #include #include +#include #include "base.h" #include "power/power.h" int (*platform_notify)(struct device *dev) = NULL; int (*platform_notify_remove)(struct device *dev) = NULL; +static struct kobject *dev_kobj; +struct kobject *sysfs_dev_char_kobj; +struct kobject *sysfs_dev_block_kobj; #ifdef CONFIG_BLOCK static inline int device_is_not_partition(struct device *dev) @@ -49,7 +53,7 @@ static inline int device_is_not_partition(struct device *dev) * it is attached to. If it is not attached to a bus either, an empty * string will be returned. */ -const char *dev_driver_string(struct device *dev) +const char *dev_driver_string(const struct device *dev) { return dev->driver ? dev->driver->name : (dev->bus ? dev->bus->name : @@ -112,12 +116,10 @@ static void device_release(struct kobject *kobj) dev->type->release(dev); else if (dev->class && dev->class->dev_release) dev->class->dev_release(dev); - else { - printk(KERN_ERR "Device '%s' does not have a release() " + else + WARN(1, KERN_ERR "Device '%s' does not have a release() " "function, it is broken and must be fixed.\n", dev->bus_id); - WARN_ON(1); - } } static struct kobj_type device_ktype = { @@ -521,11 +523,16 @@ static void klist_children_put(struct klist_node *n) * device_initialize - init device structure. * @dev: device. * - * This prepares the device for use by other layers, - * including adding it to the device hierarchy. + * This prepares the device for use by other layers by initializing + * its fields. * It is the first half of device_register(), if called by - * that, though it can also be called separately, so one - * may use @dev's fields (e.g. the refcount). + * that function, though it can also be called separately, so one + * may use @dev's fields. In particular, get_device()/put_device() + * may be used for reference counting of @dev after calling this + * function. + * + * NOTE: Use put_device() to give up your reference instead of freeing + * @dev directly once you have called this function. */ void device_initialize(struct device *dev) { @@ -534,11 +541,11 @@ void device_initialize(struct device *dev) klist_init(&dev->klist_children, klist_children_get, klist_children_put); INIT_LIST_HEAD(&dev->dma_pools); - INIT_LIST_HEAD(&dev->node); init_MUTEX(&dev->sem); spin_lock_init(&dev->devres_lock); INIT_LIST_HEAD(&dev->devres_head); device_init_wakeup(dev, 0); + device_pm_init(dev); set_dev_node(dev, -1); } @@ -548,7 +555,7 @@ static struct kobject *get_device_parent(struct device *dev, { /* class devices without a parent live in /sys/class// */ if (dev->class && (!parent || parent->class != dev->class)) - return &dev->class->subsys.kobj; + return &dev->class->p->class_subsys.kobj; /* all other devices keep their parent */ else if (parent) return &parent->kobj; @@ -594,13 +601,13 @@ static struct kobject *get_device_parent(struct device *dev, parent_kobj = &parent->kobj; /* find our class-directory at the parent and reference it */ - spin_lock(&dev->class->class_dirs.list_lock); - list_for_each_entry(k, &dev->class->class_dirs.list, entry) + spin_lock(&dev->class->p->class_dirs.list_lock); + list_for_each_entry(k, &dev->class->p->class_dirs.list, entry) if (k->parent == parent_kobj) { kobj = kobject_get(k); break; } - spin_unlock(&dev->class->class_dirs.list_lock); + spin_unlock(&dev->class->p->class_dirs.list_lock); if (kobj) return kobj; @@ -608,7 +615,7 @@ static struct kobject *get_device_parent(struct device *dev, k = kobject_create(); if (!k) return NULL; - k->kset = &dev->class->class_dirs; + k->kset = &dev->class->p->class_dirs; retval = kobject_add(k, parent_kobj, "%s", dev->class->name); if (retval < 0) { kobject_put(k); @@ -627,7 +634,7 @@ static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) { /* see if we live in a "glue" directory */ if (!glue_dir || !dev->class || - glue_dir->kset != &dev->class->class_dirs) + glue_dir->kset != &dev->class->p->class_dirs) return; kobject_put(glue_dir); @@ -654,17 +661,18 @@ static int device_add_class_symlinks(struct device *dev) if (!dev->class) return 0; - error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, + error = sysfs_create_link(&dev->kobj, + &dev->class->p->class_subsys.kobj, "subsystem"); if (error) goto out; #ifdef CONFIG_SYSFS_DEPRECATED /* stacked class devices need a symlink in the class directory */ - if (dev->kobj.parent != &dev->class->subsys.kobj && + if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) { - error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, - dev->bus_id); + error = sysfs_create_link(&dev->class->p->class_subsys.kobj, + &dev->kobj, dev->bus_id); if (error) goto out_subsys; } @@ -701,13 +709,14 @@ out_device: if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); out_busid: - if (dev->kobj.parent != &dev->class->subsys.kobj && + if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) - sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); + sysfs_remove_link(&dev->class->p->class_subsys.kobj, + dev->bus_id); #else /* link in the class directory pointing to the device */ - error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, - dev->bus_id); + error = sysfs_create_link(&dev->class->p->class_subsys.kobj, + &dev->kobj, dev->bus_id); if (error) goto out_subsys; @@ -720,7 +729,7 @@ out_busid: return 0; out_busid: - sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); + sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev->bus_id); #endif out_subsys: @@ -746,41 +755,116 @@ static void device_remove_class_symlinks(struct device *dev) sysfs_remove_link(&dev->kobj, "device"); } - if (dev->kobj.parent != &dev->class->subsys.kobj && + if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) - sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); + sysfs_remove_link(&dev->class->p->class_subsys.kobj, + dev->bus_id); #else if (dev->parent && device_is_not_partition(dev)) sysfs_remove_link(&dev->kobj, "device"); - sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); + sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev->bus_id); #endif sysfs_remove_link(&dev->kobj, "subsystem"); } /** + * dev_set_name - set a device name + * @dev: device + * @fmt: format string for the device's name + */ +int dev_set_name(struct device *dev, const char *fmt, ...) +{ + va_list vargs; + + va_start(vargs, fmt); + vsnprintf(dev->bus_id, sizeof(dev->bus_id), fmt, vargs); + va_end(vargs); + return 0; +} +EXPORT_SYMBOL_GPL(dev_set_name); + +/** + * device_to_dev_kobj - select a /sys/dev/ directory for the device + * @dev: device + * + * By default we select char/ for new entries. Setting class->dev_obj + * to NULL prevents an entry from being created. class->dev_kobj must + * be set (or cleared) before any devices are registered to the class + * otherwise device_create_sys_dev_entry() and + * device_remove_sys_dev_entry() will disagree about the the presence + * of the link. + */ +static struct kobject *device_to_dev_kobj(struct device *dev) +{ + struct kobject *kobj; + + if (dev->class) + kobj = dev->class->dev_kobj; + else + kobj = sysfs_dev_char_kobj; + + return kobj; +} + +static int device_create_sys_dev_entry(struct device *dev) +{ + struct kobject *kobj = device_to_dev_kobj(dev); + int error = 0; + char devt_str[15]; + + if (kobj) { + format_dev_t(devt_str, dev->devt); + error = sysfs_create_link(kobj, &dev->kobj, devt_str); + } + + return error; +} + +static void device_remove_sys_dev_entry(struct device *dev) +{ + struct kobject *kobj = device_to_dev_kobj(dev); + char devt_str[15]; + + if (kobj) { + format_dev_t(devt_str, dev->devt); + sysfs_remove_link(kobj, devt_str); + } +} + +/** * device_add - add device to device hierarchy. * @dev: device. * * This is part 2 of device_register(), though may be called * separately _iff_ device_initialize() has been called separately. * - * This adds it to the kobject hierarchy via kobject_add(), adds it + * This adds @dev to the kobject hierarchy via kobject_add(), adds it * to the global and sibling lists for the device, then * adds it to the other relevant subsystems of the driver model. + * + * NOTE: _Never_ directly free @dev after calling this function, even + * if it returned an error! Always use put_device() to give up your + * reference instead. */ int device_add(struct device *dev) { struct device *parent = NULL; struct class_interface *class_intf; - int error; + int error = -EINVAL; dev = get_device(dev); - if (!dev || !strlen(dev->bus_id)) { - error = -EINVAL; - goto Done; - } + if (!dev) + goto done; + + /* Temporarily support init_name if it is set. + * It will override bus_id for now */ + if (dev->init_name) + dev_set_name(dev, "%s", dev->init_name); + + if (!strlen(dev->bus_id)) + goto done; pr_debug("device: '%s': %s\n", dev->bus_id, __func__); @@ -813,6 +897,10 @@ int device_add(struct device *dev) error = device_create_file(dev, &devt_attr); if (error) goto ueventattrError; + + error = device_create_sys_dev_entry(dev); + if (error) + goto devtattrError; } error = device_add_class_symlinks(dev); @@ -824,29 +912,32 @@ int device_add(struct device *dev) error = bus_add_device(dev); if (error) goto BusError; - error = device_pm_add(dev); + error = dpm_sysfs_add(dev); if (error) - goto PMError; + goto DPMError; + device_pm_add(dev); kobject_uevent(&dev->kobj, KOBJ_ADD); bus_attach_device(dev); if (parent) klist_add_tail(&dev->knode_parent, &parent->klist_children); if (dev->class) { - down(&dev->class->sem); + mutex_lock(&dev->class->p->class_mutex); /* tie the class to the device */ - list_add_tail(&dev->node, &dev->class->devices); + klist_add_tail(&dev->knode_class, + &dev->class->p->class_devices); /* notify any interfaces that the device is here */ - list_for_each_entry(class_intf, &dev->class->interfaces, node) + list_for_each_entry(class_intf, + &dev->class->p->class_interfaces, node) if (class_intf->add_dev) class_intf->add_dev(dev, class_intf); - up(&dev->class->sem); + mutex_unlock(&dev->class->p->class_mutex); } - Done: +done: put_device(dev); return error; - PMError: + DPMError: bus_remove_device(dev); BusError: if (dev->bus) @@ -857,6 +948,9 @@ int device_add(struct device *dev) device_remove_class_symlinks(dev); SymlinkError: if (MAJOR(dev->devt)) + device_remove_sys_dev_entry(dev); + devtattrError: + if (MAJOR(dev->devt)) device_remove_file(dev, &devt_attr); ueventattrError: device_remove_file(dev, &uevent_attr); @@ -867,7 +961,7 @@ int device_add(struct device *dev) cleanup_device_parent(dev); if (parent) put_device(parent); - goto Done; + goto done; } /** @@ -880,6 +974,10 @@ int device_add(struct device *dev) * I.e. you should only call the two helpers separately if * have a clearly defined need to use and refcount the device * before it is added to the hierarchy. + * + * NOTE: _Never_ directly free @dev after calling this function, even + * if it returned an error! Always use put_device() to give up the + * reference initialized in this function instead. */ int device_register(struct device *dev) { @@ -930,21 +1028,25 @@ void device_del(struct device *dev) struct class_interface *class_intf; device_pm_remove(dev); + dpm_sysfs_remove(dev); if (parent) klist_del(&dev->knode_parent); - if (MAJOR(dev->devt)) + if (MAJOR(dev->devt)) { + device_remove_sys_dev_entry(dev); device_remove_file(dev, &devt_attr); + } if (dev->class) { device_remove_class_symlinks(dev); - down(&dev->class->sem); + mutex_lock(&dev->class->p->class_mutex); /* notify any interfaces that the device is now gone */ - list_for_each_entry(class_intf, &dev->class->interfaces, node) + list_for_each_entry(class_intf, + &dev->class->p->class_interfaces, node) if (class_intf->remove_dev) class_intf->remove_dev(dev, class_intf); /* remove the device from the class list */ - list_del_init(&dev->node); - up(&dev->class->sem); + klist_del(&dev->knode_class); + mutex_unlock(&dev->class->p->class_mutex); } device_remove_file(dev, &uevent_attr); device_remove_attrs(dev); @@ -1058,7 +1160,25 @@ int __init devices_init(void) devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL); if (!devices_kset) return -ENOMEM; + dev_kobj = kobject_create_and_add("dev", NULL); + if (!dev_kobj) + goto dev_kobj_err; + sysfs_dev_block_kobj = kobject_create_and_add("block", dev_kobj); + if (!sysfs_dev_block_kobj) + goto block_kobj_err; + sysfs_dev_char_kobj = kobject_create_and_add("char", dev_kobj); + if (!sysfs_dev_char_kobj) + goto char_kobj_err; + return 0; + + char_kobj_err: + kobject_put(sysfs_dev_block_kobj); + block_kobj_err: + kobject_put(dev_kobj); + dev_kobj_err: + kset_unregister(devices_kset); + return -ENOMEM; } EXPORT_SYMBOL_GPL(device_for_each_child); @@ -1084,11 +1204,13 @@ static void device_create_release(struct device *dev) } /** - * device_create - creates a device and registers it with sysfs + * device_create_vargs - creates a device and registers it with sysfs * @class: pointer to the struct class that this device should be registered to * @parent: pointer to the parent struct device of this new device, if any * @devt: the dev_t for the char device to be added + * @drvdata: the data to be added to the device for callbacks * @fmt: string for the device's name + * @args: va_list for the device's name * * This function can be used by char device classes. A struct device * will be created in sysfs, registered to the specified class. @@ -1104,10 +1226,10 @@ static void device_create_release(struct device *dev) * Note: the struct class passed to this function must have previously * been created with a call to class_create(). */ -struct device *device_create(struct class *class, struct device *parent, - dev_t devt, const char *fmt, ...) +struct device *device_create_vargs(struct class *class, struct device *parent, + dev_t devt, void *drvdata, const char *fmt, + va_list args) { - va_list args; struct device *dev = NULL; int retval = -ENODEV; @@ -1124,10 +1246,9 @@ struct device *device_create(struct class *class, struct device *parent, dev->class = class; dev->parent = parent; dev->release = device_create_release; + dev_set_drvdata(dev, drvdata); - va_start(args, fmt); vsnprintf(dev->bus_id, BUS_ID_SIZE, fmt, args); - va_end(args); retval = device_register(dev); if (retval) goto error; @@ -1135,9 +1256,44 @@ struct device *device_create(struct class *class, struct device *parent, return dev; error: - kfree(dev); + put_device(dev); return ERR_PTR(retval); } +EXPORT_SYMBOL_GPL(device_create_vargs); + +/** + * device_create - creates a device and registers it with sysfs + * @class: pointer to the struct class that this device should be registered to + * @parent: pointer to the parent struct device of this new device, if any + * @devt: the dev_t for the char device to be added + * @drvdata: the data to be added to the device for callbacks + * @fmt: string for the device's name + * + * This function can be used by char device classes. A struct device + * will be created in sysfs, registered to the specified class. + * + * A "dev" file will be created, showing the dev_t for the device, if + * the dev_t is not 0,0. + * If a pointer to a parent struct device is passed in, the newly created + * struct device will be a child of that device in sysfs. + * The pointer to the struct device will be returned from the call. + * Any further sysfs files that might be required can be created using this + * pointer. + * + * Note: the struct class passed to this function must have previously + * been created with a call to class_create(). + */ +struct device *device_create(struct class *class, struct device *parent, + dev_t devt, void *drvdata, const char *fmt, ...) +{ + va_list vargs; + struct device *dev; + + va_start(vargs, fmt); + dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs); + va_end(vargs); + return dev; +} EXPORT_SYMBOL_GPL(device_create); static int __match_devt(struct device *dev, void *data) @@ -1159,7 +1315,7 @@ void device_destroy(struct class *class, dev_t devt) { struct device *dev; - dev = class_find_device(class, &devt, __match_devt); + dev = class_find_device(class, NULL, &devt, __match_devt); if (dev) { put_device(dev); device_unregister(dev); @@ -1171,6 +1327,11 @@ EXPORT_SYMBOL_GPL(device_destroy); * device_rename - renames a device * @dev: the pointer to the struct device to be renamed * @new_name: the new name of the device + * + * It is the responsibility of the caller to provide mutual + * exclusion between two different calls of device_rename + * on the same device to ensure that new_name is valid and + * won't conflict with other devices. */ int device_rename(struct device *dev, char *new_name) { @@ -1209,8 +1370,9 @@ int device_rename(struct device *dev, char *new_name) if (old_class_name) { new_class_name = make_class_name(dev->class->name, &dev->kobj); if (new_class_name) { - error = sysfs_create_link(&dev->parent->kobj, - &dev->kobj, new_class_name); + error = sysfs_create_link_nowarn(&dev->parent->kobj, + &dev->kobj, + new_class_name); if (error) goto out; sysfs_remove_link(&dev->parent->kobj, old_class_name); @@ -1218,11 +1380,12 @@ int device_rename(struct device *dev, char *new_name) } #else if (dev->class) { - error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, - dev->bus_id); + error = sysfs_create_link_nowarn(&dev->class->p->class_subsys.kobj, + &dev->kobj, dev->bus_id); if (error) goto out; - sysfs_remove_link(&dev->class->subsys.kobj, old_device_name); + sysfs_remove_link(&dev->class->p->class_subsys.kobj, + old_device_name); } #endif @@ -1358,4 +1521,7 @@ void device_shutdown(void) dev->driver->shutdown(dev); } } + kobject_put(sysfs_dev_char_kobj); + kobject_put(sysfs_dev_block_kobj); + kobject_put(dev_kobj); }