mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-18 01:34:14 +08:00
Merge branch 'acpi-scan'
* acpi-scan: ACPI / scan: Rework modalias creation when "compatible" is present ACPI / scan: Take the PRP0001 position in the list of IDs into account ACPI / scan: Simplify acpi_match_device() ACPI / scan: Generalize of_compatible matching ACPI / scan: fix fixed event handler return value
This commit is contained in:
commit
1a7fd41ac2
@ -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))
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
count = 0;
|
||||
list_for_each_entry(id, &acpi_dev->pnp.ids, list)
|
||||
if (strcmp(id->id, "PRP0001"))
|
||||
count++;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If the device has PRP0001 we expose DT compatible modalias
|
||||
* instead in form of of:NnameTCcompatible.
|
||||
*/
|
||||
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;
|
||||
len = snprintf(modalias, size, "acpi:");
|
||||
if (len <= 0)
|
||||
return len;
|
||||
|
||||
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);
|
||||
size -= len;
|
||||
|
||||
len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
|
||||
ACPI_FREE(buf.pointer);
|
||||
list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
|
||||
if (!strcmp(id->id, "PRP0001"))
|
||||
continue;
|
||||
|
||||
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;
|
||||
count = snprintf(&modalias[len], size, "%s:", id->id);
|
||||
if (count < 0)
|
||||
return -EINVAL;
|
||||
|
||||
len += count;
|
||||
size -= count;
|
||||
}
|
||||
} else {
|
||||
len = snprintf(modalias, size, "acpi:");
|
||||
size -= len;
|
||||
if (count >= size)
|
||||
return -ENOMEM;
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
@ -194,7 +229,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 +244,67 @@ 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;
|
||||
}
|
||||
|
||||
static int __acpi_device_uevent_modalias(struct acpi_device *adev,
|
||||
struct kobj_uevent_env *env)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (!adev)
|
||||
return -ENODEV;
|
||||
|
||||
if (list_empty(&adev->pnp.ids))
|
||||
return 0;
|
||||
|
||||
if (add_uevent_var(env, "MODALIAS="))
|
||||
return -ENOMEM;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -243,22 +315,41 @@ static bool acpi_companion_match(const struct device *dev)
|
||||
*/
|
||||
int acpi_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (!acpi_companion_match(dev))
|
||||
return -ENODEV;
|
||||
|
||||
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)
|
||||
return len;
|
||||
env->buflen += len;
|
||||
return 0;
|
||||
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 (!adev)
|
||||
return -ENODEV;
|
||||
|
||||
if (list_empty(&adev->pnp.ids))
|
||||
return 0;
|
||||
|
||||
len = create_pnp_modalias(adev, buf, size - 1);
|
||||
if (len < 0) {
|
||||
return len;
|
||||
} 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.
|
||||
@ -267,29 +358,13 @@ EXPORT_SYMBOL_GPL(acpi_device_uevent_modalias);
|
||||
*/
|
||||
int acpi_device_modalias(struct device *dev, char *buf, int size)
|
||||
{
|
||||
int len;
|
||||
|
||||
if (!acpi_companion_match(dev))
|
||||
return -ENODEV;
|
||||
|
||||
len = create_modalias(ACPI_COMPANION(dev), buf, size -1);
|
||||
if (len <= 0)
|
||||
return len;
|
||||
buf[len++] = '\n';
|
||||
return len;
|
||||
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);
|
||||
|
||||
@ -894,8 +969,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;
|
||||
@ -904,14 +1022,27 @@ 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++)
|
||||
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;
|
||||
}
|
||||
|
||||
@ -929,68 +1060,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)
|
||||
{
|
||||
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, 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);
|
||||
|
||||
/* Performs match against special "PRP0001" shoehorn ACPI ID */
|
||||
static bool acpi_of_driver_match_device(struct device *dev,
|
||||
const struct device_driver *drv)
|
||||
{
|
||||
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 (!drv->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 = drv->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_driver_match_device(dev, drv);
|
||||
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);
|
||||
|
||||
@ -1031,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)
|
||||
@ -1062,10 +1138,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)
|
||||
|
Loading…
Reference in New Issue
Block a user