diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2010-11-24 18:09:15 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2011-01-12 04:48:45 -0500 |
commit | 25eed40720fc9005c63a1f436e5f8a78836c26ff (patch) | |
tree | 2c927e50d57c2e456d9ceaa575c1bb774627ee10 /drivers/acpi/bus.c | |
parent | ade3e7fef794781c0798d0cf0f046123842ba550 (diff) |
ACPI / PM: Add function for updating device power state consistently
Add function acpi_bus_update_power() for reading the actual power
state of an ACPI device and updating its device->power.state field
in such a way that its power resources' reference counters will
remain consistent with that field.
For this purpose introduce __acpi_bus_set_power() setting the
power state of an ACPI device without updating its
device->power.state field and make acpi_bus_set_power() and
acpi_bus_update_power() use it (acpi_bus_set_power() retains the
current behavior for now).
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/bus.c')
-rw-r--r-- | drivers/acpi/bus.c | 90 |
1 files changed, 61 insertions, 29 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 453451090502..19decee72e92 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -255,44 +255,17 @@ int acpi_bus_get_power(acpi_handle handle, int *state) | |||
255 | EXPORT_SYMBOL(acpi_bus_get_power); | 255 | EXPORT_SYMBOL(acpi_bus_get_power); |
256 | 256 | ||
257 | 257 | ||
258 | int acpi_bus_set_power(acpi_handle handle, int state) | 258 | static int __acpi_bus_set_power(struct acpi_device *device, int state) |
259 | { | 259 | { |
260 | int result = 0; | 260 | int result = 0; |
261 | acpi_status status = AE_OK; | 261 | acpi_status status = AE_OK; |
262 | struct acpi_device *device = NULL; | ||
263 | char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; | 262 | char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; |
264 | 263 | ||
265 | 264 | if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) | |
266 | result = acpi_bus_get_device(handle, &device); | ||
267 | if (result) | ||
268 | return result; | ||
269 | |||
270 | if ((state < ACPI_STATE_D0) || (state > ACPI_STATE_D3)) | ||
271 | return -EINVAL; | 265 | return -EINVAL; |
272 | 266 | ||
273 | /* Make sure this is a valid target state */ | 267 | /* Make sure this is a valid target state */ |
274 | 268 | ||
275 | if (!device->flags.power_manageable) { | ||
276 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n", | ||
277 | kobject_name(&device->dev.kobj))); | ||
278 | return -ENODEV; | ||
279 | } | ||
280 | /* | ||
281 | * Get device's current power state | ||
282 | */ | ||
283 | if (!acpi_power_nocheck) { | ||
284 | /* | ||
285 | * Maybe the incorrect power state is returned on the bogus | ||
286 | * bios, which is different with the real power state. | ||
287 | * For example: the bios returns D0 state and the real power | ||
288 | * state is D3. OS expects to set the device to D0 state. In | ||
289 | * such case if OS uses the power state returned by the BIOS, | ||
290 | * the device can't be transisted to the correct power state. | ||
291 | * So if the acpi_power_nocheck is set, it is unnecessary to | ||
292 | * get the power state by calling acpi_bus_get_power. | ||
293 | */ | ||
294 | acpi_bus_get_power(device->handle, &device->power.state); | ||
295 | } | ||
296 | if ((state == device->power.state) && !device->flags.force_power_state) { | 269 | if ((state == device->power.state) && !device->flags.force_power_state) { |
297 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", | 270 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", |
298 | state)); | 271 | state)); |
@@ -362,6 +335,42 @@ int acpi_bus_set_power(acpi_handle handle, int state) | |||
362 | return result; | 335 | return result; |
363 | } | 336 | } |
364 | 337 | ||
338 | |||
339 | int acpi_bus_set_power(acpi_handle handle, int state) | ||
340 | { | ||
341 | struct acpi_device *device; | ||
342 | int result; | ||
343 | |||
344 | result = acpi_bus_get_device(handle, &device); | ||
345 | if (result) | ||
346 | return result; | ||
347 | |||
348 | if (!device->flags.power_manageable) { | ||
349 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
350 | "Device [%s] is not power manageable\n", | ||
351 | dev_name(&device->dev))); | ||
352 | return -ENODEV; | ||
353 | } | ||
354 | |||
355 | /* | ||
356 | * Get device's current power state | ||
357 | */ | ||
358 | if (!acpi_power_nocheck) { | ||
359 | /* | ||
360 | * Maybe the incorrect power state is returned on the bogus | ||
361 | * bios, which is different with the real power state. | ||
362 | * For example: the bios returns D0 state and the real power | ||
363 | * state is D3. OS expects to set the device to D0 state. In | ||
364 | * such case if OS uses the power state returned by the BIOS, | ||
365 | * the device can't be transisted to the correct power state. | ||
366 | * So if the acpi_power_nocheck is set, it is unnecessary to | ||
367 | * get the power state by calling acpi_bus_get_power. | ||
368 | */ | ||
369 | __acpi_bus_get_power(device, &device->power.state); | ||
370 | } | ||
371 | |||
372 | return __acpi_bus_set_power(device, state); | ||
373 | } | ||
365 | EXPORT_SYMBOL(acpi_bus_set_power); | 374 | EXPORT_SYMBOL(acpi_bus_set_power); |
366 | 375 | ||
367 | 376 | ||
@@ -389,6 +398,29 @@ int acpi_bus_init_power(struct acpi_device *device) | |||
389 | } | 398 | } |
390 | 399 | ||
391 | 400 | ||
401 | int acpi_bus_update_power(acpi_handle handle, int *state_p) | ||
402 | { | ||
403 | struct acpi_device *device; | ||
404 | int state; | ||
405 | int result; | ||
406 | |||
407 | result = acpi_bus_get_device(handle, &device); | ||
408 | if (result) | ||
409 | return result; | ||
410 | |||
411 | result = __acpi_bus_get_power(device, &state); | ||
412 | if (result) | ||
413 | return result; | ||
414 | |||
415 | result = __acpi_bus_set_power(device, state); | ||
416 | if (!result && state_p) | ||
417 | *state_p = state; | ||
418 | |||
419 | return result; | ||
420 | } | ||
421 | EXPORT_SYMBOL_GPL(acpi_bus_update_power); | ||
422 | |||
423 | |||
392 | bool acpi_bus_power_manageable(acpi_handle handle) | 424 | bool acpi_bus_power_manageable(acpi_handle handle) |
393 | { | 425 | { |
394 | struct acpi_device *device; | 426 | struct acpi_device *device; |