Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[firefly-linux-kernel-4.4.55.git] / drivers / acpi / scan.c
index eed9740651f813e13ba2041635fda1dd40458b26..0476e90b2091faac82867e686a8bddde36ed8781 100644 (file)
@@ -130,7 +130,7 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
        list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
                count = snprintf(&modalias[len], size, "%s:", id->id);
                if (count < 0)
-                       return EINVAL;
+                       return -EINVAL;
                if (count >= size)
                        return -ENOMEM;
                len += count;
@@ -141,6 +141,53 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
        return len;
 }
 
+/*
+ * acpi_companion_match() - Can we match via ACPI companion device
+ * @dev: Device in question
+ *
+ * Check if the given device has an ACPI companion and if that companion has
+ * a valid list of PNP IDs, and if the device is the first (primary) physical
+ * device associated with it.
+ *
+ * If multiple physical devices are attached to a single ACPI companion, we need
+ * to be careful.  The usage scenario for this kind of relationship is that all
+ * of the physical devices in question use resources provided by the ACPI
+ * companion.  A typical case is an MFD device where all the sub-devices share
+ * the parent's ACPI companion.  In such cases we can only allow the primary
+ * (first) physical device to be matched with the help of the companion's PNP
+ * IDs.
+ *
+ * Additional physical devices sharing the ACPI companion can still use
+ * resources available from it but they will be matched normally using functions
+ * provided by their bus types (and analogously for their modalias).
+ */
+static bool acpi_companion_match(const struct device *dev)
+{
+       struct acpi_device *adev;
+       bool ret;
+
+       adev = ACPI_COMPANION(dev);
+       if (!adev)
+               return false;
+
+       if (list_empty(&adev->pnp.ids))
+               return false;
+
+       mutex_lock(&adev->physical_node_lock);
+       if (list_empty(&adev->physical_node_list)) {
+               ret = false;
+       } else {
+               const struct acpi_device_physical_node *node;
+
+               node = list_first_entry(&adev->physical_node_list,
+                                       struct acpi_device_physical_node, node);
+               ret = node->dev == dev;
+       }
+       mutex_unlock(&adev->physical_node_lock);
+
+       return ret;
+}
+
 /*
  * Creates uevent modalias field for ACPI enumerated devices.
  * Because the other buses does not support ACPI HIDs & CIDs.
@@ -149,20 +196,14 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
  */
 int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
 {
-       struct acpi_device *acpi_dev;
        int len;
 
-       acpi_dev = ACPI_COMPANION(dev);
-       if (!acpi_dev)
-               return -ENODEV;
-
-       /* Fall back to bus specific way of modalias exporting */
-       if (list_empty(&acpi_dev->pnp.ids))
+       if (!acpi_companion_match(dev))
                return -ENODEV;
 
        if (add_uevent_var(env, "MODALIAS="))
                return -ENOMEM;
-       len = create_modalias(acpi_dev, &env->buf[env->buflen - 1],
+       len = create_modalias(ACPI_COMPANION(dev), &env->buf[env->buflen - 1],
                                sizeof(env->buf) - env->buflen);
        if (len <= 0)
                return len;
@@ -179,18 +220,12 @@ EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
  */
 int acpi_device_modalias(struct device *dev, char *buf, int size)
 {
-       struct acpi_device *acpi_dev;
        int len;
 
-       acpi_dev = ACPI_COMPANION(dev);
-       if (!acpi_dev)
+       if (!acpi_companion_match(dev))
                return -ENODEV;
 
-       /* Fall back to bus specific way of modalias exporting */
-       if (list_empty(&acpi_dev->pnp.ids))
-               return -ENODEV;
-
-       len = create_modalias(acpi_dev, buf, size -1);
+       len = create_modalias(ACPI_COMPANION(dev), buf, size -1);
        if (len <= 0)
                return len;
        buf[len++] = '\n';
@@ -667,8 +702,14 @@ static ssize_t
 acpi_device_sun_show(struct device *dev, struct device_attribute *attr,
                     char *buf) {
        struct acpi_device *acpi_dev = to_acpi_device(dev);
+       acpi_status status;
+       unsigned long long sun;
 
-       return sprintf(buf, "%lu\n", acpi_dev->pnp.sun);
+       status = acpi_evaluate_integer(acpi_dev->handle, "_SUN", NULL, &sun);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       return sprintf(buf, "%llu\n", sun);
 }
 static DEVICE_ATTR(sun, 0444, acpi_device_sun_show, NULL);
 
@@ -690,7 +731,6 @@ static int acpi_device_setup_files(struct acpi_device *dev)
 {
        struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
        acpi_status status;
-       unsigned long long sun;
        int result = 0;
 
        /*
@@ -731,14 +771,10 @@ static int acpi_device_setup_files(struct acpi_device *dev)
        if (dev->pnp.unique_id)
                result = device_create_file(&dev->dev, &dev_attr_uid);
 
-       status = acpi_evaluate_integer(dev->handle, "_SUN", NULL, &sun);
-       if (ACPI_SUCCESS(status)) {
-               dev->pnp.sun = (unsigned long)sun;
+       if (acpi_has_method(dev->handle, "_SUN")) {
                result = device_create_file(&dev->dev, &dev_attr_sun);
                if (result)
                        goto end;
-       } else {
-               dev->pnp.sun = (unsigned long)-1;
        }
 
        if (acpi_has_method(dev->handle, "_STA")) {
@@ -852,6 +888,9 @@ const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
        if (!ids || !handle || acpi_bus_get_device(handle, &adev))
                return NULL;
 
+       if (!acpi_companion_match(dev))
+               return NULL;
+
        return __acpi_match_device(adev, ids);
 }
 EXPORT_SYMBOL_GPL(acpi_match_device);
@@ -922,12 +961,17 @@ static void acpi_device_notify(acpi_handle handle, u32 event, void *data)
        device->driver->ops.notify(device, event);
 }
 
-static acpi_status acpi_device_notify_fixed(void *data)
+static void acpi_device_notify_fixed(void *data)
 {
        struct acpi_device *device = data;
 
        /* Fixed hardware devices have no handles */
        acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device);
+}
+
+static acpi_status acpi_device_fixed_event(void *data)
+{
+       acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_device_notify_fixed, data);
        return AE_OK;
 }
 
@@ -938,12 +982,12 @@ static int acpi_device_install_notify_handler(struct acpi_device *device)
        if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
                status =
                    acpi_install_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
-                                                    acpi_device_notify_fixed,
+                                                    acpi_device_fixed_event,
                                                     device);
        else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
                status =
                    acpi_install_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
-                                                    acpi_device_notify_fixed,
+                                                    acpi_device_fixed_event,
                                                     device);
        else
                status = acpi_install_notify_handler(device->handle,
@@ -960,10 +1004,10 @@ static void acpi_device_remove_notify_handler(struct acpi_device *device)
 {
        if (device->device_type == ACPI_BUS_TYPE_POWER_BUTTON)
                acpi_remove_fixed_event_handler(ACPI_EVENT_POWER_BUTTON,
-                                               acpi_device_notify_fixed);
+                                               acpi_device_fixed_event);
        else if (device->device_type == ACPI_BUS_TYPE_SLEEP_BUTTON)
                acpi_remove_fixed_event_handler(ACPI_EVENT_SLEEP_BUTTON,
-                                               acpi_device_notify_fixed);
+                                               acpi_device_fixed_event);
        else
                acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
                                           acpi_device_notify);
@@ -975,7 +1019,7 @@ static int acpi_device_probe(struct device *dev)
        struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
        int ret;
 
-       if (acpi_dev->handler)
+       if (acpi_dev->handler && !acpi_is_pnp_device(acpi_dev))
                return -EINVAL;
 
        if (!acpi_drv->ops.add)
@@ -1464,7 +1508,7 @@ static void acpi_wakeup_gpe_init(struct acpi_device *device)
        if (ACPI_FAILURE(status))
                return;
 
-       wakeup->flags.run_wake = !!(event_status & ACPI_EVENT_FLAG_HANDLE);
+       wakeup->flags.run_wake = !!(event_status & ACPI_EVENT_FLAG_HAS_HANDLER);
 }
 
 static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
@@ -2183,6 +2227,9 @@ static void acpi_bus_attach(struct acpi_device *device)
  ok:
        list_for_each_entry(child, &device->children, node)
                acpi_bus_attach(child);
+
+       if (device->handler && device->handler->hotplug.notify_online)
+               device->handler->hotplug.notify_online(device);
 }
 
 /**