diff options
Diffstat (limited to 'drivers/acpi/bus.c')
-rw-r--r-- | drivers/acpi/bus.c | 270 |
1 files changed, 0 insertions, 270 deletions
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 1f0d457ecbcf..01708a165368 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c | |||
@@ -178,276 +178,6 @@ int acpi_bus_get_private_data(acpi_handle handle, void **data) | |||
178 | } | 178 | } |
179 | EXPORT_SYMBOL(acpi_bus_get_private_data); | 179 | EXPORT_SYMBOL(acpi_bus_get_private_data); |
180 | 180 | ||
181 | /* -------------------------------------------------------------------------- | ||
182 | Power Management | ||
183 | -------------------------------------------------------------------------- */ | ||
184 | |||
185 | static const char *state_string(int state) | ||
186 | { | ||
187 | switch (state) { | ||
188 | case ACPI_STATE_D0: | ||
189 | return "D0"; | ||
190 | case ACPI_STATE_D1: | ||
191 | return "D1"; | ||
192 | case ACPI_STATE_D2: | ||
193 | return "D2"; | ||
194 | case ACPI_STATE_D3_HOT: | ||
195 | return "D3hot"; | ||
196 | case ACPI_STATE_D3_COLD: | ||
197 | return "D3"; | ||
198 | default: | ||
199 | return "(unknown)"; | ||
200 | } | ||
201 | } | ||
202 | |||
203 | static int __acpi_bus_get_power(struct acpi_device *device, int *state) | ||
204 | { | ||
205 | int result = ACPI_STATE_UNKNOWN; | ||
206 | |||
207 | if (!device || !state) | ||
208 | return -EINVAL; | ||
209 | |||
210 | if (!device->flags.power_manageable) { | ||
211 | /* TBD: Non-recursive algorithm for walking up hierarchy. */ | ||
212 | *state = device->parent ? | ||
213 | device->parent->power.state : ACPI_STATE_D0; | ||
214 | goto out; | ||
215 | } | ||
216 | |||
217 | /* | ||
218 | * Get the device's power state either directly (via _PSC) or | ||
219 | * indirectly (via power resources). | ||
220 | */ | ||
221 | if (device->power.flags.explicit_get) { | ||
222 | unsigned long long psc; | ||
223 | acpi_status status = acpi_evaluate_integer(device->handle, | ||
224 | "_PSC", NULL, &psc); | ||
225 | if (ACPI_FAILURE(status)) | ||
226 | return -ENODEV; | ||
227 | |||
228 | result = psc; | ||
229 | } | ||
230 | /* The test below covers ACPI_STATE_UNKNOWN too. */ | ||
231 | if (result <= ACPI_STATE_D2) { | ||
232 | ; /* Do nothing. */ | ||
233 | } else if (device->power.flags.power_resources) { | ||
234 | int error = acpi_power_get_inferred_state(device, &result); | ||
235 | if (error) | ||
236 | return error; | ||
237 | } else if (result == ACPI_STATE_D3_HOT) { | ||
238 | result = ACPI_STATE_D3; | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * If we were unsure about the device parent's power state up to this | ||
243 | * point, the fact that the device is in D0 implies that the parent has | ||
244 | * to be in D0 too. | ||
245 | */ | ||
246 | if (device->parent && device->parent->power.state == ACPI_STATE_UNKNOWN | ||
247 | && result == ACPI_STATE_D0) | ||
248 | device->parent->power.state = ACPI_STATE_D0; | ||
249 | |||
250 | *state = result; | ||
251 | |||
252 | out: | ||
253 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] power state is %s\n", | ||
254 | device->pnp.bus_id, state_string(*state))); | ||
255 | |||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | |||
260 | /** | ||
261 | * acpi_device_set_power - Set power state of an ACPI device. | ||
262 | * @device: Device to set the power state of. | ||
263 | * @state: New power state to set. | ||
264 | * | ||
265 | * Callers must ensure that the device is power manageable before using this | ||
266 | * function. | ||
267 | */ | ||
268 | int acpi_device_set_power(struct acpi_device *device, int state) | ||
269 | { | ||
270 | int result = 0; | ||
271 | acpi_status status = AE_OK; | ||
272 | char object_name[5] = { '_', 'P', 'S', '0' + state, '\0' }; | ||
273 | |||
274 | if (!device || (state < ACPI_STATE_D0) || (state > ACPI_STATE_D3_COLD)) | ||
275 | return -EINVAL; | ||
276 | |||
277 | /* Make sure this is a valid target state */ | ||
278 | |||
279 | if (state == device->power.state) { | ||
280 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at %s\n", | ||
281 | state_string(state))); | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | if (!device->power.states[state].flags.valid) { | ||
286 | printk(KERN_WARNING PREFIX "Device does not support %s\n", | ||
287 | state_string(state)); | ||
288 | return -ENODEV; | ||
289 | } | ||
290 | if (device->parent && (state < device->parent->power.state)) { | ||
291 | printk(KERN_WARNING PREFIX | ||
292 | "Cannot set device to a higher-powered" | ||
293 | " state than parent\n"); | ||
294 | return -ENODEV; | ||
295 | } | ||
296 | |||
297 | /* For D3cold we should execute _PS3, not _PS4. */ | ||
298 | if (state == ACPI_STATE_D3_COLD) | ||
299 | object_name[3] = '3'; | ||
300 | |||
301 | /* | ||
302 | * Transition Power | ||
303 | * ---------------- | ||
304 | * On transitions to a high-powered state we first apply power (via | ||
305 | * power resources) then evalute _PSx. Conversly for transitions to | ||
306 | * a lower-powered state. | ||
307 | */ | ||
308 | if (state < device->power.state) { | ||
309 | if (device->power.state >= ACPI_STATE_D3_HOT && | ||
310 | state != ACPI_STATE_D0) { | ||
311 | printk(KERN_WARNING PREFIX | ||
312 | "Cannot transition to non-D0 state from D3\n"); | ||
313 | return -ENODEV; | ||
314 | } | ||
315 | if (device->power.flags.power_resources) { | ||
316 | result = acpi_power_transition(device, state); | ||
317 | if (result) | ||
318 | goto end; | ||
319 | } | ||
320 | if (device->power.states[state].flags.explicit_set) { | ||
321 | status = acpi_evaluate_object(device->handle, | ||
322 | object_name, NULL, NULL); | ||
323 | if (ACPI_FAILURE(status)) { | ||
324 | result = -ENODEV; | ||
325 | goto end; | ||
326 | } | ||
327 | } | ||
328 | } else { | ||
329 | if (device->power.states[state].flags.explicit_set) { | ||
330 | status = acpi_evaluate_object(device->handle, | ||
331 | object_name, NULL, NULL); | ||
332 | if (ACPI_FAILURE(status)) { | ||
333 | result = -ENODEV; | ||
334 | goto end; | ||
335 | } | ||
336 | } | ||
337 | if (device->power.flags.power_resources) { | ||
338 | result = acpi_power_transition(device, state); | ||
339 | if (result) | ||
340 | goto end; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | end: | ||
345 | if (result) | ||
346 | printk(KERN_WARNING PREFIX | ||
347 | "Device [%s] failed to transition to %s\n", | ||
348 | device->pnp.bus_id, state_string(state)); | ||
349 | else { | ||
350 | device->power.state = state; | ||
351 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
352 | "Device [%s] transitioned to %s\n", | ||
353 | device->pnp.bus_id, state_string(state))); | ||
354 | } | ||
355 | |||
356 | return result; | ||
357 | } | ||
358 | EXPORT_SYMBOL(acpi_device_set_power); | ||
359 | |||
360 | |||
361 | int acpi_bus_set_power(acpi_handle handle, int state) | ||
362 | { | ||
363 | struct acpi_device *device; | ||
364 | int result; | ||
365 | |||
366 | result = acpi_bus_get_device(handle, &device); | ||
367 | if (result) | ||
368 | return result; | ||
369 | |||
370 | if (!device->flags.power_manageable) { | ||
371 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
372 | "Device [%s] is not power manageable\n", | ||
373 | dev_name(&device->dev))); | ||
374 | return -ENODEV; | ||
375 | } | ||
376 | |||
377 | return acpi_device_set_power(device, state); | ||
378 | } | ||
379 | EXPORT_SYMBOL(acpi_bus_set_power); | ||
380 | |||
381 | |||
382 | int acpi_bus_init_power(struct acpi_device *device) | ||
383 | { | ||
384 | int state; | ||
385 | int result; | ||
386 | |||
387 | if (!device) | ||
388 | return -EINVAL; | ||
389 | |||
390 | device->power.state = ACPI_STATE_UNKNOWN; | ||
391 | |||
392 | result = __acpi_bus_get_power(device, &state); | ||
393 | if (result) | ||
394 | return result; | ||
395 | |||
396 | if (device->power.flags.power_resources) | ||
397 | result = acpi_power_on_resources(device, state); | ||
398 | |||
399 | if (!result) | ||
400 | device->power.state = state; | ||
401 | |||
402 | return result; | ||
403 | } | ||
404 | |||
405 | |||
406 | int acpi_bus_update_power(acpi_handle handle, int *state_p) | ||
407 | { | ||
408 | struct acpi_device *device; | ||
409 | int state; | ||
410 | int result; | ||
411 | |||
412 | result = acpi_bus_get_device(handle, &device); | ||
413 | if (result) | ||
414 | return result; | ||
415 | |||
416 | result = __acpi_bus_get_power(device, &state); | ||
417 | if (result) | ||
418 | return result; | ||
419 | |||
420 | result = acpi_device_set_power(device, state); | ||
421 | if (!result && state_p) | ||
422 | *state_p = state; | ||
423 | |||
424 | return result; | ||
425 | } | ||
426 | EXPORT_SYMBOL_GPL(acpi_bus_update_power); | ||
427 | |||
428 | |||
429 | bool acpi_bus_power_manageable(acpi_handle handle) | ||
430 | { | ||
431 | struct acpi_device *device; | ||
432 | int result; | ||
433 | |||
434 | result = acpi_bus_get_device(handle, &device); | ||
435 | return result ? false : device->flags.power_manageable; | ||
436 | } | ||
437 | |||
438 | EXPORT_SYMBOL(acpi_bus_power_manageable); | ||
439 | |||
440 | bool acpi_bus_can_wakeup(acpi_handle handle) | ||
441 | { | ||
442 | struct acpi_device *device; | ||
443 | int result; | ||
444 | |||
445 | result = acpi_bus_get_device(handle, &device); | ||
446 | return result ? false : device->wakeup.flags.valid; | ||
447 | } | ||
448 | |||
449 | EXPORT_SYMBOL(acpi_bus_can_wakeup); | ||
450 | |||
451 | static void acpi_print_osc_error(acpi_handle handle, | 181 | static void acpi_print_osc_error(acpi_handle handle, |
452 | struct acpi_osc_context *context, char *error) | 182 | struct acpi_osc_context *context, char *error) |
453 | { | 183 | { |