diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -52,6 +52,7 @@ #include #include #include +#include #if defined(__i386__) || defined(__amd64__) #include @@ -147,10 +148,13 @@ 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 @@ /* 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), @@ -296,6 +301,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. @@ -1727,6 +1741,82 @@ 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_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 --- a/sys/dev/acpica/acpi_if.m +++ b/sys/dev/acpica/acpi_if.m @@ -121,6 +121,27 @@ ACPI_BUFFER *ret; }; +# +# 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 diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -90,6 +90,9 @@ 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_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 @@ #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);