X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fbase%2Fcore.c;h=8c2cc2648f5a5c0ec330df4991f75b6be07131ae;hb=ddd535c713c788f3c23c6548c4ba985a7593113c;hp=76fdd41fea0e4e8e8a6591b42429c3d52686483b;hpb=184f1f779d5a2e62de4a0b34842ddf8546beca8f;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/base/core.c b/drivers/base/core.c index 76fdd41..8c2cc26 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "base.h" #include "power/power.h" @@ -52,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 : @@ -115,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 = { @@ -524,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) { @@ -537,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); } @@ -551,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->p->subsys.kobj; + return &dev->class->p->class_subsys.kobj; /* all other devices keep their parent */ else if (parent) return &parent->kobj; @@ -657,16 +661,17 @@ static int device_add_class_symlinks(struct device *dev) if (!dev->class) return 0; - error = sysfs_create_link(&dev->kobj, &dev->class->p->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->p->subsys.kobj && + if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) { - error = sysfs_create_link(&dev->class->p->subsys.kobj, + error = sysfs_create_link(&dev->class->p->class_subsys.kobj, &dev->kobj, dev->bus_id); if (error) goto out_subsys; @@ -704,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->p->subsys.kobj && + if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) - sysfs_remove_link(&dev->class->p->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->p->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; @@ -723,7 +729,7 @@ out_busid: return 0; out_busid: - sysfs_remove_link(&dev->class->p->subsys.kobj, dev->bus_id); + sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev->bus_id); #endif out_subsys: @@ -749,14 +755,15 @@ static void device_remove_class_symlinks(struct device *dev) sysfs_remove_link(&dev->kobj, "device"); } - if (dev->kobj.parent != &dev->class->p->subsys.kobj && + if (dev->kobj.parent != &dev->class->p->class_subsys.kobj && device_is_not_partition(dev)) - sysfs_remove_link(&dev->class->p->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->p->subsys.kobj, dev->bus_id); + sysfs_remove_link(&dev->class->p->class_subsys.kobj, dev->bus_id); #endif sysfs_remove_link(&dev->kobj, "subsystem"); @@ -833,21 +840,31 @@ static void device_remove_sys_dev_entry(struct device *dev) * 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__); @@ -895,30 +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->p->sem); + mutex_lock(&dev->class->p->class_mutex); /* tie the class to the device */ - list_add_tail(&dev->node, &dev->class->p->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->p->class_interfaces, node) if (class_intf->add_dev) class_intf->add_dev(dev, class_intf); - up(&dev->class->p->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) @@ -942,7 +961,7 @@ int device_add(struct device *dev) cleanup_device_parent(dev); if (parent) put_device(parent); - goto Done; + goto done; } /** @@ -955,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) { @@ -1005,6 +1028,7 @@ 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)) { @@ -1014,15 +1038,15 @@ void device_del(struct device *dev) if (dev->class) { device_remove_class_symlinks(dev); - down(&dev->class->p->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->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->p->sem); + klist_del(&dev->knode_class); + mutex_unlock(&dev->class->p->class_mutex); } device_remove_file(dev, &uevent_attr); device_remove_attrs(dev); @@ -1232,7 +1256,7 @@ struct device *device_create_vargs(struct class *class, struct device *parent, return dev; error: - kfree(dev); + put_device(dev); return ERR_PTR(retval); } EXPORT_SYMBOL_GPL(device_create_vargs); @@ -1303,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) { @@ -1341,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); @@ -1350,11 +1380,11 @@ int device_rename(struct device *dev, char *new_name) } #else if (dev->class) { - error = sysfs_create_link(&dev->class->p->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->p->subsys.kobj, + sysfs_remove_link(&dev->class->p->class_subsys.kobj, old_device_name); } #endif