aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/utils.c')
-rw-r--r--drivers/acpi/utils.c103
1 files changed, 97 insertions, 6 deletions
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 6d408bfbbb1d..85e3b612bdc0 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -30,8 +30,6 @@
30#include <linux/types.h> 30#include <linux/types.h>
31#include <linux/hardirq.h> 31#include <linux/hardirq.h>
32#include <linux/acpi.h> 32#include <linux/acpi.h>
33#include <acpi/acpi_bus.h>
34#include <acpi/acpi_drivers.h>
35 33
36#include "internal.h" 34#include "internal.h"
37 35
@@ -101,10 +99,6 @@ acpi_extract_package(union acpi_object *package,
101 99
102 union acpi_object *element = &(package->package.elements[i]); 100 union acpi_object *element = &(package->package.elements[i]);
103 101
104 if (!element) {
105 return AE_BAD_DATA;
106 }
107
108 switch (element->type) { 102 switch (element->type) {
109 103
110 case ACPI_TYPE_INTEGER: 104 case ACPI_TYPE_INTEGER:
@@ -574,3 +568,100 @@ acpi_status acpi_evaluate_lck(acpi_handle handle, int lock)
574 568
575 return status; 569 return status;
576} 570}
571
572/**
573 * acpi_evaluate_dsm - evaluate device's _DSM method
574 * @handle: ACPI device handle
575 * @uuid: UUID of requested functions, should be 16 bytes
576 * @rev: revision number of requested function
577 * @func: requested function number
578 * @argv4: the function specific parameter
579 *
580 * Evaluate device's _DSM method with specified UUID, revision id and
581 * function number. Caller needs to free the returned object.
582 *
583 * Though ACPI defines the fourth parameter for _DSM should be a package,
584 * some old BIOSes do expect a buffer or an integer etc.
585 */
586union acpi_object *
587acpi_evaluate_dsm(acpi_handle handle, const u8 *uuid, int rev, int func,
588 union acpi_object *argv4)
589{
590 acpi_status ret;
591 struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
592 union acpi_object params[4];
593 struct acpi_object_list input = {
594 .count = 4,
595 .pointer = params,
596 };
597
598 params[0].type = ACPI_TYPE_BUFFER;
599 params[0].buffer.length = 16;
600 params[0].buffer.pointer = (char *)uuid;
601 params[1].type = ACPI_TYPE_INTEGER;
602 params[1].integer.value = rev;
603 params[2].type = ACPI_TYPE_INTEGER;
604 params[2].integer.value = func;
605 if (argv4) {
606 params[3] = *argv4;
607 } else {
608 params[3].type = ACPI_TYPE_PACKAGE;
609 params[3].package.count = 0;
610 params[3].package.elements = NULL;
611 }
612
613 ret = acpi_evaluate_object(handle, "_DSM", &input, &buf);
614 if (ACPI_SUCCESS(ret))
615 return (union acpi_object *)buf.pointer;
616
617 if (ret != AE_NOT_FOUND)
618 acpi_handle_warn(handle,
619 "failed to evaluate _DSM (0x%x)\n", ret);
620
621 return NULL;
622}
623EXPORT_SYMBOL(acpi_evaluate_dsm);
624
625/**
626 * acpi_check_dsm - check if _DSM method supports requested functions.
627 * @handle: ACPI device handle
628 * @uuid: UUID of requested functions, should be 16 bytes at least
629 * @rev: revision number of requested functions
630 * @funcs: bitmap of requested functions
631 * @exclude: excluding special value, used to support i915 and nouveau
632 *
633 * Evaluate device's _DSM method to check whether it supports requested
634 * functions. Currently only support 64 functions at maximum, should be
635 * enough for now.
636 */
637bool acpi_check_dsm(acpi_handle handle, const u8 *uuid, int rev, u64 funcs)
638{
639 int i;
640 u64 mask = 0;
641 union acpi_object *obj;
642
643 if (funcs == 0)
644 return false;
645
646 obj = acpi_evaluate_dsm(handle, uuid, rev, 0, NULL);
647 if (!obj)
648 return false;
649
650 /* For compatibility, old BIOSes may return an integer */
651 if (obj->type == ACPI_TYPE_INTEGER)
652 mask = obj->integer.value;
653 else if (obj->type == ACPI_TYPE_BUFFER)
654 for (i = 0; i < obj->buffer.length && i < 8; i++)
655 mask |= (((u8)obj->buffer.pointer[i]) << (i * 8));
656 ACPI_FREE(obj);
657
658 /*
659 * Bit 0 indicates whether there's support for any functions other than
660 * function 0 for the specified UUID and revision.
661 */
662 if ((mask & 0x1) && (mask & funcs) == funcs)
663 return true;
664
665 return false;
666}
667EXPORT_SYMBOL(acpi_check_dsm);