diff options
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 130 |
1 files changed, 86 insertions, 44 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 2b6c21d86b98..64d4da0d6d52 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_setup_gpe_for_wake(handle, 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) |
@@ -772,7 +803,7 @@ static void acpi_bus_set_run_wake_flags(struct acpi_device *device) | |||
772 | /* Power button, Lid switch always enable wakeup */ | 803 | /* Power button, Lid switch always enable wakeup */ |
773 | if (!acpi_match_device_ids(device, button_device_ids)) { | 804 | if (!acpi_match_device_ids(device, button_device_ids)) { |
774 | device->wakeup.flags.run_wake = 1; | 805 | device->wakeup.flags.run_wake = 1; |
775 | device->wakeup.flags.always_enabled = 1; | 806 | device_set_wakeup_capable(&device->dev, true); |
776 | return; | 807 | return; |
777 | } | 808 | } |
778 | 809 | ||
@@ -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); |
@@ -827,6 +847,8 @@ end: | |||
827 | return 0; | 847 | return 0; |
828 | } | 848 | } |
829 | 849 | ||
850 | static void acpi_bus_add_power_resource(acpi_handle handle); | ||
851 | |||
830 | static int acpi_bus_get_power_flags(struct acpi_device *device) | 852 | static int acpi_bus_get_power_flags(struct acpi_device *device) |
831 | { | 853 | { |
832 | acpi_status status = 0; | 854 | acpi_status status = 0; |
@@ -855,8 +877,12 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) | |||
855 | acpi_evaluate_reference(device->handle, object_name, NULL, | 877 | acpi_evaluate_reference(device->handle, object_name, NULL, |
856 | &ps->resources); | 878 | &ps->resources); |
857 | if (ps->resources.count) { | 879 | if (ps->resources.count) { |
880 | int j; | ||
881 | |||
858 | device->power.flags.power_resources = 1; | 882 | device->power.flags.power_resources = 1; |
859 | ps->flags.valid = 1; | 883 | ps->flags.valid = 1; |
884 | for (j = 0; j < ps->resources.count; j++) | ||
885 | acpi_bus_add_power_resource(ps->resources.handles[j]); | ||
860 | } | 886 | } |
861 | 887 | ||
862 | /* Evaluate "_PSx" to see if we can do explicit sets */ | 888 | /* Evaluate "_PSx" to see if we can do explicit sets */ |
@@ -881,10 +907,7 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) | |||
881 | device->power.states[ACPI_STATE_D3].flags.valid = 1; | 907 | device->power.states[ACPI_STATE_D3].flags.valid = 1; |
882 | device->power.states[ACPI_STATE_D3].power = 0; | 908 | device->power.states[ACPI_STATE_D3].power = 0; |
883 | 909 | ||
884 | /* TBD: System wake support and resource requirements. */ | 910 | acpi_bus_init_power(device); |
885 | |||
886 | device->power.state = ACPI_STATE_UNKNOWN; | ||
887 | acpi_bus_get_power(device->handle, &(device->power.state)); | ||
888 | 911 | ||
889 | return 0; | 912 | return 0; |
890 | } | 913 | } |
@@ -1306,6 +1329,20 @@ end: | |||
1306 | #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ | 1329 | #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ |
1307 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) | 1330 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) |
1308 | 1331 | ||
1332 | static void acpi_bus_add_power_resource(acpi_handle handle) | ||
1333 | { | ||
1334 | struct acpi_bus_ops ops = { | ||
1335 | .acpi_op_add = 1, | ||
1336 | .acpi_op_start = 1, | ||
1337 | }; | ||
1338 | struct acpi_device *device = NULL; | ||
1339 | |||
1340 | acpi_bus_get_device(handle, &device); | ||
1341 | if (!device) | ||
1342 | acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER, | ||
1343 | ACPI_STA_DEFAULT, &ops); | ||
1344 | } | ||
1345 | |||
1309 | static int acpi_bus_type_and_status(acpi_handle handle, int *type, | 1346 | static int acpi_bus_type_and_status(acpi_handle handle, int *type, |
1310 | unsigned long long *sta) | 1347 | unsigned long long *sta) |
1311 | { | 1348 | { |
@@ -1351,6 +1388,7 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, | |||
1351 | struct acpi_bus_ops *ops = context; | 1388 | struct acpi_bus_ops *ops = context; |
1352 | int type; | 1389 | int type; |
1353 | unsigned long long sta; | 1390 | unsigned long long sta; |
1391 | struct acpi_device_wakeup wakeup; | ||
1354 | struct acpi_device *device; | 1392 | struct acpi_device *device; |
1355 | acpi_status status; | 1393 | acpi_status status; |
1356 | int result; | 1394 | int result; |
@@ -1360,8 +1398,10 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl, | |||
1360 | return AE_OK; | 1398 | return AE_OK; |
1361 | 1399 | ||
1362 | if (!(sta & ACPI_STA_DEVICE_PRESENT) && | 1400 | if (!(sta & ACPI_STA_DEVICE_PRESENT) && |
1363 | !(sta & ACPI_STA_DEVICE_FUNCTIONING)) | 1401 | !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { |
1402 | acpi_bus_extract_wakeup_device_power_package(handle, &wakeup); | ||
1364 | return AE_CTRL_DEPTH; | 1403 | return AE_CTRL_DEPTH; |
1404 | } | ||
1365 | 1405 | ||
1366 | /* | 1406 | /* |
1367 | * We may already have an acpi_device from a previous enumeration. If | 1407 | * We may already have an acpi_device from a previous enumeration. If |
@@ -1444,7 +1484,7 @@ int acpi_bus_start(struct acpi_device *device) | |||
1444 | 1484 | ||
1445 | result = acpi_bus_scan(device->handle, &ops, NULL); | 1485 | result = acpi_bus_scan(device->handle, &ops, NULL); |
1446 | 1486 | ||
1447 | acpi_update_gpes(); | 1487 | acpi_update_all_gpes(); |
1448 | 1488 | ||
1449 | return result; | 1489 | return result; |
1450 | } | 1490 | } |
@@ -1550,6 +1590,8 @@ int __init acpi_scan_init(void) | |||
1550 | printk(KERN_ERR PREFIX "Could not register bus type\n"); | 1590 | printk(KERN_ERR PREFIX "Could not register bus type\n"); |
1551 | } | 1591 | } |
1552 | 1592 | ||
1593 | acpi_power_init(); | ||
1594 | |||
1553 | /* | 1595 | /* |
1554 | * Enumerate devices in the ACPI namespace. | 1596 | * Enumerate devices in the ACPI namespace. |
1555 | */ | 1597 | */ |
@@ -1561,7 +1603,7 @@ int __init acpi_scan_init(void) | |||
1561 | if (result) | 1603 | if (result) |
1562 | acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); | 1604 | acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); |
1563 | else | 1605 | else |
1564 | acpi_update_gpes(); | 1606 | acpi_update_all_gpes(); |
1565 | 1607 | ||
1566 | return result; | 1608 | return result; |
1567 | } | 1609 | } |