mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 14:41:39 +00:00
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:
parent
c2efefb33a
commit
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);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
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
|
||||
-------------------------------------------------------------------------- */
|
||||
|
@ -115,55 +115,6 @@ int acpi_scan_add_handler_with_hotplug(struct acpi_scan_handler *handler,
|
||||
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)
|
||||
{
|
||||
@ -497,146 +448,6 @@ void acpi_device_hotplug(struct acpi_device *adev, u32 src)
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
|
Loading…
Reference in New Issue
Block a user