diff options
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 497 |
1 files changed, 267 insertions, 230 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 43754655c156..774b17dc7999 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 | ||
@@ -573,8 +637,7 @@ static int acpi_device_probe(struct device * dev) | |||
573 | ret = acpi_device_install_notify_handler(acpi_dev); | 637 | ret = acpi_device_install_notify_handler(acpi_dev); |
574 | if (ret) { | 638 | if (ret) { |
575 | if (acpi_drv->ops.remove) | 639 | if (acpi_drv->ops.remove) |
576 | acpi_drv->ops.remove(acpi_dev, | 640 | acpi_drv->ops.remove(acpi_dev); |
577 | acpi_dev->removal_type); | ||
578 | return ret; | 641 | return ret; |
579 | } | 642 | } |
580 | } | 643 | } |
@@ -596,7 +659,7 @@ static int acpi_device_remove(struct device * dev) | |||
596 | if (acpi_drv->ops.notify) | 659 | if (acpi_drv->ops.notify) |
597 | acpi_device_remove_notify_handler(acpi_dev); | 660 | acpi_device_remove_notify_handler(acpi_dev); |
598 | if (acpi_drv->ops.remove) | 661 | if (acpi_drv->ops.remove) |
599 | acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type); | 662 | acpi_drv->ops.remove(acpi_dev); |
600 | } | 663 | } |
601 | acpi_dev->driver = NULL; | 664 | acpi_dev->driver = NULL; |
602 | acpi_dev->driver_data = NULL; | 665 | acpi_dev->driver_data = NULL; |
@@ -613,12 +676,25 @@ struct bus_type acpi_bus_type = { | |||
613 | .uevent = acpi_device_uevent, | 676 | .uevent = acpi_device_uevent, |
614 | }; | 677 | }; |
615 | 678 | ||
616 | static int acpi_device_register(struct acpi_device *device) | 679 | int acpi_device_add(struct acpi_device *device, |
680 | void (*release)(struct device *)) | ||
617 | { | 681 | { |
618 | int result; | 682 | int result; |
619 | struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; | 683 | struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id; |
620 | int found = 0; | 684 | int found = 0; |
621 | 685 | ||
686 | if (device->handle) { | ||
687 | acpi_status status; | ||
688 | |||
689 | status = acpi_attach_data(device->handle, acpi_bus_data_handler, | ||
690 | device); | ||
691 | if (ACPI_FAILURE(status)) { | ||
692 | acpi_handle_err(device->handle, | ||
693 | "Unable to attach device data\n"); | ||
694 | return -ENODEV; | ||
695 | } | ||
696 | } | ||
697 | |||
622 | /* | 698 | /* |
623 | * Linkage | 699 | * Linkage |
624 | * ------- | 700 | * ------- |
@@ -629,11 +705,13 @@ static int acpi_device_register(struct acpi_device *device) | |||
629 | INIT_LIST_HEAD(&device->wakeup_list); | 705 | INIT_LIST_HEAD(&device->wakeup_list); |
630 | INIT_LIST_HEAD(&device->physical_node_list); | 706 | INIT_LIST_HEAD(&device->physical_node_list); |
631 | mutex_init(&device->physical_node_lock); | 707 | mutex_init(&device->physical_node_lock); |
708 | INIT_LIST_HEAD(&device->power_dependent); | ||
632 | 709 | ||
633 | new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); | 710 | new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); |
634 | if (!new_bus_id) { | 711 | if (!new_bus_id) { |
635 | printk(KERN_ERR PREFIX "Memory allocation error\n"); | 712 | pr_err(PREFIX "Memory allocation error\n"); |
636 | return -ENOMEM; | 713 | result = -ENOMEM; |
714 | goto err_detach; | ||
637 | } | 715 | } |
638 | 716 | ||
639 | mutex_lock(&acpi_device_lock); | 717 | mutex_lock(&acpi_device_lock); |
@@ -668,11 +746,11 @@ static int acpi_device_register(struct acpi_device *device) | |||
668 | if (device->parent) | 746 | if (device->parent) |
669 | device->dev.parent = &device->parent->dev; | 747 | device->dev.parent = &device->parent->dev; |
670 | device->dev.bus = &acpi_bus_type; | 748 | device->dev.bus = &acpi_bus_type; |
671 | device->dev.release = &acpi_device_release; | 749 | device->dev.release = release; |
672 | result = device_register(&device->dev); | 750 | result = device_add(&device->dev); |
673 | if (result) { | 751 | if (result) { |
674 | dev_err(&device->dev, "Error registering device\n"); | 752 | dev_err(&device->dev, "Error registering device\n"); |
675 | goto end; | 753 | goto err; |
676 | } | 754 | } |
677 | 755 | ||
678 | result = acpi_device_setup_files(device); | 756 | result = acpi_device_setup_files(device); |
@@ -682,12 +760,16 @@ static int acpi_device_register(struct acpi_device *device) | |||
682 | 760 | ||
683 | device->removal_type = ACPI_BUS_REMOVAL_NORMAL; | 761 | device->removal_type = ACPI_BUS_REMOVAL_NORMAL; |
684 | return 0; | 762 | return 0; |
685 | end: | 763 | |
764 | err: | ||
686 | mutex_lock(&acpi_device_lock); | 765 | mutex_lock(&acpi_device_lock); |
687 | if (device->parent) | 766 | if (device->parent) |
688 | list_del(&device->node); | 767 | list_del(&device->node); |
689 | list_del(&device->wakeup_list); | 768 | list_del(&device->wakeup_list); |
690 | mutex_unlock(&acpi_device_lock); | 769 | mutex_unlock(&acpi_device_lock); |
770 | |||
771 | err_detach: | ||
772 | acpi_detach_data(device->handle, acpi_bus_data_handler); | ||
691 | return result; | 773 | return result; |
692 | } | 774 | } |
693 | 775 | ||
@@ -702,8 +784,18 @@ static void acpi_device_unregister(struct acpi_device *device) | |||
702 | 784 | ||
703 | acpi_detach_data(device->handle, acpi_bus_data_handler); | 785 | acpi_detach_data(device->handle, acpi_bus_data_handler); |
704 | 786 | ||
787 | acpi_power_add_remove_device(device, false); | ||
705 | acpi_device_remove_files(device); | 788 | acpi_device_remove_files(device); |
706 | device_unregister(&device->dev); | 789 | if (device->remove) |
790 | device->remove(device); | ||
791 | |||
792 | device_del(&device->dev); | ||
793 | /* | ||
794 | * Drop the reference counts of all power resources the device depends | ||
795 | * on and turn off the ones that have no more references. | ||
796 | */ | ||
797 | acpi_power_transition(device, ACPI_STATE_D3_COLD); | ||
798 | put_device(&device->dev); | ||
707 | } | 799 | } |
708 | 800 | ||
709 | /* -------------------------------------------------------------------------- | 801 | /* -------------------------------------------------------------------------- |
@@ -846,52 +938,43 @@ void acpi_bus_data_handler(acpi_handle handle, void *context) | |||
846 | return; | 938 | return; |
847 | } | 939 | } |
848 | 940 | ||
849 | static int acpi_bus_get_perf_flags(struct acpi_device *device) | 941 | static int acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, |
850 | { | 942 | 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 | { | 943 | { |
859 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | 944 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; |
860 | union acpi_object *package = NULL; | 945 | union acpi_object *package = NULL; |
861 | union acpi_object *element = NULL; | 946 | union acpi_object *element = NULL; |
862 | acpi_status status; | 947 | acpi_status status; |
863 | int i = 0; | 948 | int err = -ENODATA; |
864 | 949 | ||
865 | if (!wakeup) | 950 | if (!wakeup) |
866 | return AE_BAD_PARAMETER; | 951 | return -EINVAL; |
952 | |||
953 | INIT_LIST_HEAD(&wakeup->resources); | ||
867 | 954 | ||
868 | /* _PRW */ | 955 | /* _PRW */ |
869 | status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer); | 956 | status = acpi_evaluate_object(handle, "_PRW", NULL, &buffer); |
870 | if (ACPI_FAILURE(status)) { | 957 | if (ACPI_FAILURE(status)) { |
871 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); | 958 | ACPI_EXCEPTION((AE_INFO, status, "Evaluating _PRW")); |
872 | return status; | 959 | return err; |
873 | } | 960 | } |
874 | 961 | ||
875 | package = (union acpi_object *)buffer.pointer; | 962 | package = (union acpi_object *)buffer.pointer; |
876 | 963 | ||
877 | if (!package || (package->package.count < 2)) { | 964 | if (!package || package->package.count < 2) |
878 | status = AE_BAD_DATA; | ||
879 | goto out; | 965 | goto out; |
880 | } | ||
881 | 966 | ||
882 | element = &(package->package.elements[0]); | 967 | element = &(package->package.elements[0]); |
883 | if (!element) { | 968 | if (!element) |
884 | status = AE_BAD_DATA; | ||
885 | goto out; | 969 | goto out; |
886 | } | 970 | |
887 | if (element->type == ACPI_TYPE_PACKAGE) { | 971 | if (element->type == ACPI_TYPE_PACKAGE) { |
888 | if ((element->package.count < 2) || | 972 | if ((element->package.count < 2) || |
889 | (element->package.elements[0].type != | 973 | (element->package.elements[0].type != |
890 | ACPI_TYPE_LOCAL_REFERENCE) | 974 | ACPI_TYPE_LOCAL_REFERENCE) |
891 | || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) { | 975 | || (element->package.elements[1].type != ACPI_TYPE_INTEGER)) |
892 | status = AE_BAD_DATA; | ||
893 | goto out; | 976 | goto out; |
894 | } | 977 | |
895 | wakeup->gpe_device = | 978 | wakeup->gpe_device = |
896 | element->package.elements[0].reference.handle; | 979 | element->package.elements[0].reference.handle; |
897 | wakeup->gpe_number = | 980 | wakeup->gpe_number = |
@@ -900,38 +983,35 @@ acpi_bus_extract_wakeup_device_power_package(acpi_handle handle, | |||
900 | wakeup->gpe_device = NULL; | 983 | wakeup->gpe_device = NULL; |
901 | wakeup->gpe_number = element->integer.value; | 984 | wakeup->gpe_number = element->integer.value; |
902 | } else { | 985 | } else { |
903 | status = AE_BAD_DATA; | ||
904 | goto out; | 986 | goto out; |
905 | } | 987 | } |
906 | 988 | ||
907 | element = &(package->package.elements[1]); | 989 | element = &(package->package.elements[1]); |
908 | if (element->type != ACPI_TYPE_INTEGER) { | 990 | if (element->type != ACPI_TYPE_INTEGER) |
909 | status = AE_BAD_DATA; | ||
910 | goto out; | 991 | goto out; |
911 | } | 992 | |
912 | wakeup->sleep_state = element->integer.value; | 993 | wakeup->sleep_state = element->integer.value; |
913 | 994 | ||
914 | if ((package->package.count - 2) > ACPI_MAX_HANDLES) { | 995 | err = acpi_extract_power_resources(package, 2, &wakeup->resources); |
915 | status = AE_NO_MEMORY; | 996 | if (err) |
916 | goto out; | 997 | 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 | 998 | ||
926 | wakeup->resources.handles[i] = element->reference.handle; | 999 | if (!list_empty(&wakeup->resources)) { |
927 | } | 1000 | int sleep_state; |
928 | 1001 | ||
1002 | sleep_state = acpi_power_min_system_level(&wakeup->resources); | ||
1003 | if (sleep_state < wakeup->sleep_state) { | ||
1004 | acpi_handle_warn(handle, "Overriding _PRW sleep state " | ||
1005 | "(S%d) by S%d from power resources\n", | ||
1006 | (int)wakeup->sleep_state, sleep_state); | ||
1007 | wakeup->sleep_state = sleep_state; | ||
1008 | } | ||
1009 | } | ||
929 | acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number); | 1010 | acpi_setup_gpe_for_wake(handle, wakeup->gpe_device, wakeup->gpe_number); |
930 | 1011 | ||
931 | out: | 1012 | out: |
932 | kfree(buffer.pointer); | 1013 | kfree(buffer.pointer); |
933 | 1014 | return err; | |
934 | return status; | ||
935 | } | 1015 | } |
936 | 1016 | ||
937 | static void acpi_bus_set_run_wake_flags(struct acpi_device *device) | 1017 | static void acpi_bus_set_run_wake_flags(struct acpi_device *device) |
@@ -971,17 +1051,17 @@ static void acpi_bus_get_wakeup_device_flags(struct acpi_device *device) | |||
971 | { | 1051 | { |
972 | acpi_handle temp; | 1052 | acpi_handle temp; |
973 | acpi_status status = 0; | 1053 | acpi_status status = 0; |
974 | int psw_error; | 1054 | int err; |
975 | 1055 | ||
976 | /* Presence of _PRW indicates wake capable */ | 1056 | /* Presence of _PRW indicates wake capable */ |
977 | status = acpi_get_handle(device->handle, "_PRW", &temp); | 1057 | status = acpi_get_handle(device->handle, "_PRW", &temp); |
978 | if (ACPI_FAILURE(status)) | 1058 | if (ACPI_FAILURE(status)) |
979 | return; | 1059 | return; |
980 | 1060 | ||
981 | status = acpi_bus_extract_wakeup_device_power_package(device->handle, | 1061 | err = acpi_bus_extract_wakeup_device_power_package(device->handle, |
982 | &device->wakeup); | 1062 | &device->wakeup); |
983 | if (ACPI_FAILURE(status)) { | 1063 | if (err) { |
984 | ACPI_EXCEPTION((AE_INFO, status, "Extracting _PRW package")); | 1064 | dev_err(&device->dev, "_PRW evaluation error: %d\n", err); |
985 | return; | 1065 | return; |
986 | } | 1066 | } |
987 | 1067 | ||
@@ -994,20 +1074,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 | 1074 | * So it is necessary to call _DSW object first. Only when it is not |
995 | * present will the _PSW object used. | 1075 | * present will the _PSW object used. |
996 | */ | 1076 | */ |
997 | psw_error = acpi_device_sleep_wake(device, 0, 0, 0); | 1077 | err = acpi_device_sleep_wake(device, 0, 0, 0); |
998 | if (psw_error) | 1078 | if (err) |
999 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | 1079 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
1000 | "error in _DSW or _PSW evaluation\n")); | 1080 | "error in _DSW or _PSW evaluation\n")); |
1001 | } | 1081 | } |
1002 | 1082 | ||
1003 | static void acpi_bus_add_power_resource(acpi_handle handle); | 1083 | static void acpi_bus_init_power_state(struct acpi_device *device, int state) |
1084 | { | ||
1085 | struct acpi_device_power_state *ps = &device->power.states[state]; | ||
1086 | char pathname[5] = { '_', 'P', 'R', '0' + state, '\0' }; | ||
1087 | struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
1088 | acpi_handle handle; | ||
1089 | acpi_status status; | ||
1090 | |||
1091 | INIT_LIST_HEAD(&ps->resources); | ||
1004 | 1092 | ||
1005 | static int acpi_bus_get_power_flags(struct acpi_device *device) | 1093 | /* Evaluate "_PRx" to get referenced power resources */ |
1094 | status = acpi_evaluate_object(device->handle, pathname, NULL, &buffer); | ||
1095 | if (ACPI_SUCCESS(status)) { | ||
1096 | union acpi_object *package = buffer.pointer; | ||
1097 | |||
1098 | if (buffer.length && package | ||
1099 | && package->type == ACPI_TYPE_PACKAGE | ||
1100 | && package->package.count) { | ||
1101 | int err = acpi_extract_power_resources(package, 0, | ||
1102 | &ps->resources); | ||
1103 | if (!err) | ||
1104 | device->power.flags.power_resources = 1; | ||
1105 | } | ||
1106 | ACPI_FREE(buffer.pointer); | ||
1107 | } | ||
1108 | |||
1109 | /* Evaluate "_PSx" to see if we can do explicit sets */ | ||
1110 | pathname[2] = 'S'; | ||
1111 | status = acpi_get_handle(device->handle, pathname, &handle); | ||
1112 | if (ACPI_SUCCESS(status)) | ||
1113 | ps->flags.explicit_set = 1; | ||
1114 | |||
1115 | /* | ||
1116 | * State is valid if there are means to put the device into it. | ||
1117 | * D3hot is only valid if _PR3 present. | ||
1118 | */ | ||
1119 | if (!list_empty(&ps->resources) | ||
1120 | || (ps->flags.explicit_set && state < ACPI_STATE_D3_HOT)) { | ||
1121 | ps->flags.valid = 1; | ||
1122 | ps->flags.os_accessible = 1; | ||
1123 | } | ||
1124 | |||
1125 | ps->power = -1; /* Unknown - driver assigned */ | ||
1126 | ps->latency = -1; /* Unknown - driver assigned */ | ||
1127 | } | ||
1128 | |||
1129 | static void acpi_bus_get_power_flags(struct acpi_device *device) | ||
1006 | { | 1130 | { |
1007 | acpi_status status = 0; | 1131 | acpi_status status; |
1008 | acpi_handle handle = NULL; | 1132 | acpi_handle handle; |
1009 | u32 i = 0; | 1133 | u32 i; |
1010 | 1134 | ||
1135 | /* Presence of _PS0|_PR0 indicates 'power manageable' */ | ||
1136 | status = acpi_get_handle(device->handle, "_PS0", &handle); | ||
1137 | if (ACPI_FAILURE(status)) { | ||
1138 | status = acpi_get_handle(device->handle, "_PR0", &handle); | ||
1139 | if (ACPI_FAILURE(status)) | ||
1140 | return; | ||
1141 | } | ||
1142 | |||
1143 | device->flags.power_manageable = 1; | ||
1011 | 1144 | ||
1012 | /* | 1145 | /* |
1013 | * Power Management Flags | 1146 | * Power Management Flags |
@@ -1022,40 +1155,10 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) | |||
1022 | /* | 1155 | /* |
1023 | * Enumerate supported power management states | 1156 | * Enumerate supported power management states |
1024 | */ | 1157 | */ |
1025 | for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) { | 1158 | for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3_HOT; i++) |
1026 | struct acpi_device_power_state *ps = &device->power.states[i]; | 1159 | acpi_bus_init_power_state(device, i); |
1027 | char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' }; | ||
1028 | 1160 | ||
1029 | /* Evaluate "_PRx" to se if power resources are referenced */ | 1161 | INIT_LIST_HEAD(&device->power.states[ACPI_STATE_D3_COLD].resources); |
1030 | acpi_evaluate_reference(device->handle, object_name, NULL, | ||
1031 | &ps->resources); | ||
1032 | if (ps->resources.count) { | ||
1033 | int j; | ||
1034 | |||
1035 | device->power.flags.power_resources = 1; | ||
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 | 1162 | ||
1060 | /* Set defaults for D0 and D3 states (always valid) */ | 1163 | /* Set defaults for D0 and D3 states (always valid) */ |
1061 | device->power.states[ACPI_STATE_D0].flags.valid = 1; | 1164 | device->power.states[ACPI_STATE_D0].flags.valid = 1; |
@@ -1073,16 +1176,13 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) | |||
1073 | device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1; | 1176 | device->power.states[ACPI_STATE_D3_COLD].flags.os_accessible = 1; |
1074 | 1177 | ||
1075 | acpi_bus_init_power(device); | 1178 | acpi_bus_init_power(device); |
1076 | |||
1077 | return 0; | ||
1078 | } | 1179 | } |
1079 | 1180 | ||
1080 | static int acpi_bus_get_flags(struct acpi_device *device) | 1181 | static void acpi_bus_get_flags(struct acpi_device *device) |
1081 | { | 1182 | { |
1082 | acpi_status status = AE_OK; | 1183 | acpi_status status = AE_OK; |
1083 | acpi_handle temp = NULL; | 1184 | acpi_handle temp = NULL; |
1084 | 1185 | ||
1085 | |||
1086 | /* Presence of _STA indicates 'dynamic_status' */ | 1186 | /* Presence of _STA indicates 'dynamic_status' */ |
1087 | status = acpi_get_handle(device->handle, "_STA", &temp); | 1187 | status = acpi_get_handle(device->handle, "_STA", &temp); |
1088 | if (ACPI_SUCCESS(status)) | 1188 | if (ACPI_SUCCESS(status)) |
@@ -1102,21 +1202,6 @@ static int acpi_bus_get_flags(struct acpi_device *device) | |||
1102 | if (ACPI_SUCCESS(status)) | 1202 | if (ACPI_SUCCESS(status)) |
1103 | device->flags.ejectable = 1; | 1203 | device->flags.ejectable = 1; |
1104 | } | 1204 | } |
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 | } | 1205 | } |
1121 | 1206 | ||
1122 | static void acpi_device_get_busid(struct acpi_device *device) | 1207 | static void acpi_device_get_busid(struct acpi_device *device) |
@@ -1315,7 +1400,7 @@ static void acpi_device_set_id(struct acpi_device *device) | |||
1315 | acpi_add_id(device, ACPI_DOCK_HID); | 1400 | acpi_add_id(device, ACPI_DOCK_HID); |
1316 | else if (!acpi_ibm_smbus_match(device)) | 1401 | else if (!acpi_ibm_smbus_match(device)) |
1317 | acpi_add_id(device, ACPI_SMBUS_IBM_HID); | 1402 | acpi_add_id(device, ACPI_SMBUS_IBM_HID); |
1318 | else if (!acpi_device_hid(device) && | 1403 | else if (list_empty(&device->pnp.ids) && |
1319 | ACPI_IS_ROOT_DEVICE(device->parent)) { | 1404 | ACPI_IS_ROOT_DEVICE(device->parent)) { |
1320 | acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */ | 1405 | acpi_add_id(device, ACPI_BUS_HID); /* \_SB, LNXSYBUS */ |
1321 | strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); | 1406 | strcpy(device->pnp.device_name, ACPI_BUS_DEVICE_NAME); |
@@ -1341,32 +1426,32 @@ static void acpi_device_set_id(struct acpi_device *device) | |||
1341 | } | 1426 | } |
1342 | } | 1427 | } |
1343 | 1428 | ||
1344 | static int acpi_device_set_context(struct acpi_device *device) | 1429 | void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, |
1430 | int type, unsigned long long sta) | ||
1345 | { | 1431 | { |
1346 | acpi_status status; | 1432 | INIT_LIST_HEAD(&device->pnp.ids); |
1347 | 1433 | device->device_type = type; | |
1348 | /* | 1434 | device->handle = handle; |
1349 | * Context | 1435 | device->parent = acpi_bus_get_parent(handle); |
1350 | * ------- | 1436 | STRUCT_TO_INT(device->status) = sta; |
1351 | * Attach this 'struct acpi_device' to the ACPI object. This makes | 1437 | acpi_device_get_busid(device); |
1352 | * resolutions from handle->device very efficient. Fixed hardware | 1438 | acpi_device_set_id(device); |
1353 | * devices have no handles, so we skip them. | 1439 | acpi_bus_get_flags(device); |
1354 | */ | 1440 | device->flags.match_driver = false; |
1355 | if (!device->handle) | 1441 | device_initialize(&device->dev); |
1356 | return 0; | 1442 | dev_set_uevent_suppress(&device->dev, true); |
1357 | 1443 | } | |
1358 | status = acpi_attach_data(device->handle, | ||
1359 | acpi_bus_data_handler, device); | ||
1360 | if (ACPI_SUCCESS(status)) | ||
1361 | return 0; | ||
1362 | 1444 | ||
1363 | printk(KERN_ERR PREFIX "Error attaching device data\n"); | 1445 | void acpi_device_add_finalize(struct acpi_device *device) |
1364 | return -ENODEV; | 1446 | { |
1447 | device->flags.match_driver = true; | ||
1448 | dev_set_uevent_suppress(&device->dev, false); | ||
1449 | kobject_uevent(&device->dev.kobj, KOBJ_ADD); | ||
1365 | } | 1450 | } |
1366 | 1451 | ||
1367 | static int acpi_add_single_object(struct acpi_device **child, | 1452 | static int acpi_add_single_object(struct acpi_device **child, |
1368 | acpi_handle handle, int type, | 1453 | acpi_handle handle, int type, |
1369 | unsigned long long sta, bool match_driver) | 1454 | unsigned long long sta) |
1370 | { | 1455 | { |
1371 | int result; | 1456 | int result; |
1372 | struct acpi_device *device; | 1457 | struct acpi_device *device; |
@@ -1378,90 +1463,25 @@ static int acpi_add_single_object(struct acpi_device **child, | |||
1378 | return -ENOMEM; | 1463 | return -ENOMEM; |
1379 | } | 1464 | } |
1380 | 1465 | ||
1381 | INIT_LIST_HEAD(&device->pnp.ids); | 1466 | acpi_init_device_object(device, handle, type, sta); |
1382 | device->device_type = type; | 1467 | 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); | 1468 | acpi_bus_get_wakeup_device_flags(device); |
1421 | 1469 | ||
1422 | /* | 1470 | result = acpi_device_add(device, acpi_device_release); |
1423 | * Performance Management | 1471 | if (result) { |
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; | ||
1436 | result = acpi_device_register(device); | ||
1437 | |||
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); | 1472 | acpi_device_release(&device->dev); |
1473 | return result; | ||
1474 | } | ||
1450 | 1475 | ||
1451 | return result; | 1476 | acpi_power_add_remove_device(device, true); |
1452 | } | 1477 | acpi_device_add_finalize(device); |
1453 | 1478 | acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); | |
1454 | #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ | 1479 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Added %s [%s] parent %s\n", |
1455 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) | 1480 | dev_name(&device->dev), (char *) buffer.pointer, |
1456 | 1481 | device->parent ? dev_name(&device->parent->dev) : "(null)")); | |
1457 | static void acpi_bus_add_power_resource(acpi_handle handle) | 1482 | kfree(buffer.pointer); |
1458 | { | 1483 | *child = device; |
1459 | struct acpi_device *device = NULL; | 1484 | 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 | } | 1485 | } |
1466 | 1486 | ||
1467 | static int acpi_bus_type_and_status(acpi_handle handle, int *type, | 1487 | static int acpi_bus_type_and_status(acpi_handle handle, int *type, |
@@ -1520,25 +1540,29 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, | |||
1520 | if (result) | 1540 | if (result) |
1521 | return AE_OK; | 1541 | return AE_OK; |
1522 | 1542 | ||
1543 | if (type == ACPI_BUS_TYPE_POWER) { | ||
1544 | acpi_add_power_resource(handle); | ||
1545 | return AE_OK; | ||
1546 | } | ||
1547 | |||
1523 | if (!(sta & ACPI_STA_DEVICE_PRESENT) && | 1548 | if (!(sta & ACPI_STA_DEVICE_PRESENT) && |
1524 | !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { | 1549 | !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { |
1525 | struct acpi_device_wakeup wakeup; | 1550 | struct acpi_device_wakeup wakeup; |
1526 | acpi_handle temp; | 1551 | acpi_handle temp; |
1527 | 1552 | ||
1528 | status = acpi_get_handle(handle, "_PRW", &temp); | 1553 | status = acpi_get_handle(handle, "_PRW", &temp); |
1529 | if (ACPI_SUCCESS(status)) | 1554 | if (ACPI_SUCCESS(status)) { |
1530 | acpi_bus_extract_wakeup_device_power_package(handle, | 1555 | acpi_bus_extract_wakeup_device_power_package(handle, |
1531 | &wakeup); | 1556 | &wakeup); |
1557 | acpi_power_resources_list_free(&wakeup.resources); | ||
1558 | } | ||
1532 | return AE_CTRL_DEPTH; | 1559 | return AE_CTRL_DEPTH; |
1533 | } | 1560 | } |
1534 | 1561 | ||
1535 | acpi_add_single_object(&device, handle, type, sta, | 1562 | acpi_add_single_object(&device, handle, type, sta); |
1536 | type == ACPI_BUS_TYPE_POWER); | ||
1537 | if (!device) | 1563 | if (!device) |
1538 | return AE_CTRL_DEPTH; | 1564 | return AE_CTRL_DEPTH; |
1539 | 1565 | ||
1540 | device->flags.match_driver = true; | ||
1541 | |||
1542 | out: | 1566 | out: |
1543 | if (!*return_value) | 1567 | if (!*return_value) |
1544 | *return_value = device; | 1568 | *return_value = device; |
@@ -1656,25 +1680,39 @@ EXPORT_SYMBOL_GPL(acpi_bus_trim); | |||
1656 | static int acpi_bus_scan_fixed(void) | 1680 | static int acpi_bus_scan_fixed(void) |
1657 | { | 1681 | { |
1658 | int result = 0; | 1682 | int result = 0; |
1659 | struct acpi_device *device = NULL; | ||
1660 | 1683 | ||
1661 | /* | 1684 | /* |
1662 | * Enumerate all fixed-feature devices. | 1685 | * Enumerate all fixed-feature devices. |
1663 | */ | 1686 | */ |
1664 | if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) { | 1687 | if (!(acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON)) { |
1688 | struct acpi_device *device = NULL; | ||
1689 | |||
1665 | result = acpi_add_single_object(&device, NULL, | 1690 | result = acpi_add_single_object(&device, NULL, |
1666 | ACPI_BUS_TYPE_POWER_BUTTON, | 1691 | ACPI_BUS_TYPE_POWER_BUTTON, |
1667 | ACPI_STA_DEFAULT, true); | 1692 | ACPI_STA_DEFAULT); |
1693 | if (result) | ||
1694 | return result; | ||
1695 | |||
1696 | result = device_attach(&device->dev); | ||
1697 | if (result < 0) | ||
1698 | return result; | ||
1699 | |||
1668 | device_init_wakeup(&device->dev, true); | 1700 | device_init_wakeup(&device->dev, true); |
1669 | } | 1701 | } |
1670 | 1702 | ||
1671 | if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) { | 1703 | if (!(acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON)) { |
1704 | struct acpi_device *device = NULL; | ||
1705 | |||
1672 | result = acpi_add_single_object(&device, NULL, | 1706 | result = acpi_add_single_object(&device, NULL, |
1673 | ACPI_BUS_TYPE_SLEEP_BUTTON, | 1707 | ACPI_BUS_TYPE_SLEEP_BUTTON, |
1674 | ACPI_STA_DEFAULT, true); | 1708 | ACPI_STA_DEFAULT); |
1709 | if (result) | ||
1710 | return result; | ||
1711 | |||
1712 | result = device_attach(&device->dev); | ||
1675 | } | 1713 | } |
1676 | 1714 | ||
1677 | return result; | 1715 | return result < 0 ? result : 0; |
1678 | } | 1716 | } |
1679 | 1717 | ||
1680 | int __init acpi_scan_init(void) | 1718 | int __init acpi_scan_init(void) |
@@ -1687,7 +1725,6 @@ int __init acpi_scan_init(void) | |||
1687 | printk(KERN_ERR PREFIX "Could not register bus type\n"); | 1725 | printk(KERN_ERR PREFIX "Could not register bus type\n"); |
1688 | } | 1726 | } |
1689 | 1727 | ||
1690 | acpi_power_init(); | ||
1691 | acpi_pci_root_init(); | 1728 | acpi_pci_root_init(); |
1692 | 1729 | ||
1693 | /* | 1730 | /* |