aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartlomiej Grzesik <bag@semihalf.com>2021-07-27 12:39:31 +0000
committerMarcin Wojtas <mw@FreeBSD.org>2021-09-20 14:31:08 +0000
commitb91fc6c43a81d3b760fb570c8439a922e536d7e6 (patch)
treedd98835e3ce6ecec6eb247c22baab1ef6ba4171c
parent34b1efcea19dd4324eecd19d2de313d039fd9656 (diff)
downloadsrc-b91fc6c43a81d3b760fb570c8439a922e536d7e6.tar.gz
src-b91fc6c43a81d3b760fb570c8439a922e536d7e6.zip
acpica: add ACPI_GET_PROPERTY to access Device Specific Data (DSD)
Add lazy acquiring of DSD package, which allows accessing Device Specific Data. Reviewed by: manu, mw Sponsored by: Semihalf Differential revision: https://reviews.freebsd.org/D31596
-rw-r--r--sys/dev/acpica/acpi.c99
-rw-r--r--sys/dev/acpica/acpi_if.m21
-rw-r--r--sys/dev/acpica/acpivar.h12
3 files changed, 132 insertions, 0 deletions
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 02358d407c66..40b928f9cdd6 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -52,6 +52,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sched.h>
#include <sys/smp.h>
#include <sys/timetc.h>
+#include <sys/uuid.h>
#if defined(__i386__) || defined(__amd64__)
#include <machine/clock.h>
@@ -147,10 +148,13 @@ static int acpi_device_id_probe(device_t bus, device_t dev, char **ids, char **m
static ACPI_STATUS acpi_device_eval_obj(device_t bus, device_t dev,
ACPI_STRING pathname, ACPI_OBJECT_LIST *parameters,
ACPI_BUFFER *ret);
+static ACPI_STATUS acpi_device_get_prop(device_t bus, device_t dev,
+ ACPI_STRING propname, const ACPI_OBJECT **value);
static ACPI_STATUS acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level,
void *context, void **retval);
static ACPI_STATUS acpi_device_scan_children(device_t bus, device_t dev,
int max_depth, acpi_scan_cb_t user_fn, void *arg);
+static ACPI_STATUS acpi_find_dsd(device_t bus, device_t dev);
static int acpi_isa_pnp_probe(device_t bus, device_t child,
struct isa_pnp_id *ids);
static void acpi_platform_osc(device_t dev);
@@ -223,6 +227,7 @@ static device_method_t acpi_methods[] = {
/* ACPI bus */
DEVMETHOD(acpi_id_probe, acpi_device_id_probe),
DEVMETHOD(acpi_evaluate_object, acpi_device_eval_obj),
+ DEVMETHOD(acpi_get_property, acpi_device_get_prop),
DEVMETHOD(acpi_pwr_for_sleep, acpi_device_pwr_for_sleep),
DEVMETHOD(acpi_scan_children, acpi_device_scan_children),
@@ -297,6 +302,15 @@ SYSCTL_INT(_debug_acpi, OID_AUTO, suspend_bounce, CTLFLAG_RW,
&acpi_susp_bounce, 0, "Don't actually suspend, just test devices.");
/*
+ * ACPI standard UUID for Device Specific Data Package
+ * "Device Properties UUID for _DSD" Rev. 2.0
+ */
+static const struct uuid acpi_dsd_uuid = {
+ 0xdaffd814, 0x6eba, 0x4d8c, 0x8a, 0x91,
+ { 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01 }
+};
+
+/*
* ACPI can only be loaded as a module by the loader; activating it after
* system bootstrap time is not useful, and can be fatal to the system.
* It also cannot be unloaded, since the entire system bus hierarchy hangs
@@ -1727,6 +1741,82 @@ acpi_device_eval_obj(device_t bus, device_t dev, ACPI_STRING pathname,
return (AcpiEvaluateObject(h, pathname, parameters, ret));
}
+static ACPI_STATUS
+acpi_device_get_prop(device_t bus, device_t dev, ACPI_STRING propname,
+ const ACPI_OBJECT **value)
+{
+ const ACPI_OBJECT *pkg, *name, *val;
+ struct acpi_device *ad;
+ ACPI_STATUS status;
+ int i;
+
+ ad = device_get_ivars(dev);
+
+ if (ad == NULL || propname == NULL)
+ return (AE_BAD_PARAMETER);
+ if (ad->dsd_pkg == NULL) {
+ if (ad->dsd.Pointer == NULL) {
+ status = acpi_find_dsd(bus, dev);
+ if (ACPI_FAILURE(status))
+ return (status);
+ } else {
+ return (AE_NOT_FOUND);
+ }
+ }
+
+ for (i = 0; i < ad->dsd_pkg->Package.Count; i ++) {
+ pkg = &ad->dsd_pkg->Package.Elements[i];
+ if (pkg->Type != ACPI_TYPE_PACKAGE || pkg->Package.Count != 2)
+ continue;
+
+ name = &pkg->Package.Elements[0];
+ val = &pkg->Package.Elements[1];
+ if (name->Type != ACPI_TYPE_STRING)
+ continue;
+ if (strncmp(propname, name->String.Pointer, name->String.Length) == 0) {
+ if (value != NULL)
+ *value = val;
+
+ return (AE_OK);
+ }
+ }
+
+ return (AE_NOT_FOUND);
+}
+
+static ACPI_STATUS
+acpi_find_dsd(device_t bus, device_t dev)
+{
+ const ACPI_OBJECT *dsd, *guid, *pkg;
+ struct acpi_device *ad;
+ ACPI_STATUS status;
+
+ ad = device_get_ivars(dev);
+ ad->dsd.Length = ACPI_ALLOCATE_BUFFER;
+ ad->dsd.Pointer = NULL;
+ ad->dsd_pkg = NULL;
+
+ status = ACPI_EVALUATE_OBJECT(bus, dev, "_DSD", NULL, &ad->dsd);
+ if (ACPI_FAILURE(status))
+ return (status);
+
+ dsd = ad->dsd.Pointer;
+ guid = &dsd->Package.Elements[0];
+ pkg = &dsd->Package.Elements[1];
+
+ if (guid->Type != ACPI_TYPE_BUFFER || pkg->Type != ACPI_TYPE_PACKAGE ||
+ guid->Buffer.Length != sizeof(acpi_dsd_uuid))
+ return (AE_NOT_FOUND);
+ if (memcmp(guid->Buffer.Pointer, &acpi_dsd_uuid,
+ sizeof(acpi_dsd_uuid)) == 0) {
+
+ ad->dsd_pkg = pkg;
+ return (AE_OK);
+ }
+
+ return (AE_NOT_FOUND);
+}
+
int
acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate)
{
@@ -2399,6 +2489,15 @@ acpi_GetHandleInScope(ACPI_HANDLE parent, char *path, ACPI_HANDLE *result)
}
}
+ACPI_STATUS
+acpi_GetProperty(device_t dev, ACPI_STRING propname,
+ const ACPI_OBJECT **value)
+{
+ device_t bus = device_get_parent(dev);
+
+ return (ACPI_GET_PROPERTY(bus, dev, propname, value));
+}
+
/*
* Allocate a buffer with a preset data size.
*/
diff --git a/sys/dev/acpica/acpi_if.m b/sys/dev/acpica/acpi_if.m
index 6e36f398411e..e0ed4d72e899 100644
--- a/sys/dev/acpica/acpi_if.m
+++ b/sys/dev/acpica/acpi_if.m
@@ -122,6 +122,27 @@ METHOD ACPI_STATUS evaluate_object {
};
#
+# Get property value from Device Specific Data
+#
+# device_t bus: parent bus for the device
+#
+# device_t dev: find property for this device's handle.
+#
+# const ACPI_STRING propname: name of the property
+#
+# const ACPI_OBJECT **value: property value output
+# Specify NULL if ignored
+#
+# Returns: AE_OK or an error value
+#
+METHOD ACPI_STATUS get_property {
+ device_t bus;
+ device_t dev;
+ ACPI_STRING propname;
+ const ACPI_OBJECT **value;
+};
+
+#
# Get the highest power state (D0-D3) that is usable for a device when
# suspending/resuming. If a bus calls this when suspending a device, it
# must also call it when resuming.
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index 1f64b479d414..e276193aebc0 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -90,6 +90,9 @@ struct acpi_device {
int ad_flags;
int ad_cls_class;
+ ACPI_BUFFER dsd; /* Device Specific Data */
+ const ACPI_OBJECT *dsd_pkg;
+
/* Resources */
struct resource_list ad_rl;
};
@@ -350,6 +353,8 @@ BOOLEAN acpi_DeviceIsPresent(device_t dev);
BOOLEAN acpi_BatteryIsPresent(device_t dev);
ACPI_STATUS acpi_GetHandleInScope(ACPI_HANDLE parent, char *path,
ACPI_HANDLE *result);
+ACPI_STATUS acpi_GetProperty(device_t dev, ACPI_STRING propname,
+ const ACPI_OBJECT **value);
ACPI_BUFFER *acpi_AllocBuffer(int size);
ACPI_STATUS acpi_ConvertBufferToInteger(ACPI_BUFFER *bufp,
UINT32 *number);
@@ -396,6 +401,13 @@ int acpi_MatchHid(ACPI_HANDLE h, const char *hid);
#define ACPI_MATCHHID_HID 1
#define ACPI_MATCHHID_CID 2
+static __inline bool
+acpi_HasProperty(device_t dev, ACPI_STRING propname)
+{
+
+ return ACPI_SUCCESS(acpi_GetProperty(dev, propname, NULL));
+}
+
struct acpi_parse_resource_set {
void (*set_init)(device_t dev, void *arg, void **context);
void (*set_done)(device_t dev, void *context);