diff options
-rw-r--r-- | drivers/acpi/bus.c | 153 | ||||
-rw-r--r-- | drivers/acpi/fan.c | 27 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 5 | ||||
-rw-r--r-- | drivers/acpi/power.c | 90 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 27 | ||||
-rw-r--r-- | drivers/acpi/thermal.c | 5 | ||||
-rw-r--r-- | drivers/platform/x86/fujitsu-laptop.c | 4 | ||||
-rw-r--r-- | include/acpi/acpi_bus.h | 5 |
8 files changed, 171 insertions, 145 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index d68bd61072bb..7ced61f39492 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -52,22 +52,6 @@ EXPORT_SYMBOL(acpi_root_dir); | |||
52 | 52 | ||
53 | #define STRUCT_TO_INT(s) (*((int*)&s)) | 53 | #define STRUCT_TO_INT(s) (*((int*)&s)) |
54 | 54 | ||
55 | static int set_power_nocheck(const struct dmi_system_id *id) | ||
56 | { | ||
57 | printk(KERN_NOTICE PREFIX "%s detected - " | ||
58 | "disable power check in power transition\n", id->ident); | ||
59 | acpi_power_nocheck = 1; | ||
60 | return 0; | ||
61 | } | ||
62 | static struct dmi_system_id __cpuinitdata power_nocheck_dmi_table[] = { | ||
63 | { | ||
64 | set_power_nocheck, "HP Pavilion 05", { | ||
65 | DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies LTD"), | ||
66 | DMI_MATCH(DMI_SYS_VENDOR, "HP Pavilion 05"), | ||
67 | DMI_MATCH(DMI_PRODUCT_VERSION, "2001211RE101GLEND") }, NULL}, | ||
68 | {}, | ||
69 | }; | ||
70 | |||
71 | 55 | ||
72 | #ifdef CONFIG_X86 | 56 | #ifdef CONFIG_X86 |
73 | static int set_copy_dsdt(const struct dmi_system_id *id) | 57 | static int set_copy_dsdt(const struct dmi_system_id *id) |
@@ -196,33 +180,24 @@ EXPORT_SYMBOL(acpi_bus_get_private_data); | |||
196 | Power Management | 180 | Power Management |
197 | -------------------------------------------------------------------------- */ | 181 | -------------------------------------------------------------------------- */ |
198 | 182 | ||
199 | int acpi_bus_get_power(acpi_handle handle, int *state) | 183 | static int __acpi_bus_get_power(struct acpi_device *device, int *state) |
200 | { | 184 | { |
201 | int result = 0; | 185 | int result = 0; |
202 | acpi_status status = 0; | 186 | acpi_status status = 0; |
203 | struct acpi_device *device = NULL; | ||
204 | unsigned long long psc = 0; | 187 | unsigned long long psc = 0; |
205 | 188 | ||
206 | 189 | if (!device || !state) | |
207 | result = acpi_bus_get_device(handle, &device); | 190 | return -EINVAL; |
208 | if (result) | ||
209 | return result; | ||
210 | 191 | ||
211 | *state = ACPI_STATE_UNKNOWN; | 192 | *state = ACPI_STATE_UNKNOWN; |
212 | 193 | ||
213 | if (!device->flags.power_manageable) { | 194 | if (device->flags.power_manageable) { |
214 | /* TBD: Non-recursive algorithm for walking up hierarchy */ | ||
215 | if (device->parent) | ||
216 | *state = device->parent->power.state; | ||
217 | else | ||
218 | *state = ACPI_STATE_D0; | ||
219 | } else { | ||
220 | /* | 195 | /* |
221 | * Get the device's power state either directly (via _PSC) or | 196 | * Get the device's power state either directly (via _PSC) or |
222 | * indirectly (via power resources). | 197 | * indirectly (via power resources). |
223 | */ | 198 | */ |
224 | if (device->power.flags.power_resources) { | 199 | if (device->power.flags.power_resources) { |
225 | result = acpi_power_get_inferred_state(device); | 200 | result = acpi_power_get_inferred_state(device, state); |
226 | if (result) | 201 | if (result) |
227 | return result; | 202 | return result; |
228 | } else if (device->power.flags.explicit_get) { | 203 | } else if (device->power.flags.explicit_get) { |
@@ -230,59 +205,33 @@ int acpi_bus_get_power(acpi_handle handle, int *state) | |||
230 | NULL, &psc); | 205 | NULL, &psc); |
231 | if (ACPI_FAILURE(status)) | 206 | if (ACPI_FAILURE(status)) |
232 | return -ENODEV; | 207 | return -ENODEV; |
233 | device->power.state = (int)psc; | 208 | *state = (int)psc; |
234 | } | 209 | } |
235 | 210 | } else { | |
236 | *state = device->power.state; | 211 | /* TBD: Non-recursive algorithm for walking up hierarchy. */ |
212 | *state = device->parent ? | ||
213 | device->parent->power.state : ACPI_STATE_D0; | ||
237 | } | 214 | } |
238 | 215 | ||
239 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n", | 216 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is D%d\n", |
240 | device->pnp.bus_id, device->power.state)); | 217 | device->pnp.bus_id, *state)); |
241 | 218 | ||
242 | return 0; | 219 | return 0; |
243 | } | 220 | } |
244 | 221 | ||
245 | EXPORT_SYMBOL(acpi_bus_get_power); | ||
246 | 222 | ||
247 | int acpi_bus_set_power(acpi_handle handle, int state) | 223 | static int __acpi_bus_set_power(struct acpi_device *device, int state) |
248 | { | 224 | { |
249 | int result = 0; | 225 | int result = 0; |
250 | acpi_status status = AE_OK; | 226 | acpi_status status = AE_OK; |
251 | struct acpi_device *device = NULL; | ||
252 | char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; | 227 | char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; |
253 | 228 | ||
254 | 229 | if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) | |
255 | result = acpi_bus_get_device(handle, &device); | ||
256 | if (result) | ||
257 | return result; | ||
258 | |||
259 | if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) | ||
260 | return -EINVAL; | 230 | return -EINVAL; |
261 | 231 | ||
262 | /* Make sure this is a valid target state */ | 232 | /* Make sure this is a valid target state */ |
263 | 233 | ||
264 | if (!device->flags.power_manageable) { | 234 | if (state == device->power.state) { |
265 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", | ||
266 | kobject_name(&device->dev.kobj))); | ||
267 | return -ENODEV; | ||
268 | } | ||
269 | /* | ||
270 | * Get device's current power state | ||
271 | */ | ||
272 | if (!acpi_power_nocheck) { | ||
273 | /* | ||
274 | * Maybe the incorrect power state is returned on the bogus | ||
275 | * bios, which is different with the real power state. | ||
276 | * For example: the bios returns D0 state and the real power | ||
277 | * state is D3. OS expects to set the device to D0 state. In | ||
278 | * such case if OS uses the power state returned by the BIOS, | ||
279 | * the device can't be transisted to the correct power state. | ||
280 | * So if the acpi_power_nocheck is set, it is unnecessary to | ||
281 | * get the power state by calling acpi_bus_get_power. | ||
282 | */ | ||
283 | acpi_bus_get_power(device->handle, &device->power.state); | ||
284 | } | ||
285 | if ((state == device->power.state) && !device->flags.force_power_state) { | ||
286 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", | 235 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", |
287 | state)); | 236 | state)); |
288 | return 0; | 237 | return 0; |
@@ -351,8 +300,75 @@ int acpi_bus_set_power(acpi_handle handle, int state) | |||
351 | return result; | 300 | return result; |
352 | } | 301 | } |
353 | 302 | ||
303 | |||
304 | int acpi_bus_set_power(acpi_handle handle, int state) | ||
305 | { | ||
306 | struct acpi_device *device; | ||
307 | int result; | ||
308 | |||
309 | result = acpi_bus_get_device(handle, &device); | ||
310 | if (result) | ||
311 | return result; | ||
312 | |||
313 | if (!device->flags.power_manageable) { | ||
314 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
315 | "Device [%s] is not power manageable\n", | ||
316 | dev_name(&device->dev))); | ||
317 | return -ENODEV; | ||
318 | } | ||
319 | |||
320 | return __acpi_bus_set_power(device, state); | ||
321 | } | ||
354 | EXPORT_SYMBOL(acpi_bus_set_power); | 322 | EXPORT_SYMBOL(acpi_bus_set_power); |
355 | 323 | ||
324 | |||
325 | int acpi_bus_init_power(struct acpi_device *device) | ||
326 | { | ||
327 | int state; | ||
328 | int result; | ||
329 | |||
330 | if (!device) | ||
331 | return -EINVAL; | ||
332 | |||
333 | device->power.state = ACPI_STATE_UNKNOWN; | ||
334 | |||
335 | result = __acpi_bus_get_power(device, &state); | ||
336 | if (result) | ||
337 | return result; | ||
338 | |||
339 | if (device->power.flags.power_resources) | ||
340 | result = acpi_power_on_resources(device, state); | ||
341 | |||
342 | if (!result) | ||
343 | device->power.state = state; | ||
344 | |||
345 | return result; | ||
346 | } | ||
347 | |||
348 | |||
349 | int acpi_bus_update_power(acpi_handle handle, int *state_p) | ||
350 | { | ||
351 | struct acpi_device *device; | ||
352 | int state; | ||
353 | int result; | ||
354 | |||
355 | result = acpi_bus_get_device(handle, &device); | ||
356 | if (result) | ||
357 | return result; | ||
358 | |||
359 | result = __acpi_bus_get_power(device, &state); | ||
360 | if (result) | ||
361 | return result; | ||
362 | |||
363 | result = __acpi_bus_set_power(device, state); | ||
364 | if (!result && state_p) | ||
365 | *state_p = state; | ||
366 | |||
367 | return result; | ||
368 | } | ||
369 | EXPORT_SYMBOL_GPL(acpi_bus_update_power); | ||
370 | |||
371 | |||
356 | bool acpi_bus_power_manageable(acpi_handle handle) | 372 | bool acpi_bus_power_manageable(acpi_handle handle) |
357 | { | 373 | { |
358 | struct acpi_device *device; | 374 | struct acpi_device *device; |
@@ -1023,15 +1039,8 @@ static int __init acpi_init(void) | |||
1023 | if (acpi_disabled) | 1039 | if (acpi_disabled) |
1024 | return result; | 1040 | return result; |
1025 | 1041 | ||
1026 | /* | ||
1027 | * If the laptop falls into the DMI check table, the power state check | ||
1028 | * will be disabled in the course of device power transition. | ||
1029 | */ | ||
1030 | dmi_check_system(power_nocheck_dmi_table); | ||
1031 | |||
1032 | acpi_scan_init(); | 1042 | acpi_scan_init(); |
1033 | acpi_ec_init(); | 1043 | acpi_ec_init(); |
1034 | acpi_power_init(); | ||
1035 | acpi_debugfs_init(); | 1044 | acpi_debugfs_init(); |
1036 | acpi_sleep_proc_init(); | 1045 | acpi_sleep_proc_init(); |
1037 | acpi_wakeup_device_init(); | 1046 | acpi_wakeup_device_init(); |
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c index 60049080c869..467479f07c1f 100644 --- a/drivers/acpi/fan.c +++ b/drivers/acpi/fan.c | |||
@@ -86,7 +86,7 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long | |||
86 | if (!device) | 86 | if (!device) |
87 | return -EINVAL; | 87 | return -EINVAL; |
88 | 88 | ||
89 | result = acpi_bus_get_power(device->handle, &acpi_state); | 89 | result = acpi_bus_update_power(device->handle, &acpi_state); |
90 | if (result) | 90 | if (result) |
91 | return result; | 91 | return result; |
92 | 92 | ||
@@ -123,7 +123,6 @@ static struct thermal_cooling_device_ops fan_cooling_ops = { | |||
123 | static int acpi_fan_add(struct acpi_device *device) | 123 | static int acpi_fan_add(struct acpi_device *device) |
124 | { | 124 | { |
125 | int result = 0; | 125 | int result = 0; |
126 | int state = 0; | ||
127 | struct thermal_cooling_device *cdev; | 126 | struct thermal_cooling_device *cdev; |
128 | 127 | ||
129 | if (!device) | 128 | if (!device) |
@@ -132,16 +131,12 @@ static int acpi_fan_add(struct acpi_device *device) | |||
132 | strcpy(acpi_device_name(device), "Fan"); | 131 | strcpy(acpi_device_name(device), "Fan"); |
133 | strcpy(acpi_device_class(device), ACPI_FAN_CLASS); | 132 | strcpy(acpi_device_class(device), ACPI_FAN_CLASS); |
134 | 133 | ||
135 | result = acpi_bus_get_power(device->handle, &state); | 134 | result = acpi_bus_update_power(device->handle, NULL); |
136 | if (result) { | 135 | if (result) { |
137 | printk(KERN_ERR PREFIX "Reading power state\n"); | 136 | printk(KERN_ERR PREFIX "Setting initial power state\n"); |
138 | goto end; | 137 | goto end; |
139 | } | 138 | } |
140 | 139 | ||
141 | device->flags.force_power_state = 1; | ||
142 | acpi_bus_set_power(device->handle, state); | ||
143 | device->flags.force_power_state = 0; | ||
144 | |||
145 | cdev = thermal_cooling_device_register("Fan", device, | 140 | cdev = thermal_cooling_device_register("Fan", device, |
146 | &fan_cooling_ops); | 141 | &fan_cooling_ops); |
147 | if (IS_ERR(cdev)) { | 142 | if (IS_ERR(cdev)) { |
@@ -200,22 +195,14 @@ static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state) | |||
200 | 195 | ||
201 | static int acpi_fan_resume(struct acpi_device *device) | 196 | static int acpi_fan_resume(struct acpi_device *device) |
202 | { | 197 | { |
203 | int result = 0; | 198 | int result; |
204 | int power_state = 0; | ||
205 | 199 | ||
206 | if (!device) | 200 | if (!device) |
207 | return -EINVAL; | 201 | return -EINVAL; |
208 | 202 | ||
209 | result = acpi_bus_get_power(device->handle, &power_state); | 203 | result = acpi_bus_update_power(device->handle, NULL); |
210 | if (result) { | 204 | if (result) |
211 | printk(KERN_ERR PREFIX | 205 | printk(KERN_ERR PREFIX "Error updating fan power state\n"); |
212 | "Error reading fan power state\n"); | ||
213 | return result; | ||
214 | } | ||
215 | |||
216 | device->flags.force_power_state = 1; | ||
217 | acpi_bus_set_power(device->handle, power_state); | ||
218 | device->flags.force_power_state = 0; | ||
219 | 206 | ||
220 | return result; | 207 | return result; |
221 | } | 208 | } |
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index a212bfeddf8c..8df5d7061a45 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h | |||
@@ -41,9 +41,10 @@ static inline int acpi_debugfs_init(void) { return 0; } | |||
41 | int acpi_power_init(void); | 41 | int acpi_power_init(void); |
42 | int acpi_device_sleep_wake(struct acpi_device *dev, | 42 | int acpi_device_sleep_wake(struct acpi_device *dev, |
43 | int enable, int sleep_state, int dev_state); | 43 | int enable, int sleep_state, int dev_state); |
44 | int acpi_power_get_inferred_state(struct acpi_device *device); | 44 | int acpi_power_get_inferred_state(struct acpi_device *device, int *state); |
45 | int acpi_power_on_resources(struct acpi_device *device, int state); | ||
45 | int acpi_power_transition(struct acpi_device *device, int state); | 46 | int acpi_power_transition(struct acpi_device *device, int state); |
46 | extern int acpi_power_nocheck; | 47 | int acpi_bus_init_power(struct acpi_device *device); |
47 | 48 | ||
48 | int acpi_wakeup_device_init(void); | 49 | int acpi_wakeup_device_init(void); |
49 | void acpi_early_processor_set_pdc(void); | 50 | void acpi_early_processor_set_pdc(void); |
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 4c9c2fb5d98f..0003f1009885 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c | |||
@@ -56,9 +56,6 @@ ACPI_MODULE_NAME("power"); | |||
56 | #define ACPI_POWER_RESOURCE_STATE_ON 0x01 | 56 | #define ACPI_POWER_RESOURCE_STATE_ON 0x01 |
57 | #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF | 57 | #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF |
58 | 58 | ||
59 | int acpi_power_nocheck; | ||
60 | module_param_named(power_nocheck, acpi_power_nocheck, bool, 000); | ||
61 | |||
62 | static int acpi_power_add(struct acpi_device *device); | 59 | static int acpi_power_add(struct acpi_device *device); |
63 | static int acpi_power_remove(struct acpi_device *device, int type); | 60 | static int acpi_power_remove(struct acpi_device *device, int type); |
64 | static int acpi_power_resume(struct acpi_device *device); | 61 | static int acpi_power_resume(struct acpi_device *device); |
@@ -266,6 +263,35 @@ static int acpi_power_off_device(acpi_handle handle) | |||
266 | return result; | 263 | return result; |
267 | } | 264 | } |
268 | 265 | ||
266 | static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res) | ||
267 | { | ||
268 | int i; | ||
269 | |||
270 | for (i = num_res - 1; i >= 0 ; i--) | ||
271 | acpi_power_off_device(list->handles[i]); | ||
272 | } | ||
273 | |||
274 | static void acpi_power_off_list(struct acpi_handle_list *list) | ||
275 | { | ||
276 | __acpi_power_off_list(list, list->count); | ||
277 | } | ||
278 | |||
279 | static int acpi_power_on_list(struct acpi_handle_list *list) | ||
280 | { | ||
281 | int result = 0; | ||
282 | int i; | ||
283 | |||
284 | for (i = 0; i < list->count; i++) { | ||
285 | result = acpi_power_on(list->handles[i]); | ||
286 | if (result) { | ||
287 | __acpi_power_off_list(list, i); | ||
288 | break; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | return result; | ||
293 | } | ||
294 | |||
269 | /** | 295 | /** |
270 | * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in | 296 | * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in |
271 | * ACPI 3.0) _PSW (Power State Wake) | 297 | * ACPI 3.0) _PSW (Power State Wake) |
@@ -423,19 +449,16 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) | |||
423 | Device Power Management | 449 | Device Power Management |
424 | -------------------------------------------------------------------------- */ | 450 | -------------------------------------------------------------------------- */ |
425 | 451 | ||
426 | int acpi_power_get_inferred_state(struct acpi_device *device) | 452 | int acpi_power_get_inferred_state(struct acpi_device *device, int *state) |
427 | { | 453 | { |
428 | int result = 0; | 454 | int result = 0; |
429 | struct acpi_handle_list *list = NULL; | 455 | struct acpi_handle_list *list = NULL; |
430 | int list_state = 0; | 456 | int list_state = 0; |
431 | int i = 0; | 457 | int i = 0; |
432 | 458 | ||
433 | 459 | if (!device || !state) | |
434 | if (!device) | ||
435 | return -EINVAL; | 460 | return -EINVAL; |
436 | 461 | ||
437 | device->power.state = ACPI_STATE_UNKNOWN; | ||
438 | |||
439 | /* | 462 | /* |
440 | * We know a device's inferred power state when all the resources | 463 | * We know a device's inferred power state when all the resources |
441 | * required for a given D-state are 'on'. | 464 | * required for a given D-state are 'on'. |
@@ -450,22 +473,26 @@ int acpi_power_get_inferred_state(struct acpi_device *device) | |||
450 | return result; | 473 | return result; |
451 | 474 | ||
452 | if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { | 475 | if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { |
453 | device->power.state = i; | 476 | *state = i; |
454 | return 0; | 477 | return 0; |
455 | } | 478 | } |
456 | } | 479 | } |
457 | 480 | ||
458 | device->power.state = ACPI_STATE_D3; | 481 | *state = ACPI_STATE_D3; |
459 | |||
460 | return 0; | 482 | return 0; |
461 | } | 483 | } |
462 | 484 | ||
485 | int acpi_power_on_resources(struct acpi_device *device, int state) | ||
486 | { | ||
487 | if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3) | ||
488 | return -EINVAL; | ||
489 | |||
490 | return acpi_power_on_list(&device->power.states[state].resources); | ||
491 | } | ||
492 | |||
463 | int acpi_power_transition(struct acpi_device *device, int state) | 493 | int acpi_power_transition(struct acpi_device *device, int state) |
464 | { | 494 | { |
465 | int result = 0; | 495 | int result; |
466 | struct acpi_handle_list *cl = NULL; /* Current Resources */ | ||
467 | struct acpi_handle_list *tl = NULL; /* Target Resources */ | ||
468 | int i = 0; | ||
469 | 496 | ||
470 | if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) | 497 | if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) |
471 | return -EINVAL; | 498 | return -EINVAL; |
@@ -477,37 +504,20 @@ int acpi_power_transition(struct acpi_device *device, int state) | |||
477 | || (device->power.state > ACPI_STATE_D3)) | 504 | || (device->power.state > ACPI_STATE_D3)) |
478 | return -ENODEV; | 505 | return -ENODEV; |
479 | 506 | ||
480 | cl = &device->power.states[device->power.state].resources; | ||
481 | tl = &device->power.states[state].resources; | ||
482 | |||
483 | /* TBD: Resources must be ordered. */ | 507 | /* TBD: Resources must be ordered. */ |
484 | 508 | ||
485 | /* | 509 | /* |
486 | * First we reference all power resources required in the target list | 510 | * First we reference all power resources required in the target list |
487 | * (e.g. so the device doesn't lose power while transitioning). | 511 | * (e.g. so the device doesn't lose power while transitioning). Then, |
512 | * we dereference all power resources used in the current list. | ||
488 | */ | 513 | */ |
489 | for (i = 0; i < tl->count; i++) { | 514 | result = acpi_power_on_list(&device->power.states[state].resources); |
490 | result = acpi_power_on(tl->handles[i]); | 515 | if (!result) |
491 | if (result) | 516 | acpi_power_off_list( |
492 | goto end; | 517 | &device->power.states[device->power.state].resources); |
493 | } | ||
494 | |||
495 | /* | ||
496 | * Then we dereference all power resources used in the current list. | ||
497 | */ | ||
498 | for (i = 0; i < cl->count; i++) { | ||
499 | result = acpi_power_off_device(cl->handles[i]); | ||
500 | if (result) | ||
501 | goto end; | ||
502 | } | ||
503 | 518 | ||
504 | end: | 519 | /* We shouldn't change the state unless the above operations succeed. */ |
505 | if (result) | 520 | device->power.state = result ? ACPI_STATE_UNKNOWN : state; |
506 | device->power.state = ACPI_STATE_UNKNOWN; | ||
507 | else { | ||
508 | /* We shouldn't change the state till all above operations succeed */ | ||
509 | device->power.state = state; | ||
510 | } | ||
511 | 521 | ||
512 | return result; | 522 | return result; |
513 | } | 523 | } |
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ce6741ee1965..148e7492d736 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -847,6 +847,8 @@ end: | |||
847 | return 0; | 847 | return 0; |
848 | } | 848 | } |
849 | 849 | ||
850 | static void acpi_bus_add_power_resource(acpi_handle handle); | ||
851 | |||
850 | static int acpi_bus_get_power_flags(struct acpi_device *device) | 852 | static int acpi_bus_get_power_flags(struct acpi_device *device) |
851 | { | 853 | { |
852 | acpi_status status = 0; | 854 | acpi_status status = 0; |
@@ -875,8 +877,12 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) | |||
875 | acpi_evaluate_reference(device->handle, object_name, NULL, | 877 | acpi_evaluate_reference(device->handle, object_name, NULL, |
876 | &ps->resources); | 878 | &ps->resources); |
877 | if (ps->resources.count) { | 879 | if (ps->resources.count) { |
880 | int j; | ||
881 | |||
878 | device->power.flags.power_resources = 1; | 882 | device->power.flags.power_resources = 1; |
879 | ps->flags.valid = 1; | 883 | ps->flags.valid = 1; |
884 | for (j = 0; j < ps->resources.count; j++) | ||
885 | acpi_bus_add_power_resource(ps->resources.handles[j]); | ||
880 | } | 886 | } |
881 | 887 | ||
882 | /* Evaluate "_PSx" to see if we can do explicit sets */ | 888 | /* Evaluate "_PSx" to see if we can do explicit sets */ |
@@ -901,10 +907,7 @@ static int acpi_bus_get_power_flags(struct acpi_device *device) | |||
901 | device->power.states[ACPI_STATE_D3].flags.valid = 1; | 907 | device->power.states[ACPI_STATE_D3].flags.valid = 1; |
902 | device->power.states[ACPI_STATE_D3].power = 0; | 908 | device->power.states[ACPI_STATE_D3].power = 0; |
903 | 909 | ||
904 | /* TBD: System wake support and resource requirements. */ | 910 | acpi_bus_init_power(device); |
905 | |||
906 | device->power.state = ACPI_STATE_UNKNOWN; | ||
907 | acpi_bus_get_power(device->handle, &(device->power.state)); | ||
908 | 911 | ||
909 | return 0; | 912 | return 0; |
910 | } | 913 | } |
@@ -1326,6 +1329,20 @@ end: | |||
1326 | #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ | 1329 | #define ACPI_STA_DEFAULT (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_ENABLED | \ |
1327 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) | 1330 | ACPI_STA_DEVICE_UI | ACPI_STA_DEVICE_FUNCTIONING) |
1328 | 1331 | ||
1332 | static void acpi_bus_add_power_resource(acpi_handle handle) | ||
1333 | { | ||
1334 | struct acpi_bus_ops ops = { | ||
1335 | .acpi_op_add = 1, | ||
1336 | .acpi_op_start = 1, | ||
1337 | }; | ||
1338 | struct acpi_device *device = NULL; | ||
1339 | |||
1340 | acpi_bus_get_device(handle, &device); | ||
1341 | if (!device) | ||
1342 | acpi_add_single_object(&device, handle, ACPI_BUS_TYPE_POWER, | ||
1343 | ACPI_STA_DEFAULT, &ops); | ||
1344 | } | ||
1345 | |||
1329 | static int acpi_bus_type_and_status(acpi_handle handle, int *type, | 1346 | static int acpi_bus_type_and_status(acpi_handle handle, int *type, |
1330 | unsigned long long *sta) | 1347 | unsigned long long *sta) |
1331 | { | 1348 | { |
@@ -1573,6 +1590,8 @@ int __init acpi_scan_init(void) | |||
1573 | printk(KERN_ERR PREFIX "Could not register bus type\n"); | 1590 | printk(KERN_ERR PREFIX "Could not register bus type\n"); |
1574 | } | 1591 | } |
1575 | 1592 | ||
1593 | acpi_power_init(); | ||
1594 | |||
1576 | /* | 1595 | /* |
1577 | * Enumerate devices in the ACPI namespace. | 1596 | * Enumerate devices in the ACPI namespace. |
1578 | */ | 1597 | */ |
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c index 5a27b0a31315..2607e17b520f 100644 --- a/drivers/acpi/thermal.c +++ b/drivers/acpi/thermal.c | |||
@@ -1059,8 +1059,9 @@ static int acpi_thermal_resume(struct acpi_device *device) | |||
1059 | break; | 1059 | break; |
1060 | tz->trips.active[i].flags.enabled = 1; | 1060 | tz->trips.active[i].flags.enabled = 1; |
1061 | for (j = 0; j < tz->trips.active[i].devices.count; j++) { | 1061 | for (j = 0; j < tz->trips.active[i].devices.count; j++) { |
1062 | result = acpi_bus_get_power(tz->trips.active[i].devices. | 1062 | result = acpi_bus_update_power( |
1063 | handles[j], &power_state); | 1063 | tz->trips.active[i].devices.handles[j], |
1064 | &power_state); | ||
1064 | if (result || (power_state != ACPI_STATE_D0)) { | 1065 | if (result || (power_state != ACPI_STATE_D0)) { |
1065 | tz->trips.active[i].flags.enabled = 0; | 1066 | tz->trips.active[i].flags.enabled = 0; |
1066 | break; | 1067 | break; |
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c index f44cd2620ff9..cf6c47250c56 100644 --- a/drivers/platform/x86/fujitsu-laptop.c +++ b/drivers/platform/x86/fujitsu-laptop.c | |||
@@ -689,7 +689,7 @@ static int acpi_fujitsu_add(struct acpi_device *device) | |||
689 | if (error) | 689 | if (error) |
690 | goto err_free_input_dev; | 690 | goto err_free_input_dev; |
691 | 691 | ||
692 | result = acpi_bus_get_power(fujitsu->acpi_handle, &state); | 692 | result = acpi_bus_update_power(fujitsu->acpi_handle, &state); |
693 | if (result) { | 693 | if (result) { |
694 | printk(KERN_ERR "Error reading power state\n"); | 694 | printk(KERN_ERR "Error reading power state\n"); |
695 | goto err_unregister_input_dev; | 695 | goto err_unregister_input_dev; |
@@ -857,7 +857,7 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device) | |||
857 | if (error) | 857 | if (error) |
858 | goto err_free_input_dev; | 858 | goto err_free_input_dev; |
859 | 859 | ||
860 | result = acpi_bus_get_power(fujitsu_hotkey->acpi_handle, &state); | 860 | result = acpi_bus_update_power(fujitsu_hotkey->acpi_handle, &state); |
861 | if (result) { | 861 | if (result) { |
862 | printk(KERN_ERR "Error reading power state\n"); | 862 | printk(KERN_ERR "Error reading power state\n"); |
863 | goto err_unregister_input_dev; | 863 | goto err_unregister_input_dev; |
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 359ef11725a6..673a3f4d1f07 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h | |||
@@ -149,8 +149,7 @@ struct acpi_device_flags { | |||
149 | u32 power_manageable:1; | 149 | u32 power_manageable:1; |
150 | u32 performance_manageable:1; | 150 | u32 performance_manageable:1; |
151 | u32 wake_capable:1; /* Wakeup(_PRW) supported? */ | 151 | u32 wake_capable:1; /* Wakeup(_PRW) supported? */ |
152 | u32 force_power_state:1; | 152 | u32 reserved:23; |
153 | u32 reserved:22; | ||
154 | }; | 153 | }; |
155 | 154 | ||
156 | /* File System */ | 155 | /* File System */ |
@@ -328,8 +327,8 @@ void acpi_bus_data_handler(acpi_handle handle, void *context); | |||
328 | acpi_status acpi_bus_get_status_handle(acpi_handle handle, | 327 | acpi_status acpi_bus_get_status_handle(acpi_handle handle, |
329 | unsigned long long *sta); | 328 | unsigned long long *sta); |
330 | int acpi_bus_get_status(struct acpi_device *device); | 329 | int acpi_bus_get_status(struct acpi_device *device); |
331 | int acpi_bus_get_power(acpi_handle handle, int *state); | ||
332 | int acpi_bus_set_power(acpi_handle handle, int state); | 330 | int acpi_bus_set_power(acpi_handle handle, int state); |
331 | int acpi_bus_update_power(acpi_handle handle, int *state_p); | ||
333 | bool acpi_bus_power_manageable(acpi_handle handle); | 332 | bool acpi_bus_power_manageable(acpi_handle handle); |
334 | bool acpi_bus_can_wakeup(acpi_handle handle); | 333 | bool acpi_bus_can_wakeup(acpi_handle handle); |
335 | #ifdef CONFIG_ACPI_PROC_EVENT | 334 | #ifdef CONFIG_ACPI_PROC_EVENT |