diff options
Diffstat (limited to 'drivers/acpi/power.c')
-rw-r--r-- | drivers/acpi/power.c | 128 |
1 files changed, 72 insertions, 56 deletions
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 4c9c2fb5d98f..9ac2a9fa90ff 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); |
@@ -148,9 +145,8 @@ static int acpi_power_get_state(acpi_handle handle, int *state) | |||
148 | 145 | ||
149 | static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) | 146 | static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) |
150 | { | 147 | { |
151 | int result = 0, state1; | 148 | int cur_state; |
152 | u32 i = 0; | 149 | int i = 0; |
153 | |||
154 | 150 | ||
155 | if (!list || !state) | 151 | if (!list || !state) |
156 | return -EINVAL; | 152 | return -EINVAL; |
@@ -158,25 +154,33 @@ static int acpi_power_get_list_state(struct acpi_handle_list *list, int *state) | |||
158 | /* The state of the list is 'on' IFF all resources are 'on'. */ | 154 | /* The state of the list is 'on' IFF all resources are 'on'. */ |
159 | 155 | ||
160 | for (i = 0; i < list->count; i++) { | 156 | for (i = 0; i < list->count; i++) { |
161 | /* | 157 | struct acpi_power_resource *resource; |
162 | * The state of the power resource can be obtained by | 158 | acpi_handle handle = list->handles[i]; |
163 | * using the ACPI handle. In such case it is unnecessary to | 159 | int result; |
164 | * get the Power resource first and then get its state again. | 160 | |
165 | */ | 161 | result = acpi_power_get_context(handle, &resource); |
166 | result = acpi_power_get_state(list->handles[i], &state1); | ||
167 | if (result) | 162 | if (result) |
168 | return result; | 163 | return result; |
169 | 164 | ||
170 | *state = state1; | 165 | mutex_lock(&resource->resource_lock); |
171 | 166 | ||
172 | if (*state != ACPI_POWER_RESOURCE_STATE_ON) | 167 | result = acpi_power_get_state(handle, &cur_state); |
168 | |||
169 | mutex_unlock(&resource->resource_lock); | ||
170 | |||
171 | if (result) | ||
172 | return result; | ||
173 | |||
174 | if (cur_state != ACPI_POWER_RESOURCE_STATE_ON) | ||
173 | break; | 175 | break; |
174 | } | 176 | } |
175 | 177 | ||
176 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n", | 178 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Resource list is %s\n", |
177 | *state ? "on" : "off")); | 179 | cur_state ? "on" : "off")); |
178 | 180 | ||
179 | return result; | 181 | *state = cur_state; |
182 | |||
183 | return 0; | ||
180 | } | 184 | } |
181 | 185 | ||
182 | static int __acpi_power_on(struct acpi_power_resource *resource) | 186 | static int __acpi_power_on(struct acpi_power_resource *resource) |
@@ -222,7 +226,7 @@ static int acpi_power_on(acpi_handle handle) | |||
222 | return result; | 226 | return result; |
223 | } | 227 | } |
224 | 228 | ||
225 | static int acpi_power_off_device(acpi_handle handle) | 229 | static int acpi_power_off(acpi_handle handle) |
226 | { | 230 | { |
227 | int result = 0; | 231 | int result = 0; |
228 | acpi_status status = AE_OK; | 232 | acpi_status status = AE_OK; |
@@ -266,6 +270,35 @@ static int acpi_power_off_device(acpi_handle handle) | |||
266 | return result; | 270 | return result; |
267 | } | 271 | } |
268 | 272 | ||
273 | static void __acpi_power_off_list(struct acpi_handle_list *list, int num_res) | ||
274 | { | ||
275 | int i; | ||
276 | |||
277 | for (i = num_res - 1; i >= 0 ; i--) | ||
278 | acpi_power_off(list->handles[i]); | ||
279 | } | ||
280 | |||
281 | static void acpi_power_off_list(struct acpi_handle_list *list) | ||
282 | { | ||
283 | __acpi_power_off_list(list, list->count); | ||
284 | } | ||
285 | |||
286 | static int acpi_power_on_list(struct acpi_handle_list *list) | ||
287 | { | ||
288 | int result = 0; | ||
289 | int i; | ||
290 | |||
291 | for (i = 0; i < list->count; i++) { | ||
292 | result = acpi_power_on(list->handles[i]); | ||
293 | if (result) { | ||
294 | __acpi_power_off_list(list, i); | ||
295 | break; | ||
296 | } | ||
297 | } | ||
298 | |||
299 | return result; | ||
300 | } | ||
301 | |||
269 | /** | 302 | /** |
270 | * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in | 303 | * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in |
271 | * ACPI 3.0) _PSW (Power State Wake) | 304 | * ACPI 3.0) _PSW (Power State Wake) |
@@ -404,8 +437,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) | |||
404 | 437 | ||
405 | /* Close power resource */ | 438 | /* Close power resource */ |
406 | for (i = 0; i < dev->wakeup.resources.count; i++) { | 439 | for (i = 0; i < dev->wakeup.resources.count; i++) { |
407 | int ret = acpi_power_off_device( | 440 | int ret = acpi_power_off(dev->wakeup.resources.handles[i]); |
408 | dev->wakeup.resources.handles[i]); | ||
409 | if (ret) { | 441 | if (ret) { |
410 | printk(KERN_ERR PREFIX "Transition power state\n"); | 442 | printk(KERN_ERR PREFIX "Transition power state\n"); |
411 | dev->wakeup.flags.valid = 0; | 443 | dev->wakeup.flags.valid = 0; |
@@ -423,19 +455,16 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) | |||
423 | Device Power Management | 455 | Device Power Management |
424 | -------------------------------------------------------------------------- */ | 456 | -------------------------------------------------------------------------- */ |
425 | 457 | ||
426 | int acpi_power_get_inferred_state(struct acpi_device *device) | 458 | int acpi_power_get_inferred_state(struct acpi_device *device, int *state) |
427 | { | 459 | { |
428 | int result = 0; | 460 | int result = 0; |
429 | struct acpi_handle_list *list = NULL; | 461 | struct acpi_handle_list *list = NULL; |
430 | int list_state = 0; | 462 | int list_state = 0; |
431 | int i = 0; | 463 | int i = 0; |
432 | 464 | ||
433 | 465 | if (!device || !state) | |
434 | if (!device) | ||
435 | return -EINVAL; | 466 | return -EINVAL; |
436 | 467 | ||
437 | device->power.state = ACPI_STATE_UNKNOWN; | ||
438 | |||
439 | /* | 468 | /* |
440 | * We know a device's inferred power state when all the resources | 469 | * We know a device's inferred power state when all the resources |
441 | * required for a given D-state are 'on'. | 470 | * required for a given D-state are 'on'. |
@@ -450,22 +479,26 @@ int acpi_power_get_inferred_state(struct acpi_device *device) | |||
450 | return result; | 479 | return result; |
451 | 480 | ||
452 | if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { | 481 | if (list_state == ACPI_POWER_RESOURCE_STATE_ON) { |
453 | device->power.state = i; | 482 | *state = i; |
454 | return 0; | 483 | return 0; |
455 | } | 484 | } |
456 | } | 485 | } |
457 | 486 | ||
458 | device->power.state = ACPI_STATE_D3; | 487 | *state = ACPI_STATE_D3; |
459 | |||
460 | return 0; | 488 | return 0; |
461 | } | 489 | } |
462 | 490 | ||
491 | int acpi_power_on_resources(struct acpi_device *device, int state) | ||
492 | { | ||
493 | if (!device || state < ACPI_STATE_D0 || state > ACPI_STATE_D3) | ||
494 | return -EINVAL; | ||
495 | |||
496 | return acpi_power_on_list(&device->power.states[state].resources); | ||
497 | } | ||
498 | |||
463 | int acpi_power_transition(struct acpi_device *device, int state) | 499 | int acpi_power_transition(struct acpi_device *device, int state) |
464 | { | 500 | { |
465 | int result = 0; | 501 | 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 | 502 | ||
470 | if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) | 503 | if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) |
471 | return -EINVAL; | 504 | return -EINVAL; |
@@ -477,37 +510,20 @@ int acpi_power_transition(struct acpi_device *device, int state) | |||
477 | || (device->power.state > ACPI_STATE_D3)) | 510 | || (device->power.state > ACPI_STATE_D3)) |
478 | return -ENODEV; | 511 | return -ENODEV; |
479 | 512 | ||
480 | cl = &device->power.states[device->power.state].resources; | ||
481 | tl = &device->power.states[state].resources; | ||
482 | |||
483 | /* TBD: Resources must be ordered. */ | 513 | /* TBD: Resources must be ordered. */ |
484 | 514 | ||
485 | /* | 515 | /* |
486 | * First we reference all power resources required in the target list | 516 | * First we reference all power resources required in the target list |
487 | * (e.g. so the device doesn't lose power while transitioning). | 517 | * (e.g. so the device doesn't lose power while transitioning). Then, |
518 | * we dereference all power resources used in the current list. | ||
488 | */ | 519 | */ |
489 | for (i = 0; i < tl->count; i++) { | 520 | result = acpi_power_on_list(&device->power.states[state].resources); |
490 | result = acpi_power_on(tl->handles[i]); | 521 | if (!result) |
491 | if (result) | 522 | acpi_power_off_list( |
492 | goto end; | 523 | &device->power.states[device->power.state].resources); |
493 | } | ||
494 | 524 | ||
495 | /* | 525 | /* We shouldn't change the state unless the above operations succeed. */ |
496 | * Then we dereference all power resources used in the current list. | 526 | device->power.state = result ? ACPI_STATE_UNKNOWN : state; |
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 | |||
504 | end: | ||
505 | if (result) | ||
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 | 527 | ||
512 | return result; | 528 | return result; |
513 | } | 529 | } |