ACPI / scan: Move device matching code to bus.c
To reduce the size of scan.c and improve the readability of it, move code related device matching into drivers/acpi/bus.c. Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Родитель
c2efefb33a
Коммит
68c6b148da
|
@ -423,6 +423,200 @@ static void acpi_bus_notify(acpi_handle handle, u32 type, void *data)
|
||||||
acpi_evaluate_ost(handle, type, ost_code, NULL);
|
acpi_evaluate_ost(handle, type, ost_code, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------------------------------------------
|
||||||
|
Device Matching
|
||||||
|
-------------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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. 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
|
||||||
|
* 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).
|
||||||
|
*/
|
||||||
|
struct acpi_device *acpi_companion_match(const struct device *dev)
|
||||||
|
{
|
||||||
|
struct acpi_device *adev;
|
||||||
|
struct mutex *physical_node_lock;
|
||||||
|
|
||||||
|
adev = ACPI_COMPANION(dev);
|
||||||
|
if (!adev)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (list_empty(&adev->pnp.ids))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
physical_node_lock = &adev->physical_node_lock;
|
||||||
|
mutex_lock(physical_node_lock);
|
||||||
|
if (list_empty(&adev->physical_node_list)) {
|
||||||
|
adev = NULL;
|
||||||
|
} else {
|
||||||
|
const struct acpi_device_physical_node *node;
|
||||||
|
|
||||||
|
node = list_first_entry(&adev->physical_node_list,
|
||||||
|
struct acpi_device_physical_node, node);
|
||||||
|
if (node->dev != dev)
|
||||||
|
adev = NULL;
|
||||||
|
}
|
||||||
|
mutex_unlock(physical_node_lock);
|
||||||
|
|
||||||
|
return adev;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ACPI_DT_NAMESPACE_HID 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 bool __acpi_match_device_cls(const struct acpi_device_id *id,
|
||||||
|
struct acpi_hardware_id *hwid)
|
||||||
|
{
|
||||||
|
int i, msk, byte_shift;
|
||||||
|
char buf[3];
|
||||||
|
|
||||||
|
if (!id->cls)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Apply class-code bitmask, before checking each class-code byte */
|
||||||
|
for (i = 1; i <= 3; i++) {
|
||||||
|
byte_shift = 8 * (3 - i);
|
||||||
|
msk = (id->cls_msk >> byte_shift) & 0xFF;
|
||||||
|
if (!msk)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
sprintf(buf, "%02x", (id->cls >> byte_shift) & msk);
|
||||||
|
if (strncmp(buf, &hwid->id[(i - 1) * 2], 2))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct acpi_device_id *__acpi_match_device(
|
||||||
|
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;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the device is not present, it is unnecessary to load device
|
||||||
|
* driver for it.
|
||||||
|
*/
|
||||||
|
if (!device || !device->status.present)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
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->cls; id++) {
|
||||||
|
if (id->id[0] && !strcmp((char *) id->id, hwid->id))
|
||||||
|
return id;
|
||||||
|
else if (id->cls && __acpi_match_device_cls(id, hwid))
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Next, check ACPI_DT_NAMESPACE_HID 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(ACPI_DT_NAMESPACE_HID, hwid->id)
|
||||||
|
&& acpi_of_match_device(device, of_ids))
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* acpi_match_device - Match a struct device against a given list of ACPI IDs
|
||||||
|
* @ids: Array of struct acpi_device_id object to match against.
|
||||||
|
* @dev: The device structure to match.
|
||||||
|
*
|
||||||
|
* Check if @dev has a valid ACPI handle and if there is a struct acpi_device
|
||||||
|
* object for that handle and use that object to match against a given list of
|
||||||
|
* device IDs.
|
||||||
|
*
|
||||||
|
* Return a pointer to the first matching ID on success or %NULL on failure.
|
||||||
|
*/
|
||||||
|
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, 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, NULL) ? 0 : -ENOENT;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(acpi_match_device_ids);
|
||||||
|
|
||||||
|
bool acpi_driver_match_device(struct device *dev,
|
||||||
|
const struct device_driver *drv)
|
||||||
|
{
|
||||||
|
if (!drv->acpi_match_table)
|
||||||
|
return acpi_of_match_device(ACPI_COMPANION(dev),
|
||||||
|
drv->of_match_table);
|
||||||
|
|
||||||
|
return !!__acpi_match_device(acpi_companion_match(dev),
|
||||||
|
drv->acpi_match_table, drv->of_match_table);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(acpi_driver_match_device);
|
||||||
|
|
||||||
/* --------------------------------------------------------------------------
|
/* --------------------------------------------------------------------------
|
||||||
Initialization/Cleanup
|
Initialization/Cleanup
|
||||||
-------------------------------------------------------------------------- */
|
-------------------------------------------------------------------------- */
|
||||||
|
|
|
@ -115,55 +115,6 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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. 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
|
|
||||||
* 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).
|
|
||||||
*/
|
|
||||||
struct acpi_device *acpi_companion_match(const struct device *dev)
|
|
||||||
{
|
|
||||||
struct acpi_device *adev;
|
|
||||||
struct mutex *physical_node_lock;
|
|
||||||
|
|
||||||
adev = ACPI_COMPANION(dev);
|
|
||||||
if (!adev)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (list_empty(&adev->pnp.ids))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
physical_node_lock = &adev->physical_node_lock;
|
|
||||||
mutex_lock(physical_node_lock);
|
|
||||||
if (list_empty(&adev->physical_node_list)) {
|
|
||||||
adev = NULL;
|
|
||||||
} else {
|
|
||||||
const struct acpi_device_physical_node *node;
|
|
||||||
|
|
||||||
node = list_first_entry(&adev->physical_node_list,
|
|
||||||
struct acpi_device_physical_node, node);
|
|
||||||
if (node->dev != dev)
|
|
||||||
adev = NULL;
|
|
||||||
}
|
|
||||||
mutex_unlock(physical_node_lock);
|
|
||||||
|
|
||||||
return adev;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent)
|
bool acpi_scan_is_offline(struct acpi_device *adev, bool uevent)
|
||||||
{
|
{
|
||||||
|
@ -497,146 +448,6 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src)
|
||||||
ACPI Bus operations
|
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 ACPI_DT_NAMESPACE_HID 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 bool __acpi_match_device_cls(const struct acpi_device_id *id,
|
|
||||||
struct acpi_hardware_id *hwid)
|
|
||||||
{
|
|
||||||
int i, msk, byte_shift;
|
|
||||||
char buf[3];
|
|
||||||
|
|
||||||
if (!id->cls)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Apply class-code bitmask, before checking each class-code byte */
|
|
||||||
for (i = 1; i <= 3; i++) {
|
|
||||||
byte_shift = 8 * (3 - i);
|
|
||||||
msk = (id->cls_msk >> byte_shift) & 0xFF;
|
|
||||||
if (!msk)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
sprintf(buf, "%02x", (id->cls >> byte_shift) & msk);
|
|
||||||
if (strncmp(buf, &hwid->id[(i - 1) * 2], 2))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct acpi_device_id *__acpi_match_device(
|
|
||||||
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;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If the device is not present, it is unnecessary to load device
|
|
||||||
* driver for it.
|
|
||||||
*/
|
|
||||||
if (!device || !device->status.present)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
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->cls; id++) {
|
|
||||||
if (id->id[0] && !strcmp((char *) id->id, hwid->id))
|
|
||||||
return id;
|
|
||||||
else if (id->cls && __acpi_match_device_cls(id, hwid))
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Next, check ACPI_DT_NAMESPACE_HID 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(ACPI_DT_NAMESPACE_HID, hwid->id)
|
|
||||||
&& acpi_of_match_device(device, of_ids))
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* acpi_match_device - Match a struct device against a given list of ACPI IDs
|
|
||||||
* @ids: Array of struct acpi_device_id object to match against.
|
|
||||||
* @dev: The device structure to match.
|
|
||||||
*
|
|
||||||
* Check if @dev has a valid ACPI handle and if there is a struct acpi_device
|
|
||||||
* object for that handle and use that object to match against a given list of
|
|
||||||
* device IDs.
|
|
||||||
*
|
|
||||||
* Return a pointer to the first matching ID on success or %NULL on failure.
|
|
||||||
*/
|
|
||||||
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, 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, NULL) ? 0 : -ENOENT;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL(acpi_match_device_ids);
|
|
||||||
|
|
||||||
bool acpi_driver_match_device(struct device *dev,
|
|
||||||
const struct device_driver *drv)
|
|
||||||
{
|
|
||||||
if (!drv->acpi_match_table)
|
|
||||||
return acpi_of_match_device(ACPI_COMPANION(dev),
|
|
||||||
drv->of_match_table);
|
|
||||||
|
|
||||||
return !!__acpi_match_device(acpi_companion_match(dev),
|
|
||||||
drv->acpi_match_table, drv->of_match_table);
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(acpi_driver_match_device);
|
|
||||||
|
|
||||||
static void acpi_free_power_resources_lists(struct acpi_device *device)
|
static void acpi_free_power_resources_lists(struct acpi_device *device)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче