From 3d8e00909df96c2d3eace3996748be9c0a437e5a Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 14 Jan 2014 16:46:35 +0800 Subject: ACPI: fix create_modalias() return value handling Currently, create_modalias() handles the output truncated case in an improper way (return -EINVAL). Plus, acpi_device_uevent() and acpi_device_modalias_show() do improper check for the create_modalias() return value as well. This patch fixes create_modalias() to return -EINVAL if there is an output error, return -ENOMEM if the output is truncated, and also fixes both acpi_device_uevent() and acpi_device_modalias_show() to do proper return value check. Signed-off-by: Zhang Rui Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index fd39459926b1..c92532158195 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -85,6 +85,9 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler, * 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" + * Return: 0: no _HID and no _CID + * -EINVAL: output error + * -ENOMEM: output is truncated */ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, int size) @@ -101,8 +104,10 @@ 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 || count >= size) - return -EINVAL; + if (count < 0) + return EINVAL; + if (count >= size) + return -ENOMEM; len += count; size -= count; } @@ -116,10 +121,9 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha struct acpi_device *acpi_dev = to_acpi_device(dev); int len; - /* Device has no HID and no CID or string is >1024 */ len = create_modalias(acpi_dev, buf, 1024); if (len <= 0) - return 0; + return len; buf[len++] = '\n'; return len; } @@ -782,8 +786,8 @@ static int acpi_device_uevent(struct device *dev, struct kobj_uevent_env *env) return -ENOMEM; len = create_modalias(acpi_dev, &env->buf[env->buflen - 1], sizeof(env->buf) - env->buflen); - if (len >= (sizeof(env->buf) - env->buflen)) - return -ENOMEM; + if (len <= 0) + return len; env->buflen += len; return 0; } -- cgit v1.2.3 From 6eb2451f7c43c4a7f84ae7b613ea975317b951f1 Mon Sep 17 00:00:00 2001 From: Zhang Rui Date: Tue, 14 Jan 2014 16:46:36 +0800 Subject: ACPI: add module autoloading support for ACPI enumerated devices An ACPI enumerated device may have its compatible id strings. To support the compatible ACPI ids (acpi_device->pnp.ids), we introduced acpi_driver_match_device() to match the driver->acpi_match_table and acpi_device->pnp.ids. For those drivers, MODULE_DEVICE_TABLE(acpi, xxx) is used to exports the driver module alias in the format of "acpi:device_compatible_ids". But in the mean time, the current code does not export the ACPI compatible strings as part of the module_alias for the ACPI enumerated devices, which will break the module autoloading. Take the following piece of code for example, static const struct acpi_device_id xxx_acpi_match[] = { { "INTABCD", 0 }, { } }; MODULE_DEVICE_TABLE(acpi, xxx_acpi_match); If this piece of code is used in a platform driver for an ACPI enumerated platform device, the platform driver module_alias is "acpi:INTABCD", but the uevent attribute of its platform device node is "platform:INTABCD:00" (PREFIX:platform_device->name). If this piece of code is used in an i2c driver for an ACPI enumerated i2c device, the i2c driver module_alias is "acpi:INTABCD", but the uevent of its i2c device node is "i2c:INTABCD:00" (PREFIX:i2c_client->name). If this piece of code is used in an spi driver for an ACPI enumerated spi device, the spi driver module_alias is "acpi:INTABCD", but the uevent of its spi device node is "spi:INTABCD" (PREFIX:spi_device->modalias). The reason why the module autoloading is not broken for now is that the uevent file of the ACPI device node is "acpi:INTABCD". Thus it is the ACPI device node creation that loads the platform/i2c/spi driver. So this is a problem that will affect us the day when the ACPI bus is removed from device model. This patch introduces two new APIs, one for exporting ACPI ids in uevent MODALIAS field, and another for exporting ACPI ids in device' modalias sysfs attribute. For any bus that supports ACPI enumerated devices, it needs to invoke these two functions for their uevent and modalias attribute. Signed-off-by: Zhang Rui Reviewed-by: Mika Westerberg Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'drivers/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index c92532158195..680bb5647701 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -116,6 +116,63 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias, return len; } +/* + * 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) +{ + 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)) + return -ENODEV; + + 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; +} +EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias); + +/* + * 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) +{ + 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)) + return -ENODEV; + + len = create_modalias(acpi_dev, buf, size -1); + if (len <= 0) + return len; + buf[len++] = '\n'; + return len; +} +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); -- cgit v1.2.3