LinuxKPI: Add acpi_dev_present() function.

acpi_dev_present detects that a given ACPI device is present based on
Hardware ID, Unique ID and Hardware Revision of the device.

Sponsored by:	Serenity Cyber Security, LLC
Reviewed by:	manu
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D42823

(cherry picked from commit 04952a9456e226460d1d95c42ea53861b1133b1a)
This commit is contained in:
Vladimir Kondratyev 2023-12-24 11:20:00 +03:00
parent a87884e34e
commit 455fa56ad4
2 changed files with 83 additions and 0 deletions

View file

@ -37,6 +37,8 @@ struct acpi_bus_event {
uint32_t data;
};
#define acpi_dev_present(...) lkpi_acpi_dev_present(__VA_ARGS__)
ACPI_HANDLE bsd_acpi_get_handle(device_t bsddev);
bool acpi_check_dsm(ACPI_HANDLE handle, const char *uuid, int rev,
uint64_t funcs);
@ -46,5 +48,7 @@ ACPI_OBJECT * acpi_evaluate_dsm_typed(ACPI_HANDLE handle, const char *uuid,
int register_acpi_notifier(struct notifier_block *nb);
int unregister_acpi_notifier(struct notifier_block *nb);
uint32_t acpi_target_system_state(void);
bool lkpi_acpi_dev_present(const char *hid, const char *uid,
int64_t hrv);
#endif /* _LINUXKPI_ACPI_ACPI_BUS_H_ */

View file

@ -174,6 +174,79 @@ acpi_target_system_state(void)
return (linux_acpi_target_sleep_state);
}
struct acpi_dev_present_ctx {
const char *hid;
const char *uid;
int64_t hrv;
};
static ACPI_STATUS
acpi_dev_present_cb(ACPI_HANDLE handle, UINT32 level, void *context,
void **result)
{
ACPI_DEVICE_INFO *devinfo;
struct acpi_dev_present_ctx *match = context;
bool present = false;
UINT32 sta, hrv;
int i;
if (handle == NULL)
return (AE_OK);
if (!ACPI_FAILURE(acpi_GetInteger(handle, "_STA", &sta)) &&
!ACPI_DEVICE_PRESENT(sta))
return (AE_OK);
if (ACPI_FAILURE(AcpiGetObjectInfo(handle, &devinfo)))
return (AE_OK);
if ((devinfo->Valid & ACPI_VALID_HID) != 0 &&
strcmp(match->hid, devinfo->HardwareId.String) == 0) {
present = true;
} else if ((devinfo->Valid & ACPI_VALID_CID) != 0) {
for (i = 0; i < devinfo->CompatibleIdList.Count; i++) {
if (strcmp(match->hid,
devinfo->CompatibleIdList.Ids[i].String) == 0) {
present = true;
break;
}
}
}
if (present && match->uid != NULL &&
((devinfo->Valid & ACPI_VALID_UID) == 0 ||
strcmp(match->uid, devinfo->UniqueId.String) != 0))
present = false;
AcpiOsFree(devinfo);
if (!present)
return (AE_OK);
if (match->hrv != -1) {
if (ACPI_FAILURE(acpi_GetInteger(handle, "_HRV", &hrv)))
return (AE_OK);
if (hrv != match->hrv)
return (AE_OK);
}
return (AE_ERROR);
}
bool
lkpi_acpi_dev_present(const char *hid, const char *uid, int64_t hrv)
{
struct acpi_dev_present_ctx match;
int rv;
match.hid = hid;
match.uid = uid;
match.hrv = hrv;
rv = AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
ACPI_UINT32_MAX, acpi_dev_present_cb, NULL, &match, NULL);
return (rv == AE_ERROR);
}
static void
linux_register_acpi_event_handlers(void *arg __unused)
{
@ -241,4 +314,10 @@ acpi_target_system_state(void)
return (ACPI_STATE_S0);
}
bool
lkpi_acpi_dev_present(const char *hid, const char *uid, int64_t hrv)
{
return (false);
}
#endif /* !DEV_ACPI */