diff options
Diffstat (limited to 'drivers/acpi/scan.c')
| -rw-r--r-- | drivers/acpi/scan.c | 97 |
1 files changed, 60 insertions, 37 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2b6c21d86b98..29ef505c487b 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
| @@ -705,54 +705,85 @@ static int acpi_bus_get_perf_flags(struct acpi_device *device) | |||
| 705 | } | 705 | } |
| 706 | 706 | ||
| 707 | static acpi_status | 707 | static acpi_status |
| 708 | acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device, | 708 | acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, |
| 709 | union acpi_object *package) | 709 | struct acpi_device_wakeup *wakeup) |
| 710 | { | 710 | { |
| 711 | int i = 0; | 711 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
| 712 | union acpi_object *package = NULL; | ||
| 712 | union acpi_object *element = NULL; | 713 | union acpi_object *element = NULL; |
| 714 | acpi_status status; | ||
| 715 | int i = 0; | ||
| 713 | 716 | ||
| 714 | if (!device || !package || (package->package.count < 2)) | 717 | if (!wakeup) |
| 715 | return AE_BAD_PARAMETER; | 718 | return AE_BAD_PARAMETER; |
| 716 | 719 | ||
| 720 | /* _PRW */ | ||
| 721 | status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer); | ||
| 722 | if (ACPI_FAILURE(status)) { | ||
| 723 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); | ||
| 724 | return status; | ||
| 725 | } | ||
| 726 | |||
| 727 | package = (union acpi_object *)buffer.pointer; | ||
| 728 | |||
| 729 | if (!package || (package->package.count < 2)) { | ||
| 730 | status = AE_BAD_DATA; | ||
| 731 | goto out; | ||
| 732 | } | ||
| 733 | |||
| 717 | element = &(package->package.elements[0]); | 734 | element = &(package->package.elements[0]); |
| 718 | if (!element) | 735 | if (!element) { |
| 719 | return AE_BAD_PARAMETER; | 736 | status = AE_BAD_DATA; |
| 737 | goto out; | ||
| 738 | } | ||
| 720 | if (element->type == ACPI_TYPE_PACKAGE) { | 739 | if (element->type == ACPI_TYPE_PACKAGE) { |
| 721 | if ((element->package.count < 2) || | 740 | if ((element->package.count < 2) || |
| 722 | (element->package.elements[0].type != | 741 | (element->package.elements[0].type != |
| 723 | ACPI_TYPE_LOCAL_REFERENCE) | 742 | ACPI_TYPE_LOCAL_REFERENCE) |
| 724 | || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) | 743 | || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) { |
| 725 | return AE_BAD_DATA; | 744 | status = AE_BAD_DATA; |
| 726 | device->wakeup.gpe_device = | 745 | goto out; |
| 746 | } | ||
| 747 | wakeup->gpe_device = | ||
| 727 | element->package.elements[0].reference.handle; | 748 | element->package.elements[0].reference.handle; |
| 728 | device->wakeup.gpe_number = | 749 | wakeup->gpe_number = |
| 729 | (u32) element->package.elements[1].integer.value; | 750 | (u32) element->package.elements[1].integer.value; |
| 730 | } else if (element->type == ACPI_TYPE_INTEGER) { | 751 | } else if (element->type == ACPI_TYPE_INTEGER) { |
| 731 | device->wakeup.gpe_number = element->integer.value; | 752 | wakeup->gpe_device = NULL; |
| 732 | } else | 753 | wakeup->gpe_number = element->integer.value; |
| 733 | return AE_BAD_DATA; | 754 | } else { |
| 755 | status = AE_BAD_DATA; | ||
| 756 | goto out; | ||
| 757 | } | ||
| 734 | 758 | ||
| 735 | element = &(package->package.elements[1]); | 759 | element = &(package->package.elements[1]); |
| 736 | if (element->type != ACPI_TYPE_INTEGER) { | 760 | if (element->type != ACPI_TYPE_INTEGER) { |
| 737 | return AE_BAD_DATA; | 761 | status = AE_BAD_DATA; |
| 762 | goto out; | ||
| 738 | } | 763 | } |
| 739 | device->wakeup.sleep_state = element->integer.value; | 764 | wakeup->sleep_state = element->integer.value; |
| 740 | 765 | ||
| 741 | if ((package->package.count - 2) > ACPI_MAX_HANDLES) { | 766 | if ((package->package.count - 2) > ACPI_MAX_HANDLES) { |
| 742 | return AE_NO_MEMORY; | 767 | status = AE_NO_MEMORY; |
| 768 | goto out; | ||
| 743 | } | 769 | } |
| 744 | device->wakeup.resources.count = package->package.count - 2; | 770 | wakeup->resources.count = package->package.count - 2; |
| 745 | for (i = 0; i < device->wakeup.resources.count; i++) { | 771 | for (i = 0; i < wakeup->resources.count; i++) { |
| 746 | element = &(package->package.elements[i + 2]); | 772 | element = &(package->package.elements[i + 2]); |
| 747 | if (element->type != ACPI_TYPE_LOCAL_REFERENCE) | 773 | if (element->type != ACPI_TYPE_LOCAL_REFERENCE) { |
| 748 | return AE_BAD_DATA; | 774 | status = AE_BAD_DATA; |
| 775 | goto out; | ||
| 776 | } | ||
| 749 | 777 | ||
| 750 | device->wakeup.resources.handles[i] = element->reference.handle; | 778 | wakeup->resources.handles[i] = element->reference.handle; |
| 751 | } | 779 | } |
| 752 | 780 | ||
| 753 | acpi_gpe_can_wake(device->wakeup.gpe_device, device->wakeup.gpe_number); | 781 | acpi_gpe_can_wake(wakeup->gpe_device, wakeup->gpe_number); |
| 754 | 782 | ||
| 755 | return AE_OK; | 783 | out: |
| 784 | kfree(buffer.pointer); | ||
| 785 | |||
| 786 | return status; | ||
| 756 | } | 787 | } |
| 757 | 788 | ||
| 758 | static void acpi_bus_set_run_wake_flags(struct acpi_device *device) | 789 | static void acpi_bus_set_run_wake_flags(struct acpi_device *device) |
| @@ -787,26 +818,15 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) | |||
| 787 | static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) | 818 | static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device) |
| 788 | { | 819 | { |
| 789 | acpi_status status = 0; | 820 | acpi_status status = 0; |
| 790 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
| 791 | union acpi_object *package = NULL; | ||
| 792 | int psw_error; | 821 | int psw_error; |
| 793 | 822 | ||
| 794 | /* _PRW */ | 823 | status = acpi_bus_extract_wakeup_device_power_package(device->handle, |
| 795 | status = acpi_evaluate_object(device->handle, "_PRW", NULL, &buffer); | 824 | &device->wakeup); |
| 796 | if (ACPI_FAILURE(status)) { | ||
| 797 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); | ||
| 798 | goto end; | ||
| 799 | } | ||
| 800 | |||
| 801 | package = (union acpi_object *)buffer.pointer; | ||
| 802 | status = acpi_bus_extract_wakeup_device_power_package(device, package); | ||
| 803 | if (ACPI_FAILURE(status)) { | 825 | if (ACPI_FAILURE(status)) { |
| 804 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); | 826 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); |
| 805 | goto end; | 827 | goto end; |
| 806 | } | 828 | } |
| 807 | 829 | ||
| 808 | kfree(buffer.pointer); | ||
| 809 | |||
| 810 | device->wakeup.flags.valid = 1; | 830 | device->wakeup.flags.valid = 1; |
| 811 | device->wakeup.prepare_count = 0; | 831 | device->wakeup.prepare_count = 0; |
| 812 | acpi_bus_set_run_wake_flags(device); | 832 | acpi_bus_set_run_wake_flags(device); |
| @@ -1351,6 +1371,7 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, | |||
| 1351 | struct acpi_bus_ops *ops = context; | 1371 | struct acpi_bus_ops *ops = context; |
| 1352 | int type; | 1372 | int type; |
| 1353 | unsigned long long sta; | 1373 | unsigned long long sta; |
| 1374 | struct acpi_device_wakeup wakeup; | ||
| 1354 | struct acpi_device *device; | 1375 | struct acpi_device *device; |
| 1355 | acpi_status status; | 1376 | acpi_status status; |
| 1356 | int result; | 1377 | int result; |
| @@ -1360,8 +1381,10 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, | |||
| 1360 | return AE_OK; | 1381 | return AE_OK; |
| 1361 | 1382 | ||
| 1362 | if (!(sta & ACPI_STA_DEVICE_PRESENT) && | 1383 | if (!(sta & ACPI_STA_DEVICE_PRESENT) && |
| 1363 | !(sta & ACPI_STA_DEVICE_FUNCTIONING)) | 1384 | !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { |
| 1385 | acpi_bus_extract_wakeup_device_power_package(handle, &wakeup); | ||
| 1364 | return AE_CTRL_DEPTH; | 1386 | return AE_CTRL_DEPTH; |
| 1387 | } | ||
| 1365 | 1388 | ||
| 1366 | /* | 1389 | /* |
| 1367 | * We may already have an acpi_device from a previous enumeration. If | 1390 | * We may already have an acpi_device from a previous enumeration. If |
