Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * wakeup.c - support wakeup devices | |
3 | * Copyright (C) 2004 Li Shaohua <shaohua.li@intel.com> | |
4 | */ | |
5 | ||
6 | #include <linux/init.h> | |
7 | #include <linux/acpi.h> | |
8 | #include <acpi/acpi_drivers.h> | |
9 | #include <linux/kernel.h> | |
10 | #include <linux/types.h> | |
e60cc7a6 BH |
11 | |
12 | #include "internal.h" | |
1da177e4 LT |
13 | #include "sleep.h" |
14 | ||
9090589d SL |
15 | /* |
16 | * We didn't lock acpi_device_lock in the file, because it invokes oops in | |
17 | * suspend/resume and isn't really required as this is called in S-state. At | |
18 | * that time, there is no device hotplug | |
19 | **/ | |
1da177e4 | 20 | #define _COMPONENT ACPI_SYSTEM_COMPONENT |
4be44fcd | 21 | ACPI_MODULE_NAME("wakeup_devices") |
1da177e4 | 22 | |
1da177e4 | 23 | /** |
9630bdd9 RW |
24 | * acpi_enable_wakeup_device_prep - Prepare wake-up devices. |
25 | * @sleep_state: ACPI system sleep state. | |
26 | * | |
27 | * Enable all wake-up devices' power, unless the requested system sleep state is | |
28 | * too deep. | |
1da177e4 | 29 | */ |
4be44fcd | 30 | void acpi_enable_wakeup_device_prep(u8 sleep_state) |
1da177e4 | 31 | { |
4be44fcd | 32 | struct list_head *node, *next; |
1da177e4 | 33 | |
1da177e4 | 34 | list_for_each_safe(node, next, &acpi_wakeup_device_list) { |
4be44fcd LB |
35 | struct acpi_device *dev = container_of(node, |
36 | struct acpi_device, | |
37 | wakeup_list); | |
38 | ||
9630bdd9 RW |
39 | if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled |
40 | || (sleep_state > (u32) dev->wakeup.sleep_state)) | |
1da177e4 LT |
41 | continue; |
42 | ||
77e76609 | 43 | acpi_enable_wakeup_device_power(dev, sleep_state); |
1da177e4 | 44 | } |
1da177e4 LT |
45 | } |
46 | ||
47 | /** | |
9630bdd9 RW |
48 | * acpi_enable_wakeup_device - Enable wake-up device GPEs. |
49 | * @sleep_state: ACPI system sleep state. | |
50 | * | |
51 | * Enable all wake-up devices' GPEs, with the assumption that | |
52 | * acpi_disable_all_gpes() was executed before, so we don't need to disable any | |
53 | * GPEs here. | |
1da177e4 | 54 | */ |
4be44fcd | 55 | void acpi_enable_wakeup_device(u8 sleep_state) |
1da177e4 | 56 | { |
4be44fcd | 57 | struct list_head *node, *next; |
1da177e4 LT |
58 | |
59 | /* | |
60 | * Caution: this routine must be invoked when interrupt is disabled | |
61 | * Refer ACPI2.0: P212 | |
62 | */ | |
1da177e4 | 63 | list_for_each_safe(node, next, &acpi_wakeup_device_list) { |
9b039330 AS |
64 | struct acpi_device *dev = |
65 | container_of(node, struct acpi_device, wakeup_list); | |
eb9d0fe4 | 66 | |
9b039330 AS |
67 | if (!dev->wakeup.flags.valid) |
68 | continue; | |
eb9d0fe4 | 69 | |
9b83ccd2 | 70 | if ((!dev->wakeup.state.enabled && !dev->wakeup.prepare_count) |
9630bdd9 | 71 | || sleep_state > (u32) dev->wakeup.sleep_state) |
1da177e4 | 72 | continue; |
9630bdd9 RW |
73 | |
74 | /* The wake-up power should have been enabled already. */ | |
75 | acpi_set_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, | |
76 | ACPI_GPE_ENABLE); | |
1da177e4 | 77 | } |
1da177e4 LT |
78 | } |
79 | ||
80 | /** | |
9630bdd9 RW |
81 | * acpi_disable_wakeup_device - Disable devices' wakeup capability. |
82 | * @sleep_state: ACPI system sleep state. | |
83 | * | |
84 | * This function only affects devices with wakeup.state.enabled set, which means | |
85 | * that it reverses the changes made by acpi_enable_wakeup_device_prep(). | |
1da177e4 | 86 | */ |
4be44fcd | 87 | void acpi_disable_wakeup_device(u8 sleep_state) |
1da177e4 | 88 | { |
4be44fcd | 89 | struct list_head *node, *next; |
1da177e4 | 90 | |
1da177e4 | 91 | list_for_each_safe(node, next, &acpi_wakeup_device_list) { |
9b039330 AS |
92 | struct acpi_device *dev = |
93 | container_of(node, struct acpi_device, wakeup_list); | |
1da177e4 | 94 | |
9630bdd9 RW |
95 | if (!dev->wakeup.flags.valid || !dev->wakeup.state.enabled |
96 | || (sleep_state > (u32) dev->wakeup.sleep_state)) | |
1da177e4 LT |
97 | continue; |
98 | ||
1da177e4 | 99 | acpi_disable_wakeup_device_power(dev); |
1da177e4 | 100 | } |
1da177e4 LT |
101 | } |
102 | ||
201b8c65 | 103 | int __init acpi_wakeup_device_init(void) |
1da177e4 | 104 | { |
4be44fcd | 105 | struct list_head *node, *next; |
1da177e4 | 106 | |
9090589d | 107 | mutex_lock(&acpi_device_lock); |
1da177e4 | 108 | list_for_each_safe(node, next, &acpi_wakeup_device_list) { |
4be44fcd LB |
109 | struct acpi_device *dev = container_of(node, |
110 | struct acpi_device, | |
111 | wakeup_list); | |
1da177e4 | 112 | /* In case user doesn't load button driver */ |
f517709d RW |
113 | if (!dev->wakeup.flags.always_enabled || |
114 | dev->wakeup.state.enabled) | |
9b039330 | 115 | continue; |
9630bdd9 RW |
116 | acpi_enable_gpe(dev->wakeup.gpe_device, dev->wakeup.gpe_number, |
117 | ACPI_GPE_TYPE_WAKE); | |
9b039330 | 118 | dev->wakeup.state.enabled = 1; |
1da177e4 | 119 | } |
9090589d | 120 | mutex_unlock(&acpi_device_lock); |
1da177e4 LT |
121 | return 0; |
122 | } |