diff options
Diffstat (limited to 'drivers/acpi/power.c')
-rw-r--r-- | drivers/acpi/power.c | 138 |
1 files changed, 102 insertions, 36 deletions
diff --git a/drivers/acpi/power.c b/drivers/acpi/power.c index 81e4f081a4ae..4ab21cb1c8c7 100644 --- a/drivers/acpi/power.c +++ b/drivers/acpi/power.c | |||
@@ -292,69 +292,135 @@ static int acpi_power_off_device(acpi_handle handle, struct acpi_device *dev) | |||
292 | return 0; | 292 | return 0; |
293 | } | 293 | } |
294 | 294 | ||
295 | /** | ||
296 | * acpi_device_sleep_wake - execute _DSW (Device Sleep Wake) or (deprecated in | ||
297 | * ACPI 3.0) _PSW (Power State Wake) | ||
298 | * @dev: Device to handle. | ||
299 | * @enable: 0 - disable, 1 - enable the wake capabilities of the device. | ||
300 | * @sleep_state: Target sleep state of the system. | ||
301 | * @dev_state: Target power state of the device. | ||
302 | * | ||
303 | * Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power | ||
304 | * State Wake) for the device, if present. On failure reset the device's | ||
305 | * wakeup.flags.valid flag. | ||
306 | * | ||
307 | * RETURN VALUE: | ||
308 | * 0 if either _DSW or _PSW has been successfully executed | ||
309 | * 0 if neither _DSW nor _PSW has been found | ||
310 | * -ENODEV if the execution of either _DSW or _PSW has failed | ||
311 | */ | ||
312 | int acpi_device_sleep_wake(struct acpi_device *dev, | ||
313 | int enable, int sleep_state, int dev_state) | ||
314 | { | ||
315 | union acpi_object in_arg[3]; | ||
316 | struct acpi_object_list arg_list = { 3, in_arg }; | ||
317 | acpi_status status = AE_OK; | ||
318 | |||
319 | /* | ||
320 | * Try to execute _DSW first. | ||
321 | * | ||
322 | * Three agruments are needed for the _DSW object: | ||
323 | * Argument 0: enable/disable the wake capabilities | ||
324 | * Argument 1: target system state | ||
325 | * Argument 2: target device state | ||
326 | * When _DSW object is called to disable the wake capabilities, maybe | ||
327 | * the first argument is filled. The values of the other two agruments | ||
328 | * are meaningless. | ||
329 | */ | ||
330 | in_arg[0].type = ACPI_TYPE_INTEGER; | ||
331 | in_arg[0].integer.value = enable; | ||
332 | in_arg[1].type = ACPI_TYPE_INTEGER; | ||
333 | in_arg[1].integer.value = sleep_state; | ||
334 | in_arg[2].type = ACPI_TYPE_INTEGER; | ||
335 | in_arg[2].integer.value = dev_state; | ||
336 | status = acpi_evaluate_object(dev->handle, "_DSW", &arg_list, NULL); | ||
337 | if (ACPI_SUCCESS(status)) { | ||
338 | return 0; | ||
339 | } else if (status != AE_NOT_FOUND) { | ||
340 | printk(KERN_ERR PREFIX "_DSW execution failed\n"); | ||
341 | dev->wakeup.flags.valid = 0; | ||
342 | return -ENODEV; | ||
343 | } | ||
344 | |||
345 | /* Execute _PSW */ | ||
346 | arg_list.count = 1; | ||
347 | in_arg[0].integer.value = enable; | ||
348 | status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); | ||
349 | if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { | ||
350 | printk(KERN_ERR PREFIX "_PSW execution failed\n"); | ||
351 | dev->wakeup.flags.valid = 0; | ||
352 | return -ENODEV; | ||
353 | } | ||
354 | |||
355 | return 0; | ||
356 | } | ||
357 | |||
295 | /* | 358 | /* |
296 | * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229): | 359 | * Prepare a wakeup device, two steps (Ref ACPI 2.0:P229): |
297 | * 1. Power on the power resources required for the wakeup device | 360 | * 1. Power on the power resources required for the wakeup device |
298 | * 2. Enable _PSW (power state wake) for the device if present | 361 | * 2. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power |
362 | * State Wake) for the device, if present | ||
299 | */ | 363 | */ |
300 | int acpi_enable_wakeup_device_power(struct acpi_device *dev) | 364 | int acpi_enable_wakeup_device_power(struct acpi_device *dev, int sleep_state) |
301 | { | 365 | { |
302 | union acpi_object arg = { ACPI_TYPE_INTEGER }; | 366 | int i, err; |
303 | struct acpi_object_list arg_list = { 1, &arg }; | ||
304 | acpi_status status = AE_OK; | ||
305 | int i; | ||
306 | int ret = 0; | ||
307 | 367 | ||
308 | if (!dev || !dev->wakeup.flags.valid) | 368 | if (!dev || !dev->wakeup.flags.valid) |
309 | return -1; | 369 | return -EINVAL; |
370 | |||
371 | /* | ||
372 | * Do not execute the code below twice in a row without calling | ||
373 | * acpi_disable_wakeup_device_power() in between for the same device | ||
374 | */ | ||
375 | if (dev->wakeup.flags.prepared) | ||
376 | return 0; | ||
310 | 377 | ||
311 | arg.integer.value = 1; | ||
312 | /* Open power resource */ | 378 | /* Open power resource */ |
313 | for (i = 0; i < dev->wakeup.resources.count; i++) { | 379 | for (i = 0; i < dev->wakeup.resources.count; i++) { |
314 | ret = acpi_power_on(dev->wakeup.resources.handles[i], dev); | 380 | int ret = acpi_power_on(dev->wakeup.resources.handles[i], dev); |
315 | if (ret) { | 381 | if (ret) { |
316 | printk(KERN_ERR PREFIX "Transition power state\n"); | 382 | printk(KERN_ERR PREFIX "Transition power state\n"); |
317 | dev->wakeup.flags.valid = 0; | 383 | dev->wakeup.flags.valid = 0; |
318 | return -1; | 384 | return -ENODEV; |
319 | } | 385 | } |
320 | } | 386 | } |
321 | 387 | ||
322 | /* Execute PSW */ | 388 | /* |
323 | status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); | 389 | * Passing 3 as the third argument below means the device may be placed |
324 | if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { | 390 | * in arbitrary power state afterwards. |
325 | printk(KERN_ERR PREFIX "Evaluate _PSW\n"); | 391 | */ |
326 | dev->wakeup.flags.valid = 0; | 392 | err = acpi_device_sleep_wake(dev, 1, sleep_state, 3); |
327 | ret = -1; | 393 | if (!err) |
328 | } | 394 | dev->wakeup.flags.prepared = 1; |
329 | 395 | ||
330 | return ret; | 396 | return err; |
331 | } | 397 | } |
332 | 398 | ||
333 | /* | 399 | /* |
334 | * Shutdown a wakeup device, counterpart of above method | 400 | * Shutdown a wakeup device, counterpart of above method |
335 | * 1. Disable _PSW (power state wake) | 401 | * 1. Execute _DSW (Device Sleep Wake) or (deprecated in ACPI 3.0) _PSW (Power |
402 | * State Wake) for the device, if present | ||
336 | * 2. Shutdown down the power resources | 403 | * 2. Shutdown down the power resources |
337 | */ | 404 | */ |
338 | int acpi_disable_wakeup_device_power(struct acpi_device *dev) | 405 | int acpi_disable_wakeup_device_power(struct acpi_device *dev) |
339 | { | 406 | { |
340 | union acpi_object arg = { ACPI_TYPE_INTEGER }; | 407 | int i, ret; |
341 | struct acpi_object_list arg_list = { 1, &arg }; | ||
342 | acpi_status status = AE_OK; | ||
343 | int i; | ||
344 | int ret = 0; | ||
345 | |||
346 | 408 | ||
347 | if (!dev || !dev->wakeup.flags.valid) | 409 | if (!dev || !dev->wakeup.flags.valid) |
348 | return -1; | 410 | return -EINVAL; |
349 | 411 | ||
350 | arg.integer.value = 0; | 412 | /* |
351 | /* Execute PSW */ | 413 | * Do not execute the code below twice in a row without calling |
352 | status = acpi_evaluate_object(dev->handle, "_PSW", &arg_list, NULL); | 414 | * acpi_enable_wakeup_device_power() in between for the same device |
353 | if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) { | 415 | */ |
354 | printk(KERN_ERR PREFIX "Evaluate _PSW\n"); | 416 | if (!dev->wakeup.flags.prepared) |
355 | dev->wakeup.flags.valid = 0; | 417 | return 0; |
356 | return -1; | 418 | |
357 | } | 419 | dev->wakeup.flags.prepared = 0; |
420 | |||
421 | ret = acpi_device_sleep_wake(dev, 0, 0, 0); | ||
422 | if (ret) | ||
423 | return ret; | ||
358 | 424 | ||
359 | /* Close power resource */ | 425 | /* Close power resource */ |
360 | for (i = 0; i < dev->wakeup.resources.count; i++) { | 426 | for (i = 0; i < dev->wakeup.resources.count; i++) { |
@@ -362,7 +428,7 @@ int acpi_disable_wakeup_device_power(struct acpi_device *dev) | |||
362 | if (ret) { | 428 | if (ret) { |
363 | printk(KERN_ERR PREFIX "Transition power state\n"); | 429 | printk(KERN_ERR PREFIX "Transition power state\n"); |
364 | dev->wakeup.flags.valid = 0; | 430 | dev->wakeup.flags.valid = 0; |
365 | return -1; | 431 | return -ENODEV; |
366 | } | 432 | } |
367 | } | 433 | } |
368 | 434 | ||