]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/base/core.c
firmware: change firmware_kset to firmware_kobj
[mirror_ubuntu-bionic-kernel.git] / drivers / base / core.c
index 3f4d6aa139909e49ac77541bdd8b94f46979dae2..d2de2d59af4285ea7288edaf018f8defa341a045 100644 (file)
@@ -401,11 +401,8 @@ static ssize_t show_dev(struct device *dev, struct device_attribute *attr,
 static struct device_attribute devt_attr =
        __ATTR(dev, S_IRUGO, show_dev, NULL);
 
-/*
- *     devices_subsys - structure to be registered with kobject core.
- */
-
-decl_subsys(devices, &device_ktype, &device_uevent_ops);
+/* kset to create /sys/devices/  */
+struct kset *devices_kset;
 
 
 /**
@@ -525,7 +522,8 @@ static void klist_children_put(struct klist_node *n)
 
 void device_initialize(struct device *dev)
 {
-       kobj_set_kset_s(dev, devices_subsys);
+       dev->kobj.kset = devices_kset;
+       dev->kobj.ktype = &device_ktype;
        kobject_init(&dev->kobj);
        klist_init(&dev->klist_children, klist_children_get,
                   klist_children_put);
@@ -561,7 +559,8 @@ static struct kobject *virtual_device_parent(struct device *dev)
        static struct kobject *virtual_dir = NULL;
 
        if (!virtual_dir)
-               virtual_dir = kobject_add_dir(&devices_subsys.kobj, "virtual");
+               virtual_dir = kobject_create_and_add("virtual",
+                                                    &devices_kset->kobj);
 
        return virtual_dir;
 }
@@ -569,6 +568,8 @@ static struct kobject *virtual_device_parent(struct device *dev)
 static struct kobject * get_device_parent(struct device *dev,
                                          struct device *parent)
 {
+       int retval;
+
        if (dev->class) {
                struct kobject *kobj = NULL;
                struct kobject *parent_kobj;
@@ -598,8 +599,18 @@ static struct kobject * get_device_parent(struct device *dev,
                        return kobj;
 
                /* or create a new class-directory at the parent device */
-               return kobject_kset_add_dir(&dev->class->class_dirs,
-                                           parent_kobj, dev->class->name);
+               k = kobject_create();
+               if (!k)
+                       return NULL;
+               k->kset = &dev->class->class_dirs;
+               retval = kobject_add_ng(k, parent_kobj, "%s", dev->class->name);
+               if (retval < 0) {
+                       kobject_put(k);
+                       return NULL;
+               }
+               /* Do not emit a uevent, as it's not needed for this
+                * "class glue" directory. */
+               return k;
        }
 
        if (parent)
@@ -726,11 +737,20 @@ int device_add(struct device *dev)
 {
        struct device *parent = NULL;
        struct class_interface *class_intf;
-       int error = -EINVAL;
+       int error;
+
+       error = pm_sleep_lock();
+       if (error) {
+               dev_warn(dev, "Suspicious %s during suspend\n", __FUNCTION__);
+               dump_stack();
+               return error;
+       }
 
        dev = get_device(dev);
-       if (!dev || !strlen(dev->bus_id))
+       if (!dev || !strlen(dev->bus_id)) {
+               error = -EINVAL;
                goto Error;
+       }
 
        pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
 
@@ -770,9 +790,10 @@ int device_add(struct device *dev)
        error = device_add_attrs(dev);
        if (error)
                goto AttrsError;
-       error = device_pm_add(dev);
+       error = dpm_sysfs_add(dev);
        if (error)
                goto PMError;
+       device_pm_add(dev);
        error = bus_add_device(dev);
        if (error)
                goto BusError;
@@ -794,9 +815,11 @@ int device_add(struct device *dev)
        }
  Done:
        put_device(dev);
+       pm_sleep_unlock();
        return error;
  BusError:
        device_pm_remove(dev);
+       dpm_sysfs_remove(dev);
  PMError:
        if (dev->bus)
                blocking_notifier_call_chain(&dev->bus->bus_notifier,
@@ -903,6 +926,7 @@ void device_del(struct device * dev)
        struct device * parent = dev->parent;
        struct class_interface *class_intf;
 
+       device_pm_remove(dev);
        if (parent)
                klist_del(&dev->knode_parent);
        if (MAJOR(dev->devt))
@@ -979,7 +1003,6 @@ void device_del(struct device * dev)
        if (dev->bus)
                blocking_notifier_call_chain(&dev->bus->bus_notifier,
                                             BUS_NOTIFY_DEL_DEVICE, dev);
-       device_pm_remove(dev);
        kobject_uevent(&dev->kobj, KOBJ_REMOVE);
        kobject_del(&dev->kobj);
        if (parent)
@@ -1071,7 +1094,10 @@ struct device * device_find_child(struct device *parent, void *data,
 
 int __init devices_init(void)
 {
-       return subsystem_register(&devices_subsys);
+       devices_kset = kset_create_and_add("devices", &device_uevent_ops, NULL);
+       if (!devices_kset)
+               return -ENOMEM;
+       return 0;
 }
 
 EXPORT_SYMBOL_GPL(device_for_each_child);
@@ -1154,14 +1180,11 @@ error:
 EXPORT_SYMBOL_GPL(device_create);
 
 /**
- * device_destroy - removes a device that was created with device_create()
+ * find_device - finds a device that was created with device_create()
  * @class: pointer to the struct class that this device was registered with
  * @devt: the dev_t of the device that was previously registered
- *
- * This call unregisters and cleans up a device that was created with a
- * call to device_create().
  */
-void device_destroy(struct class *class, dev_t devt)
+static struct device *find_device(struct class *class, dev_t devt)
 {
        struct device *dev = NULL;
        struct device *dev_tmp;
@@ -1174,12 +1197,54 @@ void device_destroy(struct class *class, dev_t devt)
                }
        }
        up(&class->sem);
+       return dev;
+}
 
+/**
+ * device_destroy - removes a device that was created with device_create()
+ * @class: pointer to the struct class that this device was registered with
+ * @devt: the dev_t of the device that was previously registered
+ *
+ * This call unregisters and cleans up a device that was created with a
+ * call to device_create().
+ */
+void device_destroy(struct class *class, dev_t devt)
+{
+       struct device *dev;
+
+       dev = find_device(class, devt);
        if (dev)
                device_unregister(dev);
 }
 EXPORT_SYMBOL_GPL(device_destroy);
 
+#ifdef CONFIG_PM_SLEEP
+/**
+ * destroy_suspended_device - asks the PM core to remove a suspended device
+ * @class: pointer to the struct class that this device was registered with
+ * @devt: the dev_t of the device that was previously registered
+ *
+ * This call notifies the PM core of the necessity to unregister a suspended
+ * device created with a call to device_create() (devices cannot be
+ * unregistered directly while suspended, since the PM core holds their
+ * semaphores at that time).
+ *
+ * It can only be called within the scope of a system sleep transition.  In
+ * practice this means it has to be directly or indirectly invoked either by
+ * a suspend or resume method, or by the PM core (e.g. via
+ * disable_nonboot_cpus() or enable_nonboot_cpus()).
+ */
+void destroy_suspended_device(struct class *class, dev_t devt)
+{
+       struct device *dev;
+
+       dev = find_device(class, devt);
+       if (dev)
+               device_pm_schedule_removal(dev);
+}
+EXPORT_SYMBOL_GPL(destroy_suspended_device);
+#endif /* CONFIG_PM_SLEEP */
+
 /**
  * device_rename - renames a device
  * @dev: the pointer to the struct device to be renamed