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