diff options
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 462 |
1 files changed, 245 insertions, 217 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 83fe3bf4cdc8..cbf6e7729c39 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -174,6 +174,32 @@ err_out: | |||
174 | } | 174 | } |
175 | EXPORT_SYMBOL(acpi_bus_hot_remove_device); | 175 | EXPORT_SYMBOL(acpi_bus_hot_remove_device); |
176 | 176 | ||
177 | static ssize_t real_power_state_show(struct device *dev, | ||
178 | struct device_attribute *attr, char *buf) | ||
179 | { | ||
180 | struct acpi_device *adev = to_acpi_device(dev); | ||
181 | int state; | ||
182 | int ret; | ||
183 | |||
184 | ret = acpi_device_get_power(adev, &state); | ||
185 | if (ret) | ||
186 | return ret; | ||
187 | |||
188 | return sprintf(buf, "%s\n", acpi_power_state_string(state)); | ||
189 | } | ||
190 | |||
191 | static DEVICE_ATTR(real_power_state, 0444, real_power_state_show, NULL); | ||
192 | |||
193 | static ssize_t power_state_show(struct device *dev, | ||
194 | struct device_attribute *attr, char *buf) | ||
195 | { | ||
196 | struct acpi_device *adev = to_acpi_device(dev); | ||
197 | |||
198 | return sprintf(buf, "%s\n", acpi_power_state_string(adev->power.state)); | ||
199 | } | ||
200 | |||
201 | static DEVICE_ATTR(power_state, 0444, power_state_show, NULL); | ||
202 | |||
177 | static ssize_t | 203 | static ssize_t |
178 | acpi_eject_store(struct device *d, struct device_attribute *attr, | 204 | acpi_eject_store(struct device *d, struct device_attribute *attr, |
179 | const char *buf, size_t count) | 205 | const char *buf, size_t count) |
@@ -365,8 +391,22 @@ static int acpi_device_setup_files(struct acpi_device *dev) | |||
365 | * hot-removal function from userland. | 391 | * hot-removal function from userland. |
366 | */ | 392 | */ |
367 | status = acpi_get_handle(dev->handle, "_EJ0", &temp); | 393 | status = acpi_get_handle(dev->handle, "_EJ0", &temp); |
368 | if (ACPI_SUCCESS(status)) | 394 | if (ACPI_SUCCESS(status)) { |
369 | result = device_create_file(&dev->dev, &dev_attr_eject); | 395 | result = device_create_file(&dev->dev, &dev_attr_eject); |
396 | if (result) | ||
397 | return result; | ||
398 | } | ||
399 | |||
400 | if (dev->flags.power_manageable) { | ||
401 | result = device_create_file(&dev->dev, &dev_attr_power_state); | ||
402 | if (result) | ||
403 | return result; | ||
404 | |||
405 | if (dev->power.flags.power_resources) | ||
406 | result = device_create_file(&dev->dev, | ||
407 | &dev_attr_real_power_state); | ||
408 | } | ||
409 | |||
370 | end: | 410 | end: |
371 | return result; | 411 | return result; |
372 | } | 412 | } |
@@ -376,6 +416,13 @@ static void acpi_device_remove_files(struct acpi_device *dev) | |||
376 | acpi_status status; | 416 | acpi_status status; |
377 | acpi_handle temp; | 417 | acpi_handle temp; |
378 | 418 | ||
419 | if (dev->flags.power_manageable) { | ||
420 | device_remove_file(&dev->dev, &dev_attr_power_state); | ||
421 | if (dev->power.flags.power_resources) | ||
422 | device_remove_file(&dev->dev, | ||
423 | &dev_attr_real_power_state); | ||
424 | } | ||
425 | |||
379 | /* | 426 | /* |
380 | * If device has _STR, remove 'description' file | 427 | * If device has _STR, remove 'description' file |
381 | */ | 428 | */ |
@@ -460,7 +507,7 @@ int acpi_match_device_ids(struct acpi_device *device, | |||
460 | } | 507 | } |
461 | EXPORT_SYMBOL(acpi_match_device_ids); | 508 | EXPORT_SYMBOL(acpi_match_device_ids); |
462 | 509 | ||
463 | static void acpi_free_ids(struct acpi_device *device) | 510 | void acpi_free_ids(struct acpi_device *device) |
464 | { | 511 | { |
465 | struct acpi_hardware_id *id, *tmp; | 512 | struct acpi_hardware_id *id, *tmp; |
466 | 513 | ||
@@ -468,6 +515,23 @@ static void acpi_free_ids(struct acpi_device *device) | |||
468 | kfree(id->id); | 515 | kfree(id->id); |
469 | kfree(id); | 516 | kfree(id); |
470 | } | 517 | } |
518 | kfree(device->pnp.unique_id); | ||
519 | } | ||
520 | |||
521 | static void acpi_free_power_resources_lists(struct acpi_device *device) | ||
522 | { | ||
523 | int i; | ||
524 | |||
525 | if (device->wakeup.flags.valid) | ||
526 | acpi_power_resources_list_free(&device->wakeup.resources); | ||
527 | |||
528 | if (!device->flags.power_manageable) | ||
529 | return; | ||
530 | |||
531 | for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) { | ||
532 | struct acpi_device_power_state *ps = &device->power.states[i]; | ||
533 | acpi_power_resources_list_free(&ps->resources); | ||
534 | } | ||
471 | } | 535 | } |
472 | 536 | ||
473 | static void acpi_device_release(struct device *dev) | 537 | static void acpi_device_release(struct device *dev) |
@@ -475,7 +539,7 @@ static void acpi_device_release(struct device *dev) | |||
475 | struct acpi_device *acpi_dev = to_acpi_device(dev); | 539 | struct acpi_device *acpi_dev = to_acpi_device(dev); |
476 | 540 | ||
477 | acpi_free_ids(acpi_dev); | 541 | acpi_free_ids(acpi_dev); |
478 | kfree(acpi_dev->pnp.unique_id); | 542 | acpi_free_power_resources_lists(acpi_dev); |
479 | kfree(acpi_dev); | 543 | kfree(acpi_dev); |
480 | } | 544 | } |
481 | 545 | ||
@@ -613,12 +677,25 @@ struct bus_type acpi_bus_type = { | |||
613 | .uevent = acpi_device_uevent, | 677 | .uevent = acpi_device_uevent, |
614 | }; | 678 | }; |
615 | 679 | ||
616 | static int acpi_device_register(struct acpi_device *device) | 680 | int acpi_device_add(struct acpi_device *device, |
681 | void (*release)(struct device *)) | ||
617 | { | 682 | { |
618 | int result; | 683 | int result; |
619 | struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; | 684 | struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; |
620 | int found = 0; | 685 | int found = 0; |
621 | 686 | ||
687 | if (device->handle) { | ||
688 | acpi_status status; | ||
689 | |||
690 | status = acpi_attach_data(device->handle, acpi_bus_data_handler, | ||
691 | device); | ||
692 | if (ACPI_FAILURE(status)) { | ||
693 | acpi_handle_err(device->handle, | ||
694 | "Unable to attach device data\n"); | ||
695 | return -ENODEV; | ||
696 | } | ||
697 | } | ||
698 | |||
622 | /* | 699 | /* |
623 | * Linkage | 700 | * Linkage |
624 | * ------- | 701 | * ------- |
@@ -629,11 +706,13 @@ static int acpi_device_register(struct acpi_device *device) | |||
629 | INIT_LIST_HEAD(&device->wakeup_list); | 706 | INIT_LIST_HEAD(&device->wakeup_list); |
630 | INIT_LIST_HEAD(&device->physical_node_list); | 707 | INIT_LIST_HEAD(&device->physical_node_list); |
631 | mutex_init(&device->physical_node_lock); | 708 | mutex_init(&device->physical_node_lock); |
709 | INIT_LIST_HEAD(&device->power_dependent); | ||
632 | 710 | ||
633 | new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); | 711 | new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); |
634 | if (!new_bus_id) { | 712 | if (!new_bus_id) { |
635 | printk(KERN_ERR PREFIX "Memory allocation error\n"); | 713 | pr_err(PREFIX "Memory allocation error\n"); |
636 | return -ENOMEM; | 714 | result = -ENOMEM; |
715 | goto err_detach; | ||
637 | } | 716 | } |
638 | 717 | ||
639 | mutex_lock(&acpi_device_lock); | 718 | mutex_lock(&acpi_device_lock); |
@@ -668,11 +747,11 @@ static int acpi_device_register(struct acpi_device *device) | |||
668 | if (device->parent) | 747 | if (device->parent) |
669 | device->dev.parent = &device->parent->dev; | 748 | device->dev.parent = &device->parent->dev; |
670 | device->dev.bus = &acpi_bus_type; | 749 | device->dev.bus = &acpi_bus_type; |
671 | device->dev.release = &acpi_device_release; | 750 | device->dev.release = release; |
672 | result = device_register(&device->dev); | 751 | result = device_add(&device->dev); |
673 | if (result) { | 752 | if (result) { |
674 | dev_err(&device->dev, "Error registering device\n"); | 753 | dev_err(&device->dev, "Error registering device\n"); |
675 | goto end; | 754 | goto err; |
676 | } | 755 | } |
677 | 756 | ||
678 | result = acpi_device_setup_files(device); | 757 | result = acpi_device_setup_files(device); |
@@ -682,12 +761,16 @@ static int acpi_device_register(struct acpi_device *device) | |||
682 | 761 | ||
683 | device->removal_type = ACPI_BUS_REMOVAL_NORMAL; | 762 | device->removal_type = ACPI_BUS_REMOVAL_NORMAL; |
684 | return 0; | 763 | return 0; |
685 | end: | 764 | |
765 | err: | ||
686 | mutex_lock(&acpi_device_lock); | 766 | mutex_lock(&acpi_device_lock); |
687 | if (device->parent) | 767 | if (device->parent) |
688 | list_del(&device->node); | 768 | list_del(&device->node); |
689 | list_del(&device->wakeup_list); | 769 | list_del(&device->wakeup_list); |
690 | mutex_unlock(&acpi_device_lock); | 770 | mutex_unlock(&acpi_device_lock); |
771 | |||
772 | err_detach: | ||
773 | acpi_detach_data(device->handle, acpi_bus_data_handler); | ||
691 | return result; | 774 | return result; |
692 | } | 775 | } |
693 | 776 | ||
@@ -702,8 +785,18 @@ static void acpi_device_unregister(struct acpi_device *device) | |||
702 | 785 | ||
703 | acpi_detach_data(device->handle, acpi_bus_data_handler); | 786 | acpi_detach_data(device->handle, acpi_bus_data_handler); |
704 | 787 | ||
788 | acpi_power_add_remove_device(device, false); | ||
705 | acpi_device_remove_files(device); | 789 | acpi_device_remove_files(device); |
706 | device_unregister(&device->dev); | 790 | if (device->remove) |
791 | device->remove(device); | ||
792 | |||
793 | device_del(&device->dev); | ||
794 | /* | ||
795 | * Drop the reference counts of all power resources the device depends | ||
796 | * on and turn off the ones that have no more references. | ||
797 | */ | ||
798 | acpi_power_transition(device, ACPI_STATE_D3_COLD); | ||
799 | put_device(&device->dev); | ||
707 | } | 800 | } |
708 | 801 | ||
709 | /* -------------------------------------------------------------------------- | 802 | /* -------------------------------------------------------------------------- |
@@ -846,52 +939,43 @@ void acpi_bus_data_handler(acpi_handle handle, void *context) | |||
846 | return; | 939 | return; |
847 | } | 940 | } |
848 | 941 | ||
849 | static int acpi_bus_get_perf_flags(struct acpi_device *device) | 942 | static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, |
850 | { | 943 | struct acpi_device_wakeup *wakeup) |
851 | device->performance.state = ACPI_STATE_UNKNOWN; | ||
852 | return 0; | ||
853 | } | ||
854 | |||
855 | static acpi_status | ||
856 | acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, | ||
857 | struct acpi_device_wakeup *wakeup) | ||
858 | { | 944 | { |
859 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 945 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
860 | union acpi_object *package = NULL; | 946 | union acpi_object *package = NULL; |
861 | union acpi_object *element = NULL; | 947 | union acpi_object *element = NULL; |
862 | acpi_status status; | 948 | acpi_status status; |
863 | int i = 0; | 949 | int err = -ENODATA; |
864 | 950 | ||
865 | if (!wakeup) | 951 | if (!wakeup) |
866 | return AE_BAD_PARAMETER; | 952 | return -EINVAL; |
953 | |||
954 | INIT_LIST_HEAD(&wakeup->resources); | ||
867 | 955 | ||
868 | /* _PRW */ | 956 | /* _PRW */ |
869 | status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer); | 957 | status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer); |
870 | if (ACPI_FAILURE(status)) { | 958 | if (ACPI_FAILURE(status)) { |
871 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); | 959 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); |
872 | return status; | 960 | return err; |
873 | } | 961 | } |
874 | 962 | ||
875 | package = (union acpi_object *)buffer.pointer; | 963 | package = (union acpi_object *)buffer.pointer; |
876 | 964 | ||
877 | if (!package || (package->package.count < 2)) { | 965 | if (!package || package->package.count < 2) |
878 | status = AE_BAD_DATA; | ||
879 | goto out; | 966 | goto out; |
880 | } | ||
881 | 967 | ||
882 | element = &(package->package.elements[0]); | 968 | element = &(package->package.elements[0]); |
883 | if (!element) { | 969 | if (!element) |
884 | status = AE_BAD_DATA; | ||
885 | goto out; | 970 | goto out; |
886 | } | 971 | |
887 | if (element->type == ACPI_TYPE_PACKAGE) { | 972 | if (element->type == ACPI_TYPE_PACKAGE) { |
888 | if ((element->package.count < 2) || | 973 | if ((element->package.count < 2) || |
889 | (element->package.elements[0].type != | 974 | (element->package.elements[0].type != |
890 | ACPI_TYPE_LOCAL_REFERENCE) | 975 | ACPI_TYPE_LOCAL_REFERENCE) |
891 | || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) { | 976 | || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) |
892 | status = AE_BAD_DATA; | ||
893 | goto out; | 977 | goto out; |
894 | } | 978 | |
895 | wakeup->gpe_device = | 979 | wakeup->gpe_device = |
896 | element->package.elements[0].reference.handle; | 980 | element->package.elements[0].reference.handle; |
897 | wakeup->gpe_number = | 981 | wakeup->gpe_number = |
@@ -900,38 +984,35 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, | |||
900 | wakeup->gpe_device = NULL; | 984 | wakeup->gpe_device = NULL; |
901 | wakeup->gpe_number = element->integer.value; | 985 | wakeup->gpe_number = element->integer.value; |
902 | } else { | 986 | } else { |
903 | status = AE_BAD_DATA; | ||
904 | goto out; | 987 | goto out; |
905 | } | 988 | } |
906 | 989 | ||
907 | element = &(package->package.elements[1]); | 990 | element = &(package->package.elements[1]); |
908 | if (element->type != ACPI_TYPE_INTEGER) { | 991 | if (element->type != ACPI_TYPE_INTEGER) |
909 | status = AE_BAD_DATA; | ||
910 | goto out; | 992 | goto out; |
911 | } | 993 | |
912 | wakeup->sleep_state = element->integer.value; | 994 | wakeup->sleep_state = element->integer.value; |
913 | 995 | ||
914 | if ((package->package.count - 2) > ACPI_MAX_HANDLES) { | 996 | err = acpi_extract_power_resources(package, 2, &wakeup->resources); |
915 | status = AE_NO_MEMORY; | 997 | if (err) |
916 | goto out; | 998 | goto out; |
917 | } | ||
918 | wakeup->resources.count = package->package.count - 2; | ||
919 | for (i = 0; i < wakeup->resources.count; i++) { | ||
920 | element = &(package->package.elements[i + 2]); | ||
921 | if (element->type != ACPI_TYPE_LOCAL_REFERENCE) { | ||
922 | status = AE_BAD_DATA; | ||
923 | goto out; | ||
924 | } | ||
925 | 999 | ||
926 | wakeup->resources.handles[i] = element->reference.handle; | 1000 | if (!list_empty(&wakeup->resources)) { |
927 | } | 1001 | int sleep_state; |
928 | 1002 | ||
1003 | sleep_state = acpi_power_min_system_level(&wakeup->resources); | ||
1004 | if (sleep_state < wakeup->sleep_state) { | ||
1005 | acpi_handle_warn(handle, "Overriding _PRW sleep state " | ||
1006 | "(S%d) by S%d from power resources\n", | ||
1007 | (int)wakeup->sleep_state, sleep_state); | ||
1008 | wakeup->sleep_state = sleep_state; | ||
1009 | } | ||
1010 | } | ||
929 | acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number); | 1011 | acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number); |
930 | 1012 | ||
931 | out: | 1013 | out: |
932 | kfree(buffer.pointer); | 1014 | kfree(buffer.pointer); |
933 | 1015 | return err; | |
934 | return status; | ||
935 | } | 1016 | } |
936 | 1017 | ||
937 | static void acpi_bus_set_run_wake_flags(struct acpi_device *device) | 1018 | static void acpi_bus_set_run_wake_flags(struct acpi_device *device) |
@@ -971,17 +1052,17 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) | |||
971 | { | 1052 | { |
972 | acpi_handle temp; | 1053 | acpi_handle temp; |
973 | acpi_status status = 0; | 1054 | acpi_status status = 0; |
974 | int psw_error; | 1055 | int err; |
975 | 1056 | ||
976 | /* Presence of _PRW indicates wake capable */ | 1057 | /* Presence of _PRW indicates wake capable */ |
977 | status = acpi_get_handle(device->handle, "_PRW", &temp); | 1058 | status = acpi_get_handle(device->handle, "_PRW", &temp); |
978 | if (ACPI_FAILURE(status)) | 1059 | if (ACPI_FAILURE(status)) |
979 | return; | 1060 | return; |
980 | 1061 | ||
981 | status = acpi_bus_extract_wakeup_device_power_package(device->handle, | 1062 | err = acpi_bus_extract_wakeup_device_power_package(device->handle, |
982 | &device->wakeup); | 1063 | &device->wakeup); |
983 | if (ACPI_FAILURE(status)) { | 1064 | if (err) { |
984 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); | 1065 | dev_err(&device->dev, "_PRW evaluation error: %d\n", err); |
985 | return; | 1066 | return; |
986 | } | 1067 | } |
987 | 1068 | ||
@@ -994,20 +1075,73 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) | |||
994 | * So it is necessary to call _DSW object first. Only when it is not | 1075 | * So it is necessary to call _DSW object first. Only when it is not |
995 | * present will the _PSW object used. | 1076 | * present will the _PSW object used. |
996 | */ | 1077 | */ |
997 | psw_error = acpi_device_sleep_wake(device, 0, 0, 0); | 1078 | err = acpi_device_sleep_wake(device, 0, 0, 0); |
998 | if (psw_error) | 1079 | if (err) |
999 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 1080 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
1000 | "error in _DSW or _PSW evaluation\n")); | 1081 | "error in _DSW or _PSW evaluation\n")); |
1001 | } | 1082 | } |
1002 | 1083 | ||
1003 | static void acpi_bus_add_power_resource(acpi_handle handle); | 1084 | static void acpi_bus_init_power_state(struct acpi_device *device, int state) |
1085 | { | ||
1086 | struct acpi_device_power_state *ps = &device->power.states[state]; | ||
1087 | char pathname[5] = { '_', 'P', 'R', '0' + state, '\0' }; | ||
1088 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1089 | acpi_handle handle; | ||
1090 | acpi_status status; | ||
1004 | 1091 | ||
1005 | static int acpi_bus_get_power_flags(struct acpi_device *device) | 1092 | INIT_LIST_HEAD(&ps->resources); |
1093 | |||
1094 | /* Evaluate "_PRx" to get referenced power resources */ | ||
1095 | status = acpi_evaluate_object(device->handle, pathname, NULL, &buffer); | ||
1096 | if (ACPI_SUCCESS(status)) { | ||
1097 | union acpi_object *package = buffer.pointer; | ||
1098 | |||
1099 | if (buffer.length && package | ||
1100 | && package->type == ACPI_TYPE_PACKAGE | ||
1101 | && package->package.count) { | ||
1102 | int err = acpi_extract_power_resources(package, 0, | ||
1103 | &ps->resources); | ||
1104 | if (!err) | ||
1105 | device->power.flags.power_resources = 1; | ||
1106 | } | ||
1107 | ACPI_FREE(buffer.pointer); | ||
1108 | } | ||
1109 | |||
1110 | /* Evaluate "_PSx" to see if we can do explicit sets */ | ||
1111 | pathname[2] = 'S'; | ||
1112 | status = acpi_get_handle(device->handle, pathname, &handle); | ||
1113 | if (ACPI_SUCCESS(status)) | ||
1114 | ps->flags.explicit_set = 1; | ||
1115 | |||
1116 | /* | ||
1117 | * State is valid if there are means to put the device into it. | ||
1118 | * D3hot is only valid if _PR3 present. | ||
1119 | */ | ||
1120 | if (!list_empty(&ps->resources) | ||
1121 | || (ps->flags.explicit_set && state < ACPI_STATE_D3_HOT)) { | ||
1122 | ps->flags.valid = 1; | ||
1123 | ps->flags.os_accessible = 1; | ||
1124 | } | ||
1125 | |||
1126 | ps->power = -1; /* Unknown - driver assigned */ | ||
1127 | ps->latency = -1; /* Unknown - driver assigned */ | ||
1128 | } | ||
1129 | |||
1130 | static void acpi_bus_get_power_flags(struct acpi_device *device) | ||
1006 | { | 1131 | { |
1007 | acpi_status status = 0; | 1132 | acpi_status status; |
1008 | acpi_handle handle = NULL; | 1133 | acpi_handle handle; |
1009 | u32 i = 0; | 1134 | u32 i; |
1135 | |||
1136 | /* Presence of _PS0|_PR0 indicates 'power manageable' */ | ||
1137 | status = acpi_get_handle(device->handle, "_PS0", &handle); | ||
1138 | if (ACPI_FAILURE(status)) { | ||
1139 | status = acpi_get_handle(device->handle, "_PR0", &handle); | ||
1140 | if (ACPI_FAILURE(status)) | ||
1141 | return; | ||
1142 | } | ||
1010 | 1143 | ||
1144 | device->flags.power_manageable = 1; | ||
1011 | 1145 | ||
1012 | /* | 1146 | /* |
1013 | * Power Management Flags | 1147 | * Power Management Flags |
@@ -1022,40 +1156,10 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) | |||
1022 | /* | 1156 | /* |
1023 | * Enumerate supported power management states | 1157 | * Enumerate supported power management states |
1024 | */ | 1158 | */ |
1025 | for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) { | 1159 | for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) |
1026 | struct acpi_device_power_state *ps = &device->power.states[i]; | 1160 | acpi_bus_init_power_state(device, i); |
1027 | char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; | ||
1028 | |||
1029 | /* Evaluate "_PRx" to se if power resources are referenced */ | ||
1030 | acpi_evaluate_reference(device->handle, object_name, NULL, | ||
1031 | &ps->resources); | ||
1032 | if (ps->resources.count) { | ||
1033 | int j; | ||
1034 | 1161 | ||
1035 | device->power.flags.power_resources = 1; | 1162 | INIT_LIST_HEAD(&device->power.states[ACPI_STATE_D3_COLD].resources); |
1036 | for (j = 0; j < ps->resources.count; j++) | ||
1037 | acpi_bus_add_power_resource(ps->resources.handles[j]); | ||
1038 | } | ||
1039 | |||
1040 | /* Evaluate "_PSx" to see if we can do explicit sets */ | ||
1041 | object_name[2] = 'S'; | ||
1042 | status = acpi_get_handle(device->handle, object_name, &handle); | ||
1043 | if (ACPI_SUCCESS(status)) | ||
1044 | ps->flags.explicit_set = 1; | ||
1045 | |||
1046 | /* | ||
1047 | * State is valid if there are means to put the device into it. | ||
1048 | * D3hot is only valid if _PR3 present. | ||
1049 | */ | ||
1050 | if (ps->resources.count || | ||
1051 | (ps->flags.explicit_set && i < ACPI_STATE_D3_HOT)) { | ||
1052 | ps->flags.valid = 1; | ||
1053 | ps->flags.os_accessible = 1; | ||
1054 | } | ||
1055 | |||
1056 | ps->power = -1; /* Unknown - driver assigned */ | ||
1057 | ps->latency = -1; /* Unknown - driver assigned */ | ||
1058 | } | ||
1059 | 1163 | ||
1060 | /* Set defaults for D0 and D3 states (always valid) */ | 1164 | /* Set defaults for D0 and D3 states (always valid) */ |
1061 | device->power.states[ACPI_STATE_D0].flags.valid = 1; | 1165 | device->power.states[ACPI_STATE_D0].flags.valid = 1; |
@@ -1072,17 +1176,17 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) | |||
1072 | device->power.flags.power_resources) | 1176 | device->power.flags.power_resources) |
1073 | device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1; | 1177 | device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1; |
1074 | 1178 | ||
1075 | acpi_bus_init_power(device); | 1179 | if (acpi_bus_init_power(device)) { |
1076 | 1180 | acpi_free_power_resources_lists(device); | |
1077 | return 0; | 1181 | device->flags.power_manageable = 0; |
1182 | } | ||
1078 | } | 1183 | } |
1079 | 1184 | ||
1080 | static int acpi_bus_get_flags(struct acpi_device *device) | 1185 | static void acpi_bus_get_flags(struct acpi_device *device) |
1081 | { | 1186 | { |
1082 | acpi_status status = AE_OK; | 1187 | acpi_status status = AE_OK; |
1083 | acpi_handle temp = NULL; | 1188 | acpi_handle temp = NULL; |
1084 | 1189 | ||
1085 | |||
1086 | /* Presence of _STA indicates 'dynamic_status' */ | 1190 | /* Presence of _STA indicates 'dynamic_status' */ |
1087 | status = acpi_get_handle(device->handle, "_STA", &temp); | 1191 | status = acpi_get_handle(device->handle, "_STA", &temp); |
1088 | if (ACPI_SUCCESS(status)) | 1192 | if (ACPI_SUCCESS(status)) |
@@ -1102,21 +1206,6 @@ static int acpi_bus_get_flags(struct acpi_device *device) | |||
1102 | if (ACPI_SUCCESS(status)) | 1206 | if (ACPI_SUCCESS(status)) |
1103 | device->flags.ejectable = 1; | 1207 | device->flags.ejectable = 1; |
1104 | } | 1208 | } |
1105 | |||
1106 | /* Power resources cannot be power manageable. */ | ||
1107 | if (device->device_type == ACPI_BUS_TYPE_POWER) | ||
1108 | return 0; | ||
1109 | |||
1110 | /* Presence of _PS0|_PR0 indicates 'power manageable' */ | ||
1111 | status = acpi_get_handle(device->handle, "_PS0", &temp); | ||
1112 | if (ACPI_FAILURE(status)) | ||
1113 | status = acpi_get_handle(device->handle, "_PR0", &temp); | ||
1114 | if (ACPI_SUCCESS(status)) | ||
1115 | device->flags.power_manageable = 1; | ||
1116 | |||
1117 | /* TBD: Performance management */ | ||
1118 | |||
1119 | return 0; | ||
1120 | } | 1209 | } |
1121 | 1210 | ||
1122 | static void acpi_device_get_busid(struct acpi_device *device) | 1211 | static void acpi_device_get_busid(struct acpi_device *device) |
@@ -1341,27 +1430,25 @@ static void acpi_device_set_id(struct acpi_device *device) | |||
1341 | } | 1430 | } |
1342 | } | 1431 | } |
1343 | 1432 | ||
1344 | static int acpi_device_set_context(struct acpi_device *device) | 1433 | void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, |
1434 | int type, unsigned long long sta) | ||
1345 | { | 1435 | { |
1346 | acpi_status status; | 1436 | INIT_LIST_HEAD(&device->pnp.ids); |
1347 | 1437 | device->device_type = type; | |
1348 | /* | 1438 | device->handle = handle; |
1349 | * Context | 1439 | device->parent = acpi_bus_get_parent(handle); |
1350 | * ------- | 1440 | STRUCT_TO_INT(device->status) = sta; |
1351 | * Attach this 'struct acpi_device' to the ACPI object. This makes | 1441 | acpi_device_get_busid(device); |
1352 | * resolutions from handle->device very efficient. Fixed hardware | 1442 | acpi_device_set_id(device); |
1353 | * devices have no handles, so we skip them. | 1443 | acpi_bus_get_flags(device); |
1354 | */ | 1444 | device_initialize(&device->dev); |
1355 | if (!device->handle) | 1445 | dev_set_uevent_suppress(&device->dev, true); |
1356 | return 0; | 1446 | } |
1357 | |||
1358 | status = acpi_attach_data(device->handle, | ||
1359 | acpi_bus_data_handler, device); | ||
1360 | if (ACPI_SUCCESS(status)) | ||
1361 | return 0; | ||
1362 | 1447 | ||
1363 | printk(KERN_ERR PREFIX "Error attaching device data\n"); | 1448 | void acpi_device_add_finalize(struct acpi_device *device) |
1364 | return -ENODEV; | 1449 | { |
1450 | dev_set_uevent_suppress(&device->dev, false); | ||
1451 | kobject_uevent(&device->dev.kobj, KOBJ_ADD); | ||
1365 | } | 1452 | } |
1366 | 1453 | ||
1367 | static int acpi_add_single_object(struct acpi_device **child, | 1454 | static int acpi_add_single_object(struct acpi_device **child, |
@@ -1378,90 +1465,26 @@ static int acpi_add_single_object(struct acpi_device **child, | |||
1378 | return -ENOMEM; | 1465 | return -ENOMEM; |
1379 | } | 1466 | } |
1380 | 1467 | ||
1381 | INIT_LIST_HEAD(&device->pnp.ids); | 1468 | acpi_init_device_object(device, handle, type, sta); |
1382 | device->device_type = type; | 1469 | acpi_bus_get_power_flags(device); |
1383 | device->handle = handle; | ||
1384 | device->parent = acpi_bus_get_parent(handle); | ||
1385 | STRUCT_TO_INT(device->status) = sta; | ||
1386 | |||
1387 | acpi_device_get_busid(device); | ||
1388 | |||
1389 | /* | ||
1390 | * Flags | ||
1391 | * ----- | ||
1392 | * Note that we only look for object handles -- cannot evaluate objects | ||
1393 | * until we know the device is present and properly initialized. | ||
1394 | */ | ||
1395 | result = acpi_bus_get_flags(device); | ||
1396 | if (result) | ||
1397 | goto end; | ||
1398 | |||
1399 | /* | ||
1400 | * Initialize Device | ||
1401 | * ----------------- | ||
1402 | * TBD: Synch with Core's enumeration/initialization process. | ||
1403 | */ | ||
1404 | acpi_device_set_id(device); | ||
1405 | |||
1406 | /* | ||
1407 | * Power Management | ||
1408 | * ---------------- | ||
1409 | */ | ||
1410 | if (device->flags.power_manageable) { | ||
1411 | result = acpi_bus_get_power_flags(device); | ||
1412 | if (result) | ||
1413 | goto end; | ||
1414 | } | ||
1415 | |||
1416 | /* | ||
1417 | * Wakeup device management | ||
1418 | *----------------------- | ||
1419 | */ | ||
1420 | acpi_bus_get_wakeup_device_flags(device); | 1470 | acpi_bus_get_wakeup_device_flags(device); |
1421 | 1471 | ||
1422 | /* | ||
1423 | * Performance Management | ||
1424 | * ---------------------- | ||
1425 | */ | ||
1426 | if (device->flags.performance_manageable) { | ||
1427 | result = acpi_bus_get_perf_flags(device); | ||
1428 | if (result) | ||
1429 | goto end; | ||
1430 | } | ||
1431 | |||
1432 | if ((result = acpi_device_set_context(device))) | ||
1433 | goto end; | ||
1434 | |||
1435 | device->flags.match_driver = match_driver; | 1472 | device->flags.match_driver = match_driver; |
1436 | result = acpi_device_register(device); | 1473 | result = acpi_device_add(device, acpi_device_release); |
1437 | 1474 | if (result) { | |
1438 | end: | ||
1439 | if (!result) { | ||
1440 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | ||
1441 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
1442 | "Adding %s [%s] parent %s\n", dev_name(&device->dev), | ||
1443 | (char *) buffer.pointer, | ||
1444 | device->parent ? dev_name(&device->parent->dev) : | ||
1445 | "(null)")); | ||
1446 | kfree(buffer.pointer); | ||
1447 | *child = device; | ||
1448 | } else | ||
1449 | acpi_device_release(&device->dev); | 1475 | acpi_device_release(&device->dev); |
1476 | return result; | ||
1477 | } | ||
1450 | 1478 | ||
1451 | return result; | 1479 | acpi_power_add_remove_device(device, true); |
1452 | } | 1480 | acpi_device_add_finalize(device); |
1453 | 1481 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | |
1454 | #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ | 1482 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Added %s [%s] parent %s\n", |
1455 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) | 1483 | dev_name(&device->dev), (char *) buffer.pointer, |
1456 | 1484 | device->parent ? dev_name(&device->parent->dev) : "(null)")); | |
1457 | static void acpi_bus_add_power_resource(acpi_handle handle) | 1485 | kfree(buffer.pointer); |
1458 | { | 1486 | *child = device; |
1459 | struct acpi_device *device = NULL; | 1487 | return 0; |
1460 | |||
1461 | acpi_bus_get_device(handle, &device); | ||
1462 | if (!device) | ||
1463 | acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER, | ||
1464 | ACPI_STA_DEFAULT, true); | ||
1465 | } | 1488 | } |
1466 | 1489 | ||
1467 | static int acpi_bus_type_and_status(acpi_handle handle, int *type, | 1490 | static int acpi_bus_type_and_status(acpi_handle handle, int *type, |
@@ -1520,20 +1543,26 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, | |||
1520 | if (result) | 1543 | if (result) |
1521 | return AE_OK; | 1544 | return AE_OK; |
1522 | 1545 | ||
1546 | if (type == ACPI_BUS_TYPE_POWER) { | ||
1547 | acpi_add_power_resource(handle); | ||
1548 | return AE_OK; | ||
1549 | } | ||
1550 | |||
1523 | if (!(sta & ACPI_STA_DEVICE_PRESENT) && | 1551 | if (!(sta & ACPI_STA_DEVICE_PRESENT) && |
1524 | !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { | 1552 | !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { |
1525 | struct acpi_device_wakeup wakeup; | 1553 | struct acpi_device_wakeup wakeup; |
1526 | acpi_handle temp; | 1554 | acpi_handle temp; |
1527 | 1555 | ||
1528 | status = acpi_get_handle(handle, "_PRW", &temp); | 1556 | status = acpi_get_handle(handle, "_PRW", &temp); |
1529 | if (ACPI_SUCCESS(status)) | 1557 | if (ACPI_SUCCESS(status)) { |
1530 | acpi_bus_extract_wakeup_device_power_package(handle, | 1558 | acpi_bus_extract_wakeup_device_power_package(handle, |
1531 | &wakeup); | 1559 | &wakeup); |
1560 | acpi_power_resources_list_free(&wakeup.resources); | ||
1561 | } | ||
1532 | return AE_CTRL_DEPTH; | 1562 | return AE_CTRL_DEPTH; |
1533 | } | 1563 | } |
1534 | 1564 | ||
1535 | acpi_add_single_object(&device, handle, type, sta, | 1565 | acpi_add_single_object(&device, handle, type, sta, false); |
1536 | type == ACPI_BUS_TYPE_POWER); | ||
1537 | if (!device) | 1566 | if (!device) |
1538 | return AE_CTRL_DEPTH; | 1567 | return AE_CTRL_DEPTH; |
1539 | 1568 | ||
@@ -1687,7 +1716,6 @@ int __init acpi_scan_init(void) | |||
1687 | printk(KERN_ERR PREFIX "Could not register bus type\n"); | 1716 | printk(KERN_ERR PREFIX "Could not register bus type\n"); |
1688 | } | 1717 | } |
1689 | 1718 | ||
1690 | acpi_power_init(); | ||
1691 | acpi_pci_root_init(); | 1719 | acpi_pci_root_init(); |
1692 | 1720 | ||
1693 | /* | 1721 | /* |