aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/bus.c')
-rw-r--r--drivers/acpi/bus.c270
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}
179EXPORT_SYMBOL(acpi_bus_get_private_data); 179EXPORT_SYMBOL(acpi_bus_get_private_data);
180 180
181/* --------------------------------------------------------------------------
182 Power Management
183 -------------------------------------------------------------------------- */
184
185static 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
203static 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 */
268int 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}
358EXPORT_SYMBOL(acpi_device_set_power);
359
360
361int 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}
379EXPORT_SYMBOL(acpi_bus_set_power);
380
381
382int 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
406int 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}
426EXPORT_SYMBOL_GPL(acpi_bus_update_power);
427
428
429bool 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
438EXPORT_SYMBOL(acpi_bus_power_manageable);
439
440bool 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
449EXPORT_SYMBOL(acpi_bus_can_wakeup);
450
451static void acpi_print_osc_error(acpi_handle handle, 181static 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{