diff options
author | Hans de Goede <hdegoede@redhat.com> | 2017-04-19 08:02:08 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-04-19 16:53:34 -0400 |
commit | 8661423eea1a1b58417014716e3f1ba286072379 (patch) | |
tree | 686462c9b7444bbc6ae2eb338901deb356c2c98b /drivers/acpi/utils.c | |
parent | 4f7d029b9bf009fbee76bb10c0c4351a1870d2f3 (diff) |
ACPI / utils: Add new acpi_dev_present helper
acpi_dev_found just iterates over all ACPI-ids and sees if one matches.
This means that it will return true for devices which are in the DSDT
but disabled (their _STA method returns 0).
For some drivers it is useful to be able to check if a certain HID
is not only present in the namespace, but also actually present as in
acpi_device_is_present() will return true for the device. For example
because if a certain device is present then the driver will want to use
an extcon or IIO ADC channel provided by that device.
This commit adds a new acpi_dev_present helper which drivers can use
to this end.
Like acpi_dev_found, acpi_dev_present take a HID as argument, but
it also has 2 extra optional arguments to only check for an ACPI
device with a specific UID and/or HRV value. This makes it more
generic and allows it to replace custom code doing similar checks
in several places.
Arguably acpi_dev_present is what acpi_dev_found should have been, but
there are too many users to just change acpi_dev_found without the risk
of breaking something.
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Reviewed-by: Lukas Wunner <lukas@wunner.de>
Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi/utils.c')
-rw-r--r-- | drivers/acpi/utils.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 22c09952e177..27d0dcfcf47d 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c | |||
@@ -736,6 +736,72 @@ bool acpi_dev_found(const char *hid) | |||
736 | } | 736 | } |
737 | EXPORT_SYMBOL(acpi_dev_found); | 737 | EXPORT_SYMBOL(acpi_dev_found); |
738 | 738 | ||
739 | struct acpi_dev_present_info { | ||
740 | struct acpi_device_id hid[2]; | ||
741 | const char *uid; | ||
742 | s64 hrv; | ||
743 | }; | ||
744 | |||
745 | static int acpi_dev_present_cb(struct device *dev, void *data) | ||
746 | { | ||
747 | struct acpi_device *adev = to_acpi_device(dev); | ||
748 | struct acpi_dev_present_info *match = data; | ||
749 | unsigned long long hrv; | ||
750 | acpi_status status; | ||
751 | |||
752 | if (acpi_match_device_ids(adev, match->hid)) | ||
753 | return 0; | ||
754 | |||
755 | if (match->uid && (!adev->pnp.unique_id || | ||
756 | strcmp(adev->pnp.unique_id, match->uid))) | ||
757 | return 0; | ||
758 | |||
759 | if (match->hrv == -1) | ||
760 | return 1; | ||
761 | |||
762 | status = acpi_evaluate_integer(adev->handle, "_HRV", NULL, &hrv); | ||
763 | if (ACPI_FAILURE(status)) | ||
764 | return 0; | ||
765 | |||
766 | return hrv == match->hrv; | ||
767 | } | ||
768 | |||
769 | /** | ||
770 | * acpi_dev_present - Detect that a given ACPI device is present | ||
771 | * @hid: Hardware ID of the device. | ||
772 | * @uid: Unique ID of the device, pass NULL to not check _UID | ||
773 | * @hrv: Hardware Revision of the device, pass -1 to not check _HRV | ||
774 | * | ||
775 | * Return %true if a matching device was present at the moment of invocation. | ||
776 | * Note that if the device is pluggable, it may since have disappeared. | ||
777 | * | ||
778 | * Note that unlike acpi_dev_found() this function checks the status | ||
779 | * of the device. So for devices which are present in the dsdt, but | ||
780 | * which are disabled (their _STA callback returns 0) this function | ||
781 | * will return false. | ||
782 | * | ||
783 | * For this function to work, acpi_bus_scan() must have been executed | ||
784 | * which happens in the subsys_initcall() subsection. Hence, do not | ||
785 | * call from a subsys_initcall() or earlier (use acpi_get_devices() | ||
786 | * instead). Calling from module_init() is fine (which is synonymous | ||
787 | * with device_initcall()). | ||
788 | */ | ||
789 | bool acpi_dev_present(const char *hid, const char *uid, s64 hrv) | ||
790 | { | ||
791 | struct acpi_dev_present_info match = {}; | ||
792 | struct device *dev; | ||
793 | |||
794 | strlcpy(match.hid[0].id, hid, sizeof(match.hid[0].id)); | ||
795 | match.uid = uid; | ||
796 | match.hrv = hrv; | ||
797 | |||
798 | dev = bus_find_device(&acpi_bus_type, NULL, &match, | ||
799 | acpi_dev_present_cb); | ||
800 | |||
801 | return !!dev; | ||
802 | } | ||
803 | EXPORT_SYMBOL(acpi_dev_present); | ||
804 | |||
739 | /* | 805 | /* |
740 | * acpi_backlight= handling, this is done here rather then in video_detect.c | 806 | * acpi_backlight= handling, this is done here rather then in video_detect.c |
741 | * because __setup cannot be used in modules. | 807 | * because __setup cannot be used in modules. |