|
@@ -1217,6 +1217,97 @@ EXPORT_SYMBOL_GPL(put_device);
|
|
EXPORT_SYMBOL_GPL(device_create_file);
|
|
EXPORT_SYMBOL_GPL(device_create_file);
|
|
EXPORT_SYMBOL_GPL(device_remove_file);
|
|
EXPORT_SYMBOL_GPL(device_remove_file);
|
|
|
|
|
|
|
|
+struct root_device
|
|
|
|
+{
|
|
|
|
+ struct device dev;
|
|
|
|
+ struct module *owner;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+#define to_root_device(dev) container_of(dev, struct root_device, dev)
|
|
|
|
+
|
|
|
|
+static void root_device_release(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ kfree(to_root_device(dev));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * __root_device_register - allocate and register a root device
|
|
|
|
+ * @name: root device name
|
|
|
|
+ * @owner: owner module of the root device, usually THIS_MODULE
|
|
|
|
+ *
|
|
|
|
+ * This function allocates a root device and registers it
|
|
|
|
+ * using device_register(). In order to free the returned
|
|
|
|
+ * device, use root_device_unregister().
|
|
|
|
+ *
|
|
|
|
+ * Root devices are dummy devices which allow other devices
|
|
|
|
+ * to be grouped under /sys/devices. Use this function to
|
|
|
|
+ * allocate a root device and then use it as the parent of
|
|
|
|
+ * any device which should appear under /sys/devices/{name}
|
|
|
|
+ *
|
|
|
|
+ * The /sys/devices/{name} directory will also contain a
|
|
|
|
+ * 'module' symlink which points to the @owner directory
|
|
|
|
+ * in sysfs.
|
|
|
|
+ *
|
|
|
|
+ * Note: You probably want to use root_device_register().
|
|
|
|
+ */
|
|
|
|
+struct device *__root_device_register(const char *name, struct module *owner)
|
|
|
|
+{
|
|
|
|
+ struct root_device *root;
|
|
|
|
+ int err = -ENOMEM;
|
|
|
|
+
|
|
|
|
+ root = kzalloc(sizeof(struct root_device), GFP_KERNEL);
|
|
|
|
+ if (!root)
|
|
|
|
+ return ERR_PTR(err);
|
|
|
|
+
|
|
|
|
+ err = dev_set_name(&root->dev, name);
|
|
|
|
+ if (err) {
|
|
|
|
+ kfree(root);
|
|
|
|
+ return ERR_PTR(err);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ root->dev.release = root_device_release;
|
|
|
|
+
|
|
|
|
+ err = device_register(&root->dev);
|
|
|
|
+ if (err) {
|
|
|
|
+ put_device(&root->dev);
|
|
|
|
+ return ERR_PTR(err);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_MODULE /* gotta find a "cleaner" way to do this */
|
|
|
|
+ if (owner) {
|
|
|
|
+ struct module_kobject *mk = &owner->mkobj;
|
|
|
|
+
|
|
|
|
+ err = sysfs_create_link(&root->dev.kobj, &mk->kobj, "module");
|
|
|
|
+ if (err) {
|
|
|
|
+ device_unregister(&root->dev);
|
|
|
|
+ return ERR_PTR(err);
|
|
|
|
+ }
|
|
|
|
+ root->owner = owner;
|
|
|
|
+ }
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ return &root->dev;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(__root_device_register);
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * root_device_unregister - unregister and free a root device
|
|
|
|
+ * @root: device going away.
|
|
|
|
+ *
|
|
|
|
+ * This function unregisters and cleans up a device that was created by
|
|
|
|
+ * root_device_register().
|
|
|
|
+ */
|
|
|
|
+void root_device_unregister(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ struct root_device *root = to_root_device(dev);
|
|
|
|
+
|
|
|
|
+ if (root->owner)
|
|
|
|
+ sysfs_remove_link(&root->dev.kobj, "module");
|
|
|
|
+
|
|
|
|
+ device_unregister(dev);
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL_GPL(root_device_unregister);
|
|
|
|
+
|
|
|
|
|
|
static void device_create_release(struct device *dev)
|
|
static void device_create_release(struct device *dev)
|
|
{
|
|
{
|