diff options
Diffstat (limited to 'drivers/acpi/utils.c')
-rw-r--r-- | drivers/acpi/utils.c | 103 |
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 | */ | ||
586 | union acpi_object * | ||
587 | acpi_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 | } | ||
623 | EXPORT_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 | */ | ||
637 | bool 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 | } | ||
667 | EXPORT_SYMBOL(acpi_check_dsm); | ||