From fd9caef4e222a2c5e7ed63050780d215a6a263f3 Mon Sep 17 00:00:00 2001 From: Aaron Lu Date: Fri, 13 Mar 2015 13:52:50 +0800 Subject: ACPI / scan: fix fixed event handler return value The fixed event handler should return a value that is either 0 or 1 meanning if the event is handled or not, instead of an acpi_status to mean if the handler runs well or not. Suggested-by: Lv Zheng Signed-off-by: Aaron Lu Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index bbca7830e18a..3e5a2768c3b4 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -1062,10 +1062,10 @@ static void acpi_device_notify_fixed(void *data) acpi_device_notify(NULL, ACPI_FIXED_HARDWARE_EVENT, device); } -static acpi_status acpi_device_fixed_event(void *data) +static u32 acpi_device_fixed_event(void *data) { acpi_os_execute(OSL_NOTIFY_HANDLER, acpi_device_notify_fixed, data); - return AE_OK; + return ACPI_INTERRUPT_HANDLED; } static int acpi_device_install_notify_handler(struct acpi_device *device) -- cgit v1.2.3 From 54fe9ce385d499fe5a2bb0c68f092c97dad9365c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 10 Apr 2015 16:07:30 +0200 Subject: ACPI / scan: Generalize of_compatible matching Redefine the function used for matching the device's "compatible" property against a given list of "compatible" strings to take a pointer to that list instead of a driver object pointer to make it more general. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/scan.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 3e5a2768c3b4..99f97ac64aa4 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -949,9 +949,17 @@ int acpi_match_device_ids(struct acpi_device *device, } EXPORT_SYMBOL(acpi_match_device_ids); -/* Performs match against special "PRP0001" shoehorn ACPI ID */ -static bool acpi_of_driver_match_device(struct device *dev, - const struct device_driver *drv) +/** + * acpi_of_match_device - Match device using the "compatible" property. + * @dev: Device to match. + * @of_match_table: List of device IDs to match against. + * + * If @dev has an ACPI companion which has the special PRP0001 device ID in its + * list of identifiers and a _DSD object with the "compatible" property, use + * that property to match against the given list of identifiers. + */ +static bool acpi_of_match_device(struct device *dev, + const struct of_device_id *of_match_table) { const union acpi_object *of_compatible, *obj; struct acpi_device *adev; @@ -962,7 +970,7 @@ static bool acpi_of_driver_match_device(struct device *dev, return false; of_compatible = adev->data.of_compatible; - if (!drv->of_match_table || !of_compatible) + if (!of_match_table || !of_compatible) return false; if (of_compatible->type == ACPI_TYPE_PACKAGE) { @@ -976,7 +984,7 @@ static bool acpi_of_driver_match_device(struct device *dev, for (i = 0; i < nval; i++, obj++) { const struct of_device_id *id; - for (id = drv->of_match_table; id->compatible[0]; id++) + for (id = of_match_table; id->compatible[0]; id++) if (!strcasecmp(obj->string.pointer, id->compatible)) return true; } @@ -988,7 +996,7 @@ bool acpi_driver_match_device(struct device *dev, const struct device_driver *drv) { if (!drv->acpi_match_table) - return acpi_of_driver_match_device(dev, drv); + return acpi_of_match_device(dev, drv->of_match_table); return !!acpi_match_device(drv->acpi_match_table, dev); } -- cgit v1.2.3 From e1acdeb0e7707f4220aa14ad6739102ba26e07c0 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 10 Apr 2015 16:07:38 +0200 Subject: ACPI / scan: Simplify acpi_match_device() Redefine acpi_companion_match() to return an ACPI device object pointer instead of a bool and use it to remove some redundant code from acpi_match_device(). Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/scan.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 99f97ac64aa4..b4d5549265ed 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -194,7 +194,8 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, * * 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. + * device associated with it. Return the companion pointer if that's the case + * or NULL otherwise. * * 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 @@ -208,31 +209,31 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, * 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) +static struct acpi_device *acpi_companion_match(const struct device *dev) { struct acpi_device *adev; - bool ret; adev = ACPI_COMPANION(dev); if (!adev) - return false; + return NULL; if (list_empty(&adev->pnp.ids)) - return false; + return NULL; mutex_lock(&adev->physical_node_lock); if (list_empty(&adev->physical_node_list)) { - ret = false; + adev = NULL; } 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; + if (node->dev != dev) + adev = NULL; } mutex_unlock(&adev->physical_node_lock); - return ret; + return adev; } /* @@ -904,7 +905,7 @@ static const struct acpi_device_id *__acpi_match_device( * If the device is not present, it is unnecessary to load device * driver for it. */ - if (!device->status.present) + if (!device || !device->status.present) return NULL; for (id = ids; id->id[0]; id++) @@ -929,16 +930,7 @@ static const struct acpi_device_id *__acpi_match_device( const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, const struct device *dev) { - struct acpi_device *adev; - acpi_handle handle = ACPI_HANDLE(dev); - - if (!ids || !handle || acpi_bus_get_device(handle, &adev)) - return NULL; - - if (!acpi_companion_match(dev)) - return NULL; - - return __acpi_match_device(adev, ids); + return __acpi_match_device(acpi_companion_match(dev), ids); } EXPORT_SYMBOL_GPL(acpi_match_device); -- cgit v1.2.3 From 2b9c698efa58bf7d9a0d3d3b28115cf9e55ca818 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 10 Apr 2015 16:07:51 +0200 Subject: ACPI / scan: Take the PRP0001 position in the list of IDs into account If the special PRP0001 device ID is present in a device's _CID list, it should not prevent any ACPI/PNP IDs preceding it in the device's list of identifiers from being matched first. That is, only if none of the IDs preceding PRP0001 in the device's PNP/ACPI IDs list matches the IDs recognized by the driver, the driver's list of "compatible" IDs should be matched against the device's "compatible" property, if present. In addition to that, drivers can provide both acpi_match_table and of_match_table at the same time and the of_compatible matching should be used in that case too if PRP0001 is present in the device's list of identifiers. To make that happen, rework acpi_driver_match_device() to do the "compatible" property check in addition to matching the driver's list of ACPI IDs against the device's one. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/scan.c | 115 +++++++++++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 50 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index b4d5549265ed..8f3adf924e83 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -895,8 +895,51 @@ static void acpi_device_remove_files(struct acpi_device *dev) ACPI Bus operations -------------------------------------------------------------------------- */ +/** + * acpi_of_match_device - Match device object using the "compatible" property. + * @adev: ACPI device object to match. + * @of_match_table: List of device IDs to match against. + * + * If @dev has an ACPI companion which has the special PRP0001 device ID in its + * list of identifiers and a _DSD object with the "compatible" property, use + * that property to match against the given list of identifiers. + */ +static bool acpi_of_match_device(struct acpi_device *adev, + const struct of_device_id *of_match_table) +{ + const union acpi_object *of_compatible, *obj; + int i, nval; + + if (!adev) + return false; + + of_compatible = adev->data.of_compatible; + if (!of_match_table || !of_compatible) + return false; + + if (of_compatible->type == ACPI_TYPE_PACKAGE) { + nval = of_compatible->package.count; + obj = of_compatible->package.elements; + } else { /* Must be ACPI_TYPE_STRING. */ + nval = 1; + obj = of_compatible; + } + /* Now we can look for the driver DT compatible strings */ + for (i = 0; i < nval; i++, obj++) { + const struct of_device_id *id; + + for (id = of_match_table; id->compatible[0]; id++) + if (!strcasecmp(obj->string.pointer, id->compatible)) + return true; + } + + return false; +} + static const struct acpi_device_id *__acpi_match_device( - struct acpi_device *device, const struct acpi_device_id *ids) + struct acpi_device *device, + const struct acpi_device_id *ids, + const struct of_device_id *of_ids) { const struct acpi_device_id *id; struct acpi_hardware_id *hwid; @@ -908,11 +951,24 @@ static const struct acpi_device_id *__acpi_match_device( if (!device || !device->status.present) return NULL; - for (id = ids; id->id[0]; id++) - list_for_each_entry(hwid, &device->pnp.ids, list) + list_for_each_entry(hwid, &device->pnp.ids, list) { + /* First, check the ACPI/PNP IDs provided by the caller. */ + for (id = ids; id->id[0]; id++) if (!strcmp((char *) id->id, hwid->id)) return id; + /* + * Next, check the special "PRP0001" ID and try to match the + * "compatible" property if found. + * + * The id returned by the below is not valid, but the only + * caller passing non-NULL of_ids here is only interested in + * whether or not the return value is NULL. + */ + if (!strcmp("PRP0001", hwid->id) + && acpi_of_match_device(device, of_ids)) + return id; + } return NULL; } @@ -930,67 +986,26 @@ static const struct acpi_device_id *__acpi_match_device( const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids, const struct device *dev) { - return __acpi_match_device(acpi_companion_match(dev), ids); + return __acpi_match_device(acpi_companion_match(dev), ids, NULL); } EXPORT_SYMBOL_GPL(acpi_match_device); int acpi_match_device_ids(struct acpi_device *device, const struct acpi_device_id *ids) { - return __acpi_match_device(device, ids) ? 0 : -ENOENT; + return __acpi_match_device(device, ids, NULL) ? 0 : -ENOENT; } EXPORT_SYMBOL(acpi_match_device_ids); -/** - * acpi_of_match_device - Match device using the "compatible" property. - * @dev: Device to match. - * @of_match_table: List of device IDs to match against. - * - * If @dev has an ACPI companion which has the special PRP0001 device ID in its - * list of identifiers and a _DSD object with the "compatible" property, use - * that property to match against the given list of identifiers. - */ -static bool acpi_of_match_device(struct device *dev, - const struct of_device_id *of_match_table) -{ - const union acpi_object *of_compatible, *obj; - struct acpi_device *adev; - int i, nval; - - adev = ACPI_COMPANION(dev); - if (!adev) - return false; - - of_compatible = adev->data.of_compatible; - if (!of_match_table || !of_compatible) - return false; - - if (of_compatible->type == ACPI_TYPE_PACKAGE) { - nval = of_compatible->package.count; - obj = of_compatible->package.elements; - } else { /* Must be ACPI_TYPE_STRING. */ - nval = 1; - obj = of_compatible; - } - /* Now we can look for the driver DT compatible strings */ - for (i = 0; i < nval; i++, obj++) { - const struct of_device_id *id; - - for (id = of_match_table; id->compatible[0]; id++) - if (!strcasecmp(obj->string.pointer, id->compatible)) - return true; - } - - return false; -} - bool acpi_driver_match_device(struct device *dev, const struct device_driver *drv) { if (!drv->acpi_match_table) - return acpi_of_match_device(dev, drv->of_match_table); + return acpi_of_match_device(ACPI_COMPANION(dev), + drv->of_match_table); - return !!acpi_match_device(drv->acpi_match_table, dev); + return !!__acpi_match_device(acpi_companion_match(dev), + drv->acpi_match_table, drv->of_match_table); } EXPORT_SYMBOL_GPL(acpi_driver_match_device); -- cgit v1.2.3 From 8765c5ba19490c9167fe0c4e05c2dfdcc39873a3 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Mon, 13 Apr 2015 00:29:36 +0200 Subject: ACPI / scan: Rework modalias creation when "compatible" is present Currently, the ACPI modalias creation covers two mutually exclusive cases: If the PRP0001 device ID is present in the device's list of ACPI/PNP IDs and the "compatible" property is present in _DSD, the created modalias will follow the OF rules of modalias creation. Otherwise, ACPI rules are used. However, that is not really desirable, because the presence of PRP0001 in the list of device IDs generally does not preclude using other ACPI/PNP IDs with that device and those other IDs may be of higher priority. In those cases, the other IDs should take preference over PRP0001 and therefore they also should be present in the modalias. For this reason, rework the modalias creation for ACPI so that it shows both the ACPI-style and OF-style modalias strings if the device has a non-empty list of ACPI/PNP IDs (other than PRP0001) and a valid "compatible" property at the same time. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/scan.c | 249 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 155 insertions(+), 94 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 8f3adf924e83..d2e3c3e3f9c9 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -114,7 +114,12 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, return 0; } -/* +/** + * create_pnp_modalias - Create hid/cid(s) string for modalias and uevent + * @acpi_dev: ACPI device object. + * @modalias: Buffer to print into. + * @size: Size of the buffer. + * * Creates hid/cid(s) string needed for modalias and uevent * e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get: * char *modalias: "acpi:IBM0001:ACPI0001" @@ -122,68 +127,98 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, * -EINVAL: output error * -ENOMEM: output is truncated */ -static int create_modalias(struct acpi_device *acpi_dev, char *modalias, - int size) +static int create_pnp_modalias(struct acpi_device *acpi_dev, char *modalias, + int size) { int len; int count; struct acpi_hardware_id *id; - if (list_empty(&acpi_dev->pnp.ids)) - return 0; - /* - * If the device has PRP0001 we expose DT compatible modalias - * instead in form of of:NnameTCcompatible. + * Since we skip PRP0001 from the modalias below, 0 should be returned + * if PRP0001 is the only ACPI/PNP ID in the device's list. */ - if (acpi_dev->data.of_compatible) { - struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; - const union acpi_object *of_compatible, *obj; - int i, nval; - char *c; - - acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf); - /* DT strings are all in lower case */ - for (c = buf.pointer; *c != '\0'; c++) - *c = tolower(*c); - - len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer); - ACPI_FREE(buf.pointer); - - of_compatible = acpi_dev->data.of_compatible; - if (of_compatible->type == ACPI_TYPE_PACKAGE) { - nval = of_compatible->package.count; - obj = of_compatible->package.elements; - } else { /* Must be ACPI_TYPE_STRING. */ - nval = 1; - obj = of_compatible; - } - for (i = 0; i < nval; i++, obj++) { - count = snprintf(&modalias[len], size, "C%s", - obj->string.pointer); - if (count < 0) - return -EINVAL; - if (count >= size) - return -ENOMEM; - - len += count; - size -= count; - } - } else { - len = snprintf(modalias, size, "acpi:"); - size -= len; + count = 0; + list_for_each_entry(id, &acpi_dev->pnp.ids, list) + if (strcmp(id->id, "PRP0001")) + count++; - list_for_each_entry(id, &acpi_dev->pnp.ids, list) { - count = snprintf(&modalias[len], size, "%s:", id->id); - if (count < 0) - return -EINVAL; - if (count >= size) - return -ENOMEM; - len += count; - size -= count; - } + if (!count) + return 0; + + len = snprintf(modalias, size, "acpi:"); + if (len <= 0) + return len; + + size -= len; + + list_for_each_entry(id, &acpi_dev->pnp.ids, list) { + if (!strcmp(id->id, "PRP0001")) + continue; + + count = snprintf(&modalias[len], size, "%s:", id->id); + if (count < 0) + return -EINVAL; + + if (count >= size) + return -ENOMEM; + + len += count; + size -= count; } + modalias[len] = '\0'; + return len; +} + +/** + * create_of_modalias - Creates DT compatible string for modalias and uevent + * @acpi_dev: ACPI device object. + * @modalias: Buffer to print into. + * @size: Size of the buffer. + * + * Expose DT compatible modalias as of:NnameTCcompatible. This function should + * only be called for devices having PRP0001 in their list of ACPI/PNP IDs. + */ +static int create_of_modalias(struct acpi_device *acpi_dev, char *modalias, + int size) +{ + struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER }; + const union acpi_object *of_compatible, *obj; + int len, count; + int i, nval; + char *c; + acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf); + /* DT strings are all in lower case */ + for (c = buf.pointer; *c != '\0'; c++) + *c = tolower(*c); + + len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer); + ACPI_FREE(buf.pointer); + + if (len <= 0) + return len; + + of_compatible = acpi_dev->data.of_compatible; + if (of_compatible->type == ACPI_TYPE_PACKAGE) { + nval = of_compatible->package.count; + obj = of_compatible->package.elements; + } else { /* Must be ACPI_TYPE_STRING. */ + nval = 1; + obj = of_compatible; + } + for (i = 0; i < nval; i++, obj++) { + count = snprintf(&modalias[len], size, "C%s", + obj->string.pointer); + if (count < 0) + return -EINVAL; + + if (count >= size) + return -ENOMEM; + + len += count; + size -= count; + } modalias[len] = '\0'; return len; } @@ -236,61 +271,100 @@ static struct acpi_device *acpi_companion_match(const struct device *dev) return adev; } -/* - * Creates uevent modalias field for ACPI enumerated devices. - * Because the other buses does not support ACPI HIDs & CIDs. - * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: - * "acpi:IBM0001:ACPI0001" - */ -int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) +static int __acpi_device_uevent_modalias(struct acpi_device *adev, + struct kobj_uevent_env *env) { int len; - if (!acpi_companion_match(dev)) + if (!adev) return -ENODEV; + if (list_empty(&adev->pnp.ids)) + return 0; + if (add_uevent_var(env, "MODALIAS=")) return -ENOMEM; - len = create_modalias(ACPI_COMPANION(dev), &env->buf[env->buflen - 1], - sizeof(env->buf) - env->buflen); - if (len <= 0) + + len = create_pnp_modalias(adev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len < 0) return len; + + env->buflen += len; + if (!adev->data.of_compatible) + return 0; + + if (len > 0 && add_uevent_var(env, "MODALIAS=")) + return -ENOMEM; + + len = create_of_modalias(adev, &env->buf[env->buflen - 1], + sizeof(env->buf) - env->buflen); + if (len < 0) + return len; + env->buflen += len; + return 0; } -EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias); /* - * Creates modalias sysfs attribute for ACPI enumerated devices. + * Creates uevent modalias field for ACPI enumerated devices. * Because the other buses does not support ACPI HIDs & CIDs. * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: * "acpi:IBM0001:ACPI0001" */ -int acpi_device_modalias(struct device *dev, char *buf, int size) +int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) { - int len; + return __acpi_device_uevent_modalias(acpi_companion_match(dev), env); +} +EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias); + +static int __acpi_device_modalias(struct acpi_device *adev, char *buf, int size) +{ + int len, count; - if (!acpi_companion_match(dev)) + if (!adev) return -ENODEV; - len = create_modalias(ACPI_COMPANION(dev), buf, size -1); - if (len <= 0) + if (list_empty(&adev->pnp.ids)) + return 0; + + len = create_pnp_modalias(adev, buf, size - 1); + if (len < 0) { return len; - buf[len++] = '\n'; + } else if (len > 0) { + buf[len++] = '\n'; + size -= len; + } + if (!adev->data.of_compatible) + return len; + + count = create_of_modalias(adev, buf + len, size - 1); + if (count < 0) { + return count; + } else if (count > 0) { + len += count; + buf[len++] = '\n'; + } + return len; } + +/* + * Creates modalias sysfs attribute for ACPI enumerated devices. + * Because the other buses does not support ACPI HIDs & CIDs. + * e.g. for a device with hid:IBM0001 and cid:ACPI0001 you get: + * "acpi:IBM0001:ACPI0001" + */ +int acpi_device_modalias(struct device *dev, char *buf, int size) +{ + return __acpi_device_modalias(acpi_companion_match(dev), buf, size); +} EXPORT_SYMBOL_GPL(acpi_device_modalias); static ssize_t acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - int len; - - len = create_modalias(acpi_dev, buf, 1024); - if (len <= 0) - return len; - buf[len++] = '\n'; - return len; + return __acpi_device_modalias(to_acpi_device(dev), buf, 1024); } static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); @@ -1046,20 +1120,7 @@ static int acpi_bus_match(struct device *dev, struct device_driver *drv) static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) { - struct acpi_device *acpi_dev = to_acpi_device(dev); - int len; - - if (list_empty(&acpi_dev->pnp.ids)) - return 0; - - if (add_uevent_var(env, "MODALIAS=")) - return -ENOMEM; - len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], - sizeof(env->buf) - env->buflen); - if (len <= 0) - return len; - env->buflen += len; - return 0; + return __acpi_device_uevent_modalias(to_acpi_device(dev), env); } static void acpi_device_notify(acpi_handle handle, u32 event, void *data) -- cgit v1.2.3