diff options
Diffstat (limited to 'drivers/acpi/utils.c')
| -rw-r--r-- | drivers/acpi/utils.c | 122 |
1 files changed, 103 insertions, 19 deletions
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c index 6d408bfbbb1d..bba526148583 100644 --- a/drivers/acpi/utils.c +++ b/drivers/acpi/utils.c @@ -30,8 +30,6 @@ #include <linux/types.h> #include <linux/hardirq.h> #include <linux/acpi.h> -#include <acpi/acpi_bus.h> -#include <acpi/acpi_drivers.h> #include "internal.h" @@ -101,10 +99,6 @@ acpi_extract_package(union acpi_object *package, union acpi_object *element = &(package->package.elements[i]); - if (!element) { - return AE_BAD_DATA; - } - switch (element->type) { case ACPI_TYPE_INTEGER: @@ -170,11 +164,10 @@ acpi_extract_package(union acpi_object *package, * Validate output buffer. */ if (buffer->length == ACPI_ALLOCATE_BUFFER) { - buffer->pointer = ACPI_ALLOCATE(size_required); + buffer->pointer = ACPI_ALLOCATE_ZEROED(size_required); if (!buffer->pointer) return AE_NO_MEMORY; buffer->length = size_required; - memset(buffer->pointer, 0, size_required); } else { if (buffer->length < size_required) { buffer->length = size_required; @@ -428,7 +421,7 @@ out: EXPORT_SYMBOL(acpi_get_physical_device_location); /** - * acpi_evaluate_hotplug_ost: Evaluate _OST for hotplug operations + * acpi_evaluate_ost: Evaluate _OST for hotplug operations * @handle: ACPI device handle * @source_event: source event code * @status_code: status code @@ -439,17 +432,15 @@ EXPORT_SYMBOL(acpi_get_physical_device_location); * When the platform does not support _OST, this function has no effect. */ acpi_status -acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event, - u32 status_code, struct acpi_buffer *status_buf) +acpi_evaluate_ost(acpi_handle handle, u32 source_event, u32 status_code, + struct acpi_buffer *status_buf) { -#ifdef ACPI_HOTPLUG_OST union acpi_object params[3] = { {.type = ACPI_TYPE_INTEGER,}, {.type = ACPI_TYPE_INTEGER,}, {.type = ACPI_TYPE_BUFFER,} }; struct acpi_object_list arg_list = {3, params}; - acpi_status status; params[0].integer.value = source_event; params[1].integer.value = status_code; @@ -461,13 +452,9 @@ acpi_evaluate_hotplug_ost(acpi_handle handle, u32 source_event, params[2].buffer.length = 0; } - status = acpi_evaluate_object(handle, "_OST", &arg_list, NULL); - return status; -#else - return AE_OK; -#endif + return acpi_evaluate_object(handle, "_OST", &arg_list, NULL); } -EXPORT_SYMBOL(acpi_evaluate_hotplug_ost); +EXPORT_SYMBOL(acpi_evaluate_ost); /** * acpi_handle_printk: Print message with ACPI prefix and object path @@ -574,3 +561,100 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock) return status; } + +/** + * acpi_evaluate_dsm - evaluate device's _DSM method + * @handle: ACPI device handle + * @uuid: UUID of requested functions, should be 16 bytes + * @rev: revision number of requested function + * @func: requested function number + * @argv4: the function specific parameter + * + * Evaluate device's _DSM method with specified UUID, revision id and + * function number. Caller needs to free the returned object. + * + * Though ACPI defines the fourth parameter for _DSM should be a package, + * some old BIOSes do expect a buffer or an integer etc. + */ +union acpi_object * +acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, int rev, int func, + union acpi_object *argv4) +{ + acpi_status ret; + struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL}; + union acpi_object params[4]; + struct acpi_object_list input = { + .count = 4, + .pointer = params, + }; + + params[0].type = ACPI_TYPE_BUFFER; + params[0].buffer.length = 16; + params[0].buffer.pointer = (char *)uuid; + params[1].type = ACPI_TYPE_INTEGER; + params[1].integer.value = rev; + params[2].type = ACPI_TYPE_INTEGER; + params[2].integer.value = func; + if (argv4) { + params[3] = *argv4; + } else { + params[3].type = ACPI_TYPE_PACKAGE; + params[3].package.count = 0; + params[3].package.elements = NULL; + } + + ret = acpi_evaluate_object(handle, "_DSM", &input, &buf); + if (ACPI_SUCCESS(ret)) + return (union acpi_object *)buf.pointer; + + if (ret != AE_NOT_FOUND) + acpi_handle_warn(handle, + "failed to evaluate _DSM (0x%x)\n", ret); + + return NULL; +} +EXPORT_SYMBOL(acpi_evaluate_dsm); + +/** + * acpi_check_dsm - check if _DSM method supports requested functions. + * @handle: ACPI device handle + * @uuid: UUID of requested functions, should be 16 bytes at least + * @rev: revision number of requested functions + * @funcs: bitmap of requested functions + * @exclude: excluding special value, used to support i915 and nouveau + * + * Evaluate device's _DSM method to check whether it supports requested + * functions. Currently only support 64 functions at maximum, should be + * enough for now. + */ +bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs) +{ + int i; + u64 mask = 0; + union acpi_object *obj; + + if (funcs == 0) + return false; + + obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL); + if (!obj) + return false; + + /* For compatibility, old BIOSes may return an integer */ + if (obj->type == ACPI_TYPE_INTEGER) + mask = obj->integer.value; + else if (obj->type == ACPI_TYPE_BUFFER) + for (i = 0; i < obj->buffer.length && i < 8; i++) + mask |= (((u8)obj->buffer.pointer[i]) << (i * 8)); + ACPI_FREE(obj); + + /* + * Bit 0 indicates whether there's support for any functions other than + * function 0 for the specified UUID and revision. + */ + if ((mask & 0x1) && (mask & funcs) == funcs) + return true; + + return false; +} +EXPORT_SYMBOL(acpi_check_dsm); |
