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