X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fbase%2Fcore.c;h=b224bb43ff638f812694efe1e4c8eaa5bbd47967;hb=59458f40e25915a355d8b1d701425fe9f4f9ea23;hp=f1228f25efe092e3746fb7dfdda21cc62338071d;hpb=2620efef7029bb040430f50f0fc148f2d5e002ad;p=powerpc.git diff --git a/drivers/base/core.c b/drivers/base/core.c index f1228f25ef..b224bb43ff 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c @@ -319,6 +319,32 @@ void device_remove_file(struct device * dev, struct device_attribute * attr) } } +/** + * device_create_bin_file - create sysfs binary attribute file for device. + * @dev: device. + * @attr: device binary attribute descriptor. + */ +int device_create_bin_file(struct device *dev, struct bin_attribute *attr) +{ + int error = -EINVAL; + if (dev) + error = sysfs_create_bin_file(&dev->kobj, attr); + return error; +} +EXPORT_SYMBOL_GPL(device_create_bin_file); + +/** + * device_remove_bin_file - remove sysfs binary attribute file + * @dev: device. + * @attr: device binary attribute descriptor. + */ +void device_remove_bin_file(struct device *dev, struct bin_attribute *attr) +{ + if (dev) + sysfs_remove_bin_file(&dev->kobj, attr); +} +EXPORT_SYMBOL_GPL(device_remove_bin_file); + static void klist_children_get(struct klist_node *n) { struct device *dev = container_of(n, struct device, knode_parent); @@ -372,12 +398,20 @@ int device_add(struct device *dev) { struct device *parent = NULL; char *class_name = NULL; + struct class_interface *class_intf; int error = -EINVAL; dev = get_device(dev); if (!dev || !strlen(dev->bus_id)) goto Error; + /* if this is a class device, and has no parent, create one */ + if ((dev->class) && (dev->parent == NULL)) { + error = virtual_device_parent(dev); + if (error) + goto Error; + } + parent = get_device(dev->parent); pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); @@ -390,6 +424,10 @@ int device_add(struct device *dev) if ((error = kobject_add(&dev->kobj))) goto Error; + /* notify platform of device entry */ + if (platform_notify) + platform_notify(dev); + dev->uevent_attr.attr.name = "uevent"; dev->uevent_attr.attr.mode = S_IWUSR; if (dev->driver) @@ -444,15 +482,16 @@ int device_add(struct device *dev) klist_add_tail(&dev->knode_parent, &parent->klist_children); if (dev->class) { - /* tie the class to the device */ down(&dev->class->sem); + /* tie the class to the device */ list_add_tail(&dev->node, &dev->class->devices); + + /* notify any interfaces that the device is here */ + list_for_each_entry(class_intf, &dev->class->interfaces, node) + if (class_intf->add_dev) + class_intf->add_dev(dev, class_intf); up(&dev->class->sem); } - - /* notify platform of device entry */ - if (platform_notify) - platform_notify(dev); Done: kfree(class_name); put_device(dev); @@ -541,6 +580,7 @@ void device_del(struct device * dev) { struct device * parent = dev->parent; char *class_name = NULL; + struct class_interface *class_intf; if (parent) klist_del(&dev->knode_parent); @@ -556,6 +596,11 @@ void device_del(struct device * dev) } kfree(class_name); down(&dev->class->sem); + /* notify any interfaces that the device is now gone */ + list_for_each_entry(class_intf, &dev->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); } @@ -736,3 +781,58 @@ void device_destroy(struct class *class, dev_t devt) device_unregister(dev); } 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 + */ +int device_rename(struct device *dev, char *new_name) +{ + char *old_class_name = NULL; + char *new_class_name = NULL; + char *old_symlink_name = NULL; + int error; + + dev = get_device(dev); + if (!dev) + return -EINVAL; + + pr_debug("DEVICE: renaming '%s' to '%s'\n", dev->bus_id, new_name); + + if ((dev->class) && (dev->parent)) + old_class_name = make_class_name(dev->class->name, &dev->kobj); + + if (dev->class) { + old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); + if (!old_symlink_name) + return -ENOMEM; + strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE); + } + + strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); + + error = kobject_rename(&dev->kobj, new_name); + + if (old_class_name) { + new_class_name = make_class_name(dev->class->name, &dev->kobj); + if (new_class_name) { + sysfs_create_link(&dev->parent->kobj, &dev->kobj, + new_class_name); + sysfs_remove_link(&dev->parent->kobj, old_class_name); + } + } + if (dev->class) { + sysfs_remove_link(&dev->class->subsys.kset.kobj, + old_symlink_name); + sysfs_create_link(&dev->class->subsys.kset.kobj, &dev->kobj, + dev->bus_id); + } + put_device(dev); + + kfree(old_class_name); + kfree(new_class_name); + kfree(old_symlink_name); + + return error; +}