|
@@ -27,6 +27,9 @@
|
|
|
|
|
|
int (*platform_notify)(struct device *dev) = NULL;
|
|
int (*platform_notify)(struct device *dev) = NULL;
|
|
int (*platform_notify_remove)(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
|
|
#ifdef CONFIG_BLOCK
|
|
static inline int device_is_not_partition(struct device *dev)
|
|
static inline int device_is_not_partition(struct device *dev)
|
|
@@ -775,6 +778,54 @@ int dev_set_name(struct device *dev, const char *fmt, ...)
|
|
}
|
|
}
|
|
EXPORT_SYMBOL_GPL(dev_set_name);
|
|
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.
|
|
* device_add - add device to device hierarchy.
|
|
* @dev: device.
|
|
* @dev: device.
|
|
@@ -829,6 +880,10 @@ int device_add(struct device *dev)
|
|
error = device_create_file(dev, &devt_attr);
|
|
error = device_create_file(dev, &devt_attr);
|
|
if (error)
|
|
if (error)
|
|
goto ueventattrError;
|
|
goto ueventattrError;
|
|
|
|
+
|
|
|
|
+ error = device_create_sys_dev_entry(dev);
|
|
|
|
+ if (error)
|
|
|
|
+ goto devtattrError;
|
|
}
|
|
}
|
|
|
|
|
|
error = device_add_class_symlinks(dev);
|
|
error = device_add_class_symlinks(dev);
|
|
@@ -872,6 +927,9 @@ int device_add(struct device *dev)
|
|
AttrsError:
|
|
AttrsError:
|
|
device_remove_class_symlinks(dev);
|
|
device_remove_class_symlinks(dev);
|
|
SymlinkError:
|
|
SymlinkError:
|
|
|
|
+ if (MAJOR(dev->devt))
|
|
|
|
+ device_remove_sys_dev_entry(dev);
|
|
|
|
+ devtattrError:
|
|
if (MAJOR(dev->devt))
|
|
if (MAJOR(dev->devt))
|
|
device_remove_file(dev, &devt_attr);
|
|
device_remove_file(dev, &devt_attr);
|
|
ueventattrError:
|
|
ueventattrError:
|
|
@@ -948,8 +1006,10 @@ void device_del(struct device *dev)
|
|
device_pm_remove(dev);
|
|
device_pm_remove(dev);
|
|
if (parent)
|
|
if (parent)
|
|
klist_del(&dev->knode_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);
|
|
device_remove_file(dev, &devt_attr);
|
|
|
|
+ }
|
|
if (dev->class) {
|
|
if (dev->class) {
|
|
device_remove_class_symlinks(dev);
|
|
device_remove_class_symlinks(dev);
|
|
|
|
|
|
@@ -1074,7 +1134,25 @@ int __init devices_init(void)
|
|
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
|
|
devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
|
|
if (!devices_kset)
|
|
if (!devices_kset)
|
|
return -ENOMEM;
|
|
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;
|
|
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);
|
|
EXPORT_SYMBOL_GPL(device_for_each_child);
|
|
@@ -1447,4 +1525,7 @@ void device_shutdown(void)
|
|
dev->driver->shutdown(dev);
|
|
dev->driver->shutdown(dev);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ kobject_put(sysfs_dev_char_kobj);
|
|
|
|
+ kobject_put(sysfs_dev_block_kobj);
|
|
|
|
+ kobject_put(dev_kobj);
|
|
}
|
|
}
|