diff options
Diffstat (limited to 'drivers/pnp/pnpacpi')
-rw-r--r-- | drivers/pnp/pnpacpi/core.c | 124 |
1 files changed, 92 insertions, 32 deletions
diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index dc4e32e031e9..ca84d5099ce7 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c | |||
@@ -28,7 +28,7 @@ | |||
28 | #include "../base.h" | 28 | #include "../base.h" |
29 | #include "pnpacpi.h" | 29 | #include "pnpacpi.h" |
30 | 30 | ||
31 | static int num = 0; | 31 | static int num; |
32 | 32 | ||
33 | /* We need only to blacklist devices that have already an acpi driver that | 33 | /* We need only to blacklist devices that have already an acpi driver that |
34 | * can't use pnp layer. We don't need to blacklist device that are directly | 34 | * can't use pnp layer. We don't need to blacklist device that are directly |
@@ -59,7 +59,7 @@ static inline int __init is_exclusive_device(struct acpi_device *dev) | |||
59 | #define TEST_ALPHA(c) \ | 59 | #define TEST_ALPHA(c) \ |
60 | if (!('@' <= (c) || (c) <= 'Z')) \ | 60 | if (!('@' <= (c) || (c) <= 'Z')) \ |
61 | return 0 | 61 | return 0 |
62 | static int __init ispnpidacpi(char *id) | 62 | static int __init ispnpidacpi(const char *id) |
63 | { | 63 | { |
64 | TEST_ALPHA(id[0]); | 64 | TEST_ALPHA(id[0]); |
65 | TEST_ALPHA(id[1]); | 65 | TEST_ALPHA(id[1]); |
@@ -81,12 +81,19 @@ static int pnpacpi_get_resources(struct pnp_dev *dev) | |||
81 | 81 | ||
82 | static int pnpacpi_set_resources(struct pnp_dev *dev) | 82 | static int pnpacpi_set_resources(struct pnp_dev *dev) |
83 | { | 83 | { |
84 | struct acpi_device *acpi_dev = dev->data; | 84 | struct acpi_device *acpi_dev; |
85 | acpi_handle handle = acpi_dev->handle; | 85 | acpi_handle handle; |
86 | struct acpi_buffer buffer; | 86 | struct acpi_buffer buffer; |
87 | int ret; | 87 | int ret; |
88 | 88 | ||
89 | pnp_dbg(&dev->dev, "set resources\n"); | 89 | pnp_dbg(&dev->dev, "set resources\n"); |
90 | |||
91 | handle = DEVICE_ACPI_HANDLE(&dev->dev); | ||
92 | if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) { | ||
93 | dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); | ||
94 | return -ENODEV; | ||
95 | } | ||
96 | |||
90 | ret = pnpacpi_build_resource_template(dev, &buffer); | 97 | ret = pnpacpi_build_resource_template(dev, &buffer); |
91 | if (ret) | 98 | if (ret) |
92 | return ret; | 99 | return ret; |
@@ -105,12 +112,18 @@ static int pnpacpi_set_resources(struct pnp_dev *dev) | |||
105 | 112 | ||
106 | static int pnpacpi_disable_resources(struct pnp_dev *dev) | 113 | static int pnpacpi_disable_resources(struct pnp_dev *dev) |
107 | { | 114 | { |
108 | struct acpi_device *acpi_dev = dev->data; | 115 | struct acpi_device *acpi_dev; |
109 | acpi_handle handle = acpi_dev->handle; | 116 | acpi_handle handle; |
110 | int ret; | 117 | int ret; |
111 | 118 | ||
112 | dev_dbg(&dev->dev, "disable resources\n"); | 119 | dev_dbg(&dev->dev, "disable resources\n"); |
113 | 120 | ||
121 | handle = DEVICE_ACPI_HANDLE(&dev->dev); | ||
122 | if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) { | ||
123 | dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
114 | /* acpi_unregister_gsi(pnp_irq(dev, 0)); */ | 127 | /* acpi_unregister_gsi(pnp_irq(dev, 0)); */ |
115 | ret = 0; | 128 | ret = 0; |
116 | if (acpi_bus_power_manageable(handle)) | 129 | if (acpi_bus_power_manageable(handle)) |
@@ -124,46 +137,74 @@ static int pnpacpi_disable_resources(struct pnp_dev *dev) | |||
124 | #ifdef CONFIG_ACPI_SLEEP | 137 | #ifdef CONFIG_ACPI_SLEEP |
125 | static bool pnpacpi_can_wakeup(struct pnp_dev *dev) | 138 | static bool pnpacpi_can_wakeup(struct pnp_dev *dev) |
126 | { | 139 | { |
127 | struct acpi_device *acpi_dev = dev->data; | 140 | struct acpi_device *acpi_dev; |
128 | acpi_handle handle = acpi_dev->handle; | 141 | acpi_handle handle; |
142 | |||
143 | handle = DEVICE_ACPI_HANDLE(&dev->dev); | ||
144 | if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) { | ||
145 | dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); | ||
146 | return false; | ||
147 | } | ||
129 | 148 | ||
130 | return acpi_bus_can_wakeup(handle); | 149 | return acpi_bus_can_wakeup(handle); |
131 | } | 150 | } |
132 | 151 | ||
133 | static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) | 152 | static int pnpacpi_suspend(struct pnp_dev *dev, pm_message_t state) |
134 | { | 153 | { |
135 | struct acpi_device *acpi_dev = dev->data; | 154 | struct acpi_device *acpi_dev; |
136 | acpi_handle handle = acpi_dev->handle; | 155 | acpi_handle handle; |
137 | int power_state; | 156 | int error = 0; |
157 | |||
158 | handle = DEVICE_ACPI_HANDLE(&dev->dev); | ||
159 | if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) { | ||
160 | dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); | ||
161 | return 0; | ||
162 | } | ||
138 | 163 | ||
139 | if (device_can_wakeup(&dev->dev)) { | 164 | if (device_can_wakeup(&dev->dev)) { |
140 | int rc = acpi_pm_device_sleep_wake(&dev->dev, | 165 | error = acpi_pm_device_sleep_wake(&dev->dev, |
141 | device_may_wakeup(&dev->dev)); | 166 | device_may_wakeup(&dev->dev)); |
167 | if (error) | ||
168 | return error; | ||
169 | } | ||
170 | |||
171 | if (acpi_bus_power_manageable(handle)) { | ||
172 | int power_state = acpi_pm_device_sleep_state(&dev->dev, NULL); | ||
142 | 173 | ||
143 | if (rc) | 174 | if (power_state < 0) |
144 | return rc; | 175 | power_state = (state.event == PM_EVENT_ON) ? |
176 | ACPI_STATE_D0 : ACPI_STATE_D3; | ||
177 | |||
178 | /* | ||
179 | * acpi_bus_set_power() often fails (keyboard port can't be | ||
180 | * powered-down?), and in any case, our return value is ignored | ||
181 | * by pnp_bus_suspend(). Hence we don't revert the wakeup | ||
182 | * setting if the set_power fails. | ||
183 | */ | ||
184 | error = acpi_bus_set_power(handle, power_state); | ||
145 | } | 185 | } |
146 | power_state = acpi_pm_device_sleep_state(&dev->dev, NULL); | 186 | |
147 | if (power_state < 0) | 187 | return error; |
148 | power_state = (state.event == PM_EVENT_ON) ? | ||
149 | ACPI_STATE_D0 : ACPI_STATE_D3; | ||
150 | |||
151 | /* acpi_bus_set_power() often fails (keyboard port can't be | ||
152 | * powered-down?), and in any case, our return value is ignored | ||
153 | * by pnp_bus_suspend(). Hence we don't revert the wakeup | ||
154 | * setting if the set_power fails. | ||
155 | */ | ||
156 | return acpi_bus_set_power(handle, power_state); | ||
157 | } | 188 | } |
158 | 189 | ||
159 | static int pnpacpi_resume(struct pnp_dev *dev) | 190 | static int pnpacpi_resume(struct pnp_dev *dev) |
160 | { | 191 | { |
161 | struct acpi_device *acpi_dev = dev->data; | 192 | struct acpi_device *acpi_dev; |
162 | acpi_handle handle = acpi_dev->handle; | 193 | acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); |
194 | int error = 0; | ||
195 | |||
196 | if (!handle || ACPI_FAILURE(acpi_bus_get_device(handle, &acpi_dev))) { | ||
197 | dev_dbg(&dev->dev, "ACPI device not found in %s!\n", __func__); | ||
198 | return -ENODEV; | ||
199 | } | ||
163 | 200 | ||
164 | if (device_may_wakeup(&dev->dev)) | 201 | if (device_may_wakeup(&dev->dev)) |
165 | acpi_pm_device_sleep_wake(&dev->dev, false); | 202 | acpi_pm_device_sleep_wake(&dev->dev, false); |
166 | return acpi_bus_set_power(handle, ACPI_STATE_D0); | 203 | |
204 | if (acpi_bus_power_manageable(handle)) | ||
205 | error = acpi_bus_set_power(handle, ACPI_STATE_D0); | ||
206 | |||
207 | return error; | ||
167 | } | 208 | } |
168 | #endif | 209 | #endif |
169 | 210 | ||
@@ -180,11 +221,24 @@ struct pnp_protocol pnpacpi_protocol = { | |||
180 | }; | 221 | }; |
181 | EXPORT_SYMBOL(pnpacpi_protocol); | 222 | EXPORT_SYMBOL(pnpacpi_protocol); |
182 | 223 | ||
224 | static char *__init pnpacpi_get_id(struct acpi_device *device) | ||
225 | { | ||
226 | struct acpi_hardware_id *id; | ||
227 | |||
228 | list_for_each_entry(id, &device->pnp.ids, list) { | ||
229 | if (ispnpidacpi(id->id)) | ||
230 | return id->id; | ||
231 | } | ||
232 | |||
233 | return NULL; | ||
234 | } | ||
235 | |||
183 | static int __init pnpacpi_add_device(struct acpi_device *device) | 236 | static int __init pnpacpi_add_device(struct acpi_device *device) |
184 | { | 237 | { |
185 | acpi_handle temp = NULL; | 238 | acpi_handle temp = NULL; |
186 | acpi_status status; | 239 | acpi_status status; |
187 | struct pnp_dev *dev; | 240 | struct pnp_dev *dev; |
241 | char *pnpid; | ||
188 | struct acpi_hardware_id *id; | 242 | struct acpi_hardware_id *id; |
189 | 243 | ||
190 | /* | 244 | /* |
@@ -192,11 +246,17 @@ static int __init pnpacpi_add_device(struct acpi_device *device) | |||
192 | * driver should not be loaded. | 246 | * driver should not be loaded. |
193 | */ | 247 | */ |
194 | status = acpi_get_handle(device->handle, "_CRS", &temp); | 248 | status = acpi_get_handle(device->handle, "_CRS", &temp); |
195 | if (ACPI_FAILURE(status) || !ispnpidacpi(acpi_device_hid(device)) || | 249 | if (ACPI_FAILURE(status)) |
196 | is_exclusive_device(device) || (!device->status.present)) | 250 | return 0; |
251 | |||
252 | pnpid = pnpacpi_get_id(device); | ||
253 | if (!pnpid) | ||
254 | return 0; | ||
255 | |||
256 | if (is_exclusive_device(device) || !device->status.present) | ||
197 | return 0; | 257 | return 0; |
198 | 258 | ||
199 | dev = pnp_alloc_dev(&pnpacpi_protocol, num, acpi_device_hid(device)); | 259 | dev = pnp_alloc_dev(&pnpacpi_protocol, num, pnpid); |
200 | if (!dev) | 260 | if (!dev) |
201 | return -ENOMEM; | 261 | return -ENOMEM; |
202 | 262 | ||
@@ -227,7 +287,7 @@ static int __init pnpacpi_add_device(struct acpi_device *device) | |||
227 | pnpacpi_parse_resource_option_data(dev); | 287 | pnpacpi_parse_resource_option_data(dev); |
228 | 288 | ||
229 | list_for_each_entry(id, &device->pnp.ids, list) { | 289 | list_for_each_entry(id, &device->pnp.ids, list) { |
230 | if (!strcmp(id->id, acpi_device_hid(device))) | 290 | if (!strcmp(id->id, pnpid)) |
231 | continue; | 291 | continue; |
232 | if (!ispnpidacpi(id->id)) | 292 | if (!ispnpidacpi(id->id)) |
233 | continue; | 293 | continue; |