|
@@ -660,6 +660,82 @@ static int setup_parent(struct device *dev, struct device *parent)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int device_add_class_symlinks(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ int error;
|
|
|
|
+
|
|
|
|
+ if (!dev->class)
|
|
|
|
+ return 0;
|
|
|
|
+ error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
|
|
|
|
+ "subsystem");
|
|
|
|
+ if (error)
|
|
|
|
+ goto out;
|
|
|
|
+ /*
|
|
|
|
+ * If this is not a "fake" compatible device, then create the
|
|
|
|
+ * symlink from the class to the device.
|
|
|
|
+ */
|
|
|
|
+ if (dev->kobj.parent != &dev->class->subsys.kobj) {
|
|
|
|
+ error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
|
|
|
|
+ dev->bus_id);
|
|
|
|
+ if (error)
|
|
|
|
+ goto out_subsys;
|
|
|
|
+ }
|
|
|
|
+ /* only bus-device parents get a "device"-link */
|
|
|
|
+ if (dev->parent && dev->parent->bus) {
|
|
|
|
+ error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
|
|
|
|
+ "device");
|
|
|
|
+ if (error)
|
|
|
|
+ goto out_busid;
|
|
|
|
+#ifdef CONFIG_SYSFS_DEPRECATED
|
|
|
|
+ {
|
|
|
|
+ char * class_name = make_class_name(dev->class->name,
|
|
|
|
+ &dev->kobj);
|
|
|
|
+ if (class_name)
|
|
|
|
+ error = sysfs_create_link(&dev->parent->kobj,
|
|
|
|
+ &dev->kobj, class_name);
|
|
|
|
+ kfree(class_name);
|
|
|
|
+ if (error)
|
|
|
|
+ goto out_device;
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_SYSFS_DEPRECATED
|
|
|
|
+out_device:
|
|
|
|
+ if (dev->parent)
|
|
|
|
+ sysfs_remove_link(&dev->kobj, "device");
|
|
|
|
+#endif
|
|
|
|
+out_busid:
|
|
|
|
+ if (dev->kobj.parent != &dev->class->subsys.kobj)
|
|
|
|
+ sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
|
|
|
|
+out_subsys:
|
|
|
|
+ sysfs_remove_link(&dev->kobj, "subsystem");
|
|
|
|
+out:
|
|
|
|
+ return error;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void device_remove_class_symlinks(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ if (!dev->class)
|
|
|
|
+ return;
|
|
|
|
+ if (dev->parent) {
|
|
|
|
+#ifdef CONFIG_SYSFS_DEPRECATED
|
|
|
|
+ char *class_name;
|
|
|
|
+
|
|
|
|
+ class_name = make_class_name(dev->class->name, &dev->kobj);
|
|
|
|
+ if (class_name) {
|
|
|
|
+ sysfs_remove_link(&dev->parent->kobj, class_name);
|
|
|
|
+ kfree(class_name);
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
+ sysfs_remove_link(&dev->kobj, "device");
|
|
|
|
+ }
|
|
|
|
+ if (dev->kobj.parent != &dev->class->subsys.kobj)
|
|
|
|
+ sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
|
|
|
|
+ sysfs_remove_link(&dev->kobj, "subsystem");
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* device_add - add device to device hierarchy.
|
|
* device_add - add device to device hierarchy.
|
|
* @dev: device.
|
|
* @dev: device.
|
|
@@ -674,7 +750,6 @@ static int setup_parent(struct device *dev, struct device *parent)
|
|
int device_add(struct device *dev)
|
|
int device_add(struct device *dev)
|
|
{
|
|
{
|
|
struct device *parent = NULL;
|
|
struct device *parent = NULL;
|
|
- char *class_name = NULL;
|
|
|
|
struct class_interface *class_intf;
|
|
struct class_interface *class_intf;
|
|
int error = -EINVAL;
|
|
int error = -EINVAL;
|
|
|
|
|
|
@@ -714,27 +789,9 @@ int device_add(struct device *dev)
|
|
goto ueventattrError;
|
|
goto ueventattrError;
|
|
}
|
|
}
|
|
|
|
|
|
- if (dev->class) {
|
|
|
|
- sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
|
|
|
|
- "subsystem");
|
|
|
|
- /* If this is not a "fake" compatible device, then create the
|
|
|
|
- * symlink from the class to the device. */
|
|
|
|
- if (dev->kobj.parent != &dev->class->subsys.kobj)
|
|
|
|
- sysfs_create_link(&dev->class->subsys.kobj,
|
|
|
|
- &dev->kobj, dev->bus_id);
|
|
|
|
- if (parent) {
|
|
|
|
- sysfs_create_link(&dev->kobj, &dev->parent->kobj,
|
|
|
|
- "device");
|
|
|
|
-#ifdef CONFIG_SYSFS_DEPRECATED
|
|
|
|
- class_name = make_class_name(dev->class->name,
|
|
|
|
- &dev->kobj);
|
|
|
|
- if (class_name)
|
|
|
|
- sysfs_create_link(&dev->parent->kobj,
|
|
|
|
- &dev->kobj, class_name);
|
|
|
|
-#endif
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
|
|
+ error = device_add_class_symlinks(dev);
|
|
|
|
+ if (error)
|
|
|
|
+ goto SymlinkError;
|
|
error = device_add_attrs(dev);
|
|
error = device_add_attrs(dev);
|
|
if (error)
|
|
if (error)
|
|
goto AttrsError;
|
|
goto AttrsError;
|
|
@@ -761,7 +818,6 @@ int device_add(struct device *dev)
|
|
up(&dev->class->sem);
|
|
up(&dev->class->sem);
|
|
}
|
|
}
|
|
Done:
|
|
Done:
|
|
- kfree(class_name);
|
|
|
|
put_device(dev);
|
|
put_device(dev);
|
|
return error;
|
|
return error;
|
|
BusError:
|
|
BusError:
|
|
@@ -772,6 +828,8 @@ int device_add(struct device *dev)
|
|
BUS_NOTIFY_DEL_DEVICE, dev);
|
|
BUS_NOTIFY_DEL_DEVICE, dev);
|
|
device_remove_attrs(dev);
|
|
device_remove_attrs(dev);
|
|
AttrsError:
|
|
AttrsError:
|
|
|
|
+ device_remove_class_symlinks(dev);
|
|
|
|
+ SymlinkError:
|
|
if (MAJOR(dev->devt))
|
|
if (MAJOR(dev->devt))
|
|
device_remove_file(dev, &devt_attr);
|
|
device_remove_file(dev, &devt_attr);
|
|
|
|
|
|
@@ -1156,7 +1214,7 @@ int device_rename(struct device *dev, char *new_name)
|
|
{
|
|
{
|
|
char *old_class_name = NULL;
|
|
char *old_class_name = NULL;
|
|
char *new_class_name = NULL;
|
|
char *new_class_name = NULL;
|
|
- char *old_symlink_name = NULL;
|
|
|
|
|
|
+ char *old_device_name = NULL;
|
|
int error;
|
|
int error;
|
|
|
|
|
|
dev = get_device(dev);
|
|
dev = get_device(dev);
|
|
@@ -1170,42 +1228,49 @@ int device_rename(struct device *dev, char *new_name)
|
|
old_class_name = make_class_name(dev->class->name, &dev->kobj);
|
|
old_class_name = make_class_name(dev->class->name, &dev->kobj);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
- if (dev->class) {
|
|
|
|
- old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
|
|
|
|
- if (!old_symlink_name) {
|
|
|
|
- error = -ENOMEM;
|
|
|
|
- goto out_free_old_class;
|
|
|
|
- }
|
|
|
|
- strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE);
|
|
|
|
|
|
+ old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL);
|
|
|
|
+ if (!old_device_name) {
|
|
|
|
+ error = -ENOMEM;
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+ strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE);
|
|
strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
|
|
strlcpy(dev->bus_id, new_name, BUS_ID_SIZE);
|
|
|
|
|
|
error = kobject_rename(&dev->kobj, new_name);
|
|
error = kobject_rename(&dev->kobj, new_name);
|
|
|
|
+ if (error) {
|
|
|
|
+ strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE);
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
|
|
#ifdef CONFIG_SYSFS_DEPRECATED
|
|
#ifdef CONFIG_SYSFS_DEPRECATED
|
|
if (old_class_name) {
|
|
if (old_class_name) {
|
|
new_class_name = make_class_name(dev->class->name, &dev->kobj);
|
|
new_class_name = make_class_name(dev->class->name, &dev->kobj);
|
|
if (new_class_name) {
|
|
if (new_class_name) {
|
|
- sysfs_create_link(&dev->parent->kobj, &dev->kobj,
|
|
|
|
- new_class_name);
|
|
|
|
|
|
+ error = sysfs_create_link(&dev->parent->kobj,
|
|
|
|
+ &dev->kobj, new_class_name);
|
|
|
|
+ if (error)
|
|
|
|
+ goto out;
|
|
sysfs_remove_link(&dev->parent->kobj, old_class_name);
|
|
sysfs_remove_link(&dev->parent->kobj, old_class_name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
|
|
if (dev->class) {
|
|
if (dev->class) {
|
|
- sysfs_remove_link(&dev->class->subsys.kobj,
|
|
|
|
- old_symlink_name);
|
|
|
|
- sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
|
|
|
|
- dev->bus_id);
|
|
|
|
|
|
+ sysfs_remove_link(&dev->class->subsys.kobj, old_device_name);
|
|
|
|
+ error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
|
|
|
|
+ dev->bus_id);
|
|
|
|
+ if (error) {
|
|
|
|
+ /* Uh... how to unravel this if restoring can fail? */
|
|
|
|
+ dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n",
|
|
|
|
+ __FUNCTION__, error);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+out:
|
|
put_device(dev);
|
|
put_device(dev);
|
|
|
|
|
|
kfree(new_class_name);
|
|
kfree(new_class_name);
|
|
- kfree(old_symlink_name);
|
|
|
|
- out_free_old_class:
|
|
|
|
kfree(old_class_name);
|
|
kfree(old_class_name);
|
|
|
|
+ kfree(old_device_name);
|
|
|
|
|
|
return error;
|
|
return error;
|
|
}
|
|
}
|