Sync usage with man page.
[netbsd-mini2440.git] / sys / dev / acpi / acpi_powerres.c
blobb4ba1720f276c159935c756d9fcdd04a3a181125
1 /* $NetBSD: acpi_powerres.c,v 1.7 2009/09/16 10:47:54 mlelstv Exp $ */
3 /*-
4 * Copyright (c) 2001 Michael Smith
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
28 * $FreeBSD: src/sys/dev/acpica/acpi_powerres.c,v 1.14 2002/10/16 17:28:52 jhb Exp $
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: acpi_powerres.c,v 1.7 2009/09/16 10:47:54 mlelstv Exp $");
34 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/proc.h>
37 #include <sys/malloc.h>
38 #include <sys/conf.h>
39 #include <sys/systm.h>
41 #include <dev/acpi/acpica.h>
42 #include <dev/acpi/acpireg.h>
43 #include <dev/acpi/acpivar.h>
46 * ACPI power resource management.
48 * Power resource behaviour is slightly complicated by the fact that
49 * a single power resource may provide power for more than one device.
50 * Thus, we must track the device(s) being powered by a given power
51 * resource, and only deactivate it when there are no powered devices.
53 * Note that this only manages resources for known devices. There is an
54 * ugly case where we may turn of power to a device which is in use because
55 * we don't know that it depends on a given resource. We should perhaps
56 * try to be smarter about this, but a more complete solution would involve
57 * scanning all of the ACPI namespace to find devices we're not currently
58 * aware of, and this raises questions about whether they should be left
59 * on, turned off, etc.
61 * XXX locking
64 MALLOC_DEFINE(M_ACPIPWR, "acpipwr", "ACPI power resources");
67 * Hooks for the ACPI CA debugging infrastructure
69 #define _COMPONENT ACPI_BUS_COMPONENT
70 ACPI_MODULE_NAME("POWERRES")
73 * A relationship between a power resource and a consumer.
75 struct acpi_powerreference {
76 struct acpi_powerconsumer *ar_consumer;
77 struct acpi_powerresource *ar_resource;
78 TAILQ_ENTRY(acpi_powerreference) ar_rlink; /* link on resource list */
79 TAILQ_ENTRY(acpi_powerreference) ar_clink; /* link on consumer */
83 * A power-managed device.
85 struct acpi_powerconsumer {
86 ACPI_HANDLE ac_consumer; /* device which is powered */
87 int ac_state;
88 TAILQ_ENTRY(acpi_powerconsumer) ac_link;
89 TAILQ_HEAD(,acpi_powerreference) ac_references;
93 * A power resource.
95 struct acpi_powerresource {
96 TAILQ_ENTRY(acpi_powerresource) ap_link;
97 TAILQ_HEAD(,acpi_powerreference) ap_references;
98 ACPI_HANDLE ap_resource; /* the resource's handle */
99 ACPI_INTEGER ap_systemlevel;
100 ACPI_INTEGER ap_order;
103 static TAILQ_HEAD(acpi_powerresource_list, acpi_powerresource)
104 acpi_powerresources = TAILQ_HEAD_INITIALIZER(acpi_powerresources);
105 static TAILQ_HEAD(acpi_powerconsumer_list, acpi_powerconsumer)
106 acpi_powerconsumers = TAILQ_HEAD_INITIALIZER(acpi_powerconsumers);
108 static ACPI_STATUS acpi_pwr_register_consumer(ACPI_HANDLE);
109 #if 0
110 static ACPI_STATUS acpi_pwr_register_resource(ACPI_HANDLE);
111 static ACPI_STATUS acpi_pwr_deregister_consumer(ACPI_HANDLE);
112 static ACPI_STATUS acpi_pwr_deregister_resource(ACPI_HANDLE);
113 #endif
114 static ACPI_STATUS acpi_pwr_reference_resource(ACPI_OBJECT *, void *);
115 static ACPI_STATUS acpi_pwr_switch_power(void);
116 static struct acpi_powerresource *acpi_pwr_find_resource(ACPI_HANDLE);
117 static struct acpi_powerconsumer *acpi_pwr_find_consumer(ACPI_HANDLE);
120 * Register a power resource.
122 * It's OK to call this if we already know about the resource.
124 static ACPI_STATUS
125 acpi_pwr_register_resource(ACPI_HANDLE res)
127 ACPI_STATUS status;
128 ACPI_BUFFER buf;
129 ACPI_OBJECT *obj;
130 struct acpi_powerresource *rp, *srp;
132 ACPI_FUNCTION_TRACE(__func__);
134 rp = NULL;
135 buf.Pointer = NULL;
137 /* look to see if we know about this resource */
138 if (acpi_pwr_find_resource(res) != NULL)
139 return_ACPI_STATUS(AE_OK); /* already know about it */
141 /* allocate a new resource */
142 if ((rp = malloc(sizeof(*rp), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) {
143 status = AE_NO_MEMORY;
144 goto out;
146 TAILQ_INIT(&rp->ap_references);
147 rp->ap_resource = res;
149 /* get the Power Resource object */
150 status = acpi_eval_struct(res, NULL, &buf);
151 if (ACPI_FAILURE(status)) {
152 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
153 "no power resource object\n"));
154 goto out;
156 obj = buf.Pointer;
157 if (obj->Type != ACPI_TYPE_POWER) {
158 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
159 "questionable power resource object %s\n",
160 acpi_name(res)));
161 status = AE_TYPE;
162 goto out;
164 rp->ap_systemlevel = obj->PowerResource.SystemLevel;
165 rp->ap_order = obj->PowerResource.ResourceOrder;
167 /* sort the resource into the list */
168 status = AE_OK;
169 srp = TAILQ_FIRST(&acpi_powerresources);
170 if ((srp == NULL) || (rp->ap_order < srp->ap_order)) {
171 TAILQ_INSERT_HEAD(&acpi_powerresources, rp, ap_link);
172 goto done;
174 TAILQ_FOREACH(srp, &acpi_powerresources, ap_link)
175 if (rp->ap_order < srp->ap_order) {
176 TAILQ_INSERT_BEFORE(srp, rp, ap_link);
177 goto done;
179 TAILQ_INSERT_TAIL(&acpi_powerresources, rp, ap_link);
181 done:
182 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "registered power resource %s\n",
183 acpi_name(res)));
184 out:
185 if (buf.Pointer != NULL)
186 ACPI_FREE(buf.Pointer);
187 if (ACPI_FAILURE(status) && (rp != NULL))
188 free(rp, M_ACPIPWR);
189 return_ACPI_STATUS(status);
192 #if 0
194 * Deregister a power resource.
196 static ACPI_STATUS
197 acpi_pwr_deregister_resource(ACPI_HANDLE res)
199 struct acpi_powerresource *rp;
201 ACPI_FUNCTION_TRACE(__func__);
203 rp = NULL;
205 /* find the resource */
206 if ((rp = acpi_pwr_find_resource(res)) == NULL)
207 return_ACPI_STATUS(AE_BAD_PARAMETER);
209 /* check that there are no consumers referencing this resource */
210 if (TAILQ_FIRST(&rp->ap_references) != NULL)
211 return_ACPI_STATUS(AE_BAD_PARAMETER);
213 /* pull it off the list and free it */
214 TAILQ_REMOVE(&acpi_powerresources, rp, ap_link);
215 free(rp, M_ACPIPWR);
217 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power resource %s\n",
218 acpi_name(res)));
220 return_ACPI_STATUS(AE_OK);
222 #endif
225 * Register a power consumer.
227 * It's OK to call this if we already know about the consumer.
229 static ACPI_STATUS
230 acpi_pwr_register_consumer(ACPI_HANDLE consumer)
232 struct acpi_powerconsumer *pc;
234 ACPI_FUNCTION_TRACE(__func__);
236 /* check to see whether we know about this consumer already */
237 if ((pc = acpi_pwr_find_consumer(consumer)) != NULL)
238 return_ACPI_STATUS(AE_OK);
240 /* allocate a new power consumer */
241 if ((pc = malloc(sizeof(*pc), M_ACPIPWR, M_NOWAIT)) == NULL)
242 return_ACPI_STATUS(AE_NO_MEMORY);
243 TAILQ_INSERT_HEAD(&acpi_powerconsumers, pc, ac_link);
244 TAILQ_INIT(&pc->ac_references);
245 pc->ac_consumer = consumer;
247 /* XXX we should try to find its current state */
248 pc->ac_state = ACPI_STATE_UNKNOWN;
250 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "registered power consumer %s\n",
251 acpi_name(consumer)));
253 return_ACPI_STATUS(AE_OK);
256 #if 0
258 * Deregister a power consumer.
260 * This should only be done once the consumer has been powered off.
261 * (XXX is this correct? Check once implemented)
263 static ACPI_STATUS
264 acpi_pwr_deregister_consumer(ACPI_HANDLE consumer)
266 struct acpi_powerconsumer *pc;
268 ACPI_FUNCTION_TRACE(__func__);
270 /* find the consumer */
271 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL)
272 return_ACPI_STATUS(AE_BAD_PARAMETER);
274 /* make sure the consumer's not referencing anything right now */
275 if (TAILQ_FIRST(&pc->ac_references) != NULL)
276 return_ACPI_STATUS(AE_BAD_PARAMETER);
278 /* pull the consumer off the list and free it */
279 TAILQ_REMOVE(&acpi_powerconsumers, pc, ac_link);
281 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power consumer %s\n",
282 acpi_name(consumer)));
284 return_ACPI_STATUS(AE_OK);
286 #endif
289 * Set a power consumer to a particular power state.
291 ACPI_STATUS
292 acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
294 struct acpi_powerconsumer *pc;
295 struct acpi_powerreference *pr;
296 ACPI_HANDLE method_handle, reslist_handle, pr0_handle;
297 ACPI_BUFFER reslist_buffer;
298 ACPI_OBJECT *reslist_object;
299 ACPI_STATUS status;
300 const char *method_name, *reslist_name;
301 int res_changed;
303 ACPI_FUNCTION_TRACE(__func__);
305 /* find the consumer */
306 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) {
307 status = acpi_pwr_register_consumer(consumer);
308 if (ACPI_FAILURE(status))
309 return_ACPI_STATUS(status);
310 if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) {
311 return_ACPI_STATUS(AE_ERROR); /* something very wrong */
315 /* check for valid transitions */
316 if ((pc->ac_state == ACPI_STATE_D3) && (state != ACPI_STATE_D0))
317 return_ACPI_STATUS(AE_BAD_PARAMETER); /* can only go to D0 from D3 */
319 /* find transition mechanism(s) */
320 switch(state) {
321 case ACPI_STATE_D0:
322 method_name = "_PS0";
323 reslist_name = "_PR0";
324 break;
325 case ACPI_STATE_D1:
326 method_name = "_PS1";
327 reslist_name = "_PR1";
328 break;
329 case ACPI_STATE_D2:
330 method_name = "_PS2";
331 reslist_name = "_PR2";
332 break;
333 case ACPI_STATE_D3:
334 method_name = "_PS3";
335 reslist_name = "_PR3";
336 break;
337 default:
338 return_ACPI_STATUS(AE_BAD_PARAMETER);
340 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "setup to switch %s D%d -> D%d\n",
341 acpi_name(consumer), pc->ac_state, state));
344 * Verify that this state is supported, ie. one of method or
345 * reslist must be present. We need to do this before we go
346 * dereferencing resources (since we might be trying to go to
347 * a state we don't support).
349 * Note that if any states are supported, the device has to
350 * support D0 and D3. It's never an error to try to go to
351 * D0.
353 reslist_buffer.Pointer = NULL;
354 reslist_object = NULL;
355 if (ACPI_FAILURE(AcpiGetHandle(consumer, method_name, &method_handle)))
356 method_handle = NULL;
357 if (ACPI_FAILURE(AcpiGetHandle(consumer, reslist_name, &reslist_handle)))
358 reslist_handle = NULL;
359 if ((reslist_handle == NULL) && (method_handle == NULL)) {
360 if (state == ACPI_STATE_D0) {
361 pc->ac_state = ACPI_STATE_D0;
362 return_ACPI_STATUS(AE_OK);
364 if (state != ACPI_STATE_D3) {
365 goto bad;
368 /* turn off the resources listed in _PR0 to go to D3. */
369 if (ACPI_FAILURE(AcpiGetHandle(consumer, "_PR0", &pr0_handle))) {
370 goto bad;
372 status = acpi_eval_struct(pr0_handle, NULL, &reslist_buffer);
373 if (ACPI_FAILURE(status))
374 goto bad;
375 reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer;
376 if ((reslist_object->Type != ACPI_TYPE_PACKAGE) ||
377 (reslist_object->Package.Count == 0)) {
378 goto bad;
380 ACPI_FREE(reslist_buffer.Pointer);
381 reslist_buffer.Pointer = NULL;
382 reslist_object = NULL;
386 * Check that we can actually fetch the list of power resources
388 if (reslist_handle != NULL) {
389 status = acpi_eval_struct(reslist_handle,
390 NULL, &reslist_buffer);
391 if (ACPI_FAILURE(status)) {
392 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't evaluate resource list %s\n",
393 acpi_name(reslist_handle)));
394 goto out;
396 reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer;
397 if (reslist_object->Type != ACPI_TYPE_PACKAGE) {
398 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "resource list is not ACPI_TYPE_PACKAGE (%d)\n",
399 reslist_object->Type));
400 status = AE_TYPE;
401 goto out;
406 * Now we are ready to switch, so kill off any current power resource references.
408 res_changed = 0;
409 while((pr = TAILQ_FIRST(&pc->ac_references)) != NULL) {
410 res_changed = 1;
411 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
412 "removing reference to %s\n",
413 acpi_name(pr->ar_resource->ap_resource)));
414 TAILQ_REMOVE(&pr->ar_resource->ap_references, pr, ar_rlink);
415 TAILQ_REMOVE(&pc->ac_references, pr, ar_clink);
416 free(pr, M_ACPIPWR);
420 * Add new power resource references, if we have any. Traverse the
421 * package that we got from evaluating reslist_handle, and look up each
422 * of the resources that are referenced.
424 if (reslist_object != NULL) {
425 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
426 "referencing %d new resources\n",
427 reslist_object->Package.Count));
428 acpi_foreach_package_object(reslist_object,
429 acpi_pwr_reference_resource, pc);
430 res_changed = 1;
434 * If we changed anything in the resource list, we need to run a switch
435 * pass now.
437 status = acpi_pwr_switch_power();
438 if (ACPI_FAILURE(status)) {
439 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to correctly switch resources to move %s to D%d\n",
440 acpi_name(consumer), state));
441 goto out; /* XXX is this appropriate? Should we return to previous state? */
444 /* invoke power state switch method (if present) */
445 if (method_handle != NULL) {
446 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
447 "invoking state transition method %s\n",
448 acpi_name(method_handle)));
449 status = AcpiEvaluateObject(method_handle, NULL, NULL, NULL);
450 if (ACPI_FAILURE(status)) {
451 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
452 "failed to set state - %s\n",
453 AcpiFormatException(status)));
454 pc->ac_state = ACPI_STATE_UNKNOWN;
455 goto out; /* XXX Should we return to previous state? */
459 /* transition was successful */
460 pc->ac_state = state;
461 return_ACPI_STATUS(AE_OK);
463 bad:
464 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
465 "attempt to set unsupported state D%d\n",
466 state));
467 status = AE_BAD_PARAMETER;
469 out:
470 if (reslist_buffer.Pointer != NULL)
471 ACPI_FREE(reslist_buffer.Pointer);
472 return_ACPI_STATUS(status);
476 * Called to create a reference between a power consumer and a power resource
477 * identified in the object.
479 static ACPI_STATUS
480 acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg)
482 struct acpi_powerconsumer *pc = (struct acpi_powerconsumer *)arg;
483 struct acpi_powerreference *pr;
484 struct acpi_powerresource *rp;
485 ACPI_HANDLE res;
486 ACPI_STATUS status;
488 ACPI_FUNCTION_TRACE(__func__);
490 /* check the object type */
491 switch (obj->Type) {
492 case ACPI_TYPE_LOCAL_REFERENCE:
493 case ACPI_TYPE_ANY:
494 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "building reference from %s to %s\n",
495 acpi_name(pc->ac_consumer), acpi_name(obj->Reference.Handle)));
497 res = obj->Reference.Handle;
498 break;
500 case ACPI_TYPE_STRING:
501 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
502 "building reference from %s to %s\n",
503 acpi_name(pc->ac_consumer),
504 obj->String.Pointer));
506 /* get the handle of the resource */
507 status = AcpiGetHandle(NULL, obj->String.Pointer, &res);
508 if (ACPI_FAILURE(status)) {
509 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
510 "couldn't find power resource %s\n",
511 obj->String.Pointer));
512 return_ACPI_STATUS(AE_OK);
514 break;
516 default:
517 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
518 "don't know how to create a power reference to object type %d\n",
519 obj->Type));
520 return_ACPI_STATUS(AE_OK);
523 /* create/look up the resource */
524 status = acpi_pwr_register_resource(res);
525 if (ACPI_FAILURE(status)) {
526 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
527 "couldn't register power resource %s - %s\n",
528 obj->String.Pointer,
529 AcpiFormatException(status)));
530 return_ACPI_STATUS(AE_OK);
532 if ((rp = acpi_pwr_find_resource(res)) == NULL) {
533 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
534 "power resource list corrupted\n"));
535 return_ACPI_STATUS(AE_OK);
537 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "found power resource %s\n",
538 acpi_name(rp->ap_resource)));
540 /* create a reference between the consumer and resource */
541 if ((pr = malloc(sizeof(*pr), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) {
542 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't allocate memory for a power consumer reference\n"));
543 return_ACPI_STATUS(AE_OK);
545 pr->ar_consumer = pc;
546 pr->ar_resource = rp;
547 TAILQ_INSERT_TAIL(&pc->ac_references, pr, ar_clink);
548 TAILQ_INSERT_TAIL(&rp->ap_references, pr, ar_rlink);
550 return_ACPI_STATUS(AE_OK);
555 * Switch power resources to conform to the desired state.
557 * Consumers may have modified the power resource list in an arbitrary
558 * fashion; we sweep it in sequence order.
560 static ACPI_STATUS
561 acpi_pwr_switch_power(void)
563 struct acpi_powerresource *rp;
564 ACPI_STATUS status;
565 ACPI_INTEGER cur;
567 ACPI_FUNCTION_TRACE(__func__);
570 * Sweep the list forwards turning things on.
572 TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) {
573 if (TAILQ_FIRST(&rp->ap_references) == NULL) {
574 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s has no references, not turning on\n",
575 acpi_name(rp->ap_resource)));
576 continue;
579 /* we could cache this if we trusted it not to change under us */
580 status = acpi_eval_integer(rp->ap_resource, "_STA", &cur);
581 if (ACPI_FAILURE(status)) {
582 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
583 "can't get status of %s - %d\n",
584 acpi_name(rp->ap_resource),
585 status));
586 /* XXX is this correct? Always switch if in doubt? */
587 continue;
591 * Switch if required. Note that we ignore the result
592 * of the switch effort; we don't know what to do if
593 * it fails, so checking wouldn't help much.
595 if (cur != ACPI_STA_POW_ON) {
596 status = AcpiEvaluateObject(rp->ap_resource, "_ON",
597 NULL, NULL);
598 if (ACPI_FAILURE(status)) {
599 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to switch %s on - %s\n",
600 acpi_name(rp->ap_resource),
601 AcpiFormatException(status)));
602 } else {
603 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s on\n", acpi_name(rp->ap_resource)));
605 } else {
606 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS,
607 "%s is already on\n",
608 acpi_name(rp->ap_resource)));
613 * Sweep the list backwards turning things off.
615 TAILQ_FOREACH_REVERSE(rp, &acpi_powerresources, acpi_powerresource_list, ap_link) {
616 if (TAILQ_FIRST(&rp->ap_references) != NULL) {
617 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s has references, not turning off\n",
618 acpi_name(rp->ap_resource)));
619 continue;
622 /* we could cache this if we trusted it not to change under us */
623 status = acpi_eval_integer(rp->ap_resource, "_STA", &cur);
624 if (ACPI_FAILURE(status)) {
625 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n",
626 acpi_name(rp->ap_resource), status));
627 continue; /* XXX is this correct? Always switch if in doubt? */
631 * Switch if required. Note that we ignore the result
632 * of the switch effort; we don't know what to do if
633 * it fails, so checking wouldn't help much.
635 if (cur != ACPI_STA_POW_OFF) {
636 status = AcpiEvaluateObject(rp->ap_resource, "_OFF",
637 NULL, NULL);
638 if (ACPI_FAILURE(status)) {
639 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to switch %s off - %s\n",
640 acpi_name(rp->ap_resource), AcpiFormatException(status)));
641 } else {
642 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s off\n",
643 acpi_name(rp->ap_resource)));
645 } else {
646 ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s is already off\n",
647 acpi_name(rp->ap_resource)));
650 return_ACPI_STATUS(AE_OK);
654 * Find a power resource's control structure.
656 static struct acpi_powerresource *
657 acpi_pwr_find_resource(ACPI_HANDLE res)
659 struct acpi_powerresource *rp;
661 ACPI_FUNCTION_TRACE(__func__);
663 TAILQ_FOREACH(rp, &acpi_powerresources, ap_link)
664 if (rp->ap_resource == res)
665 break;
666 return_PTR(rp);
670 * Find a power consumer's control structure.
672 static struct acpi_powerconsumer *
673 acpi_pwr_find_consumer(ACPI_HANDLE consumer)
675 struct acpi_powerconsumer *pc;
677 ACPI_FUNCTION_TRACE(__func__);
679 TAILQ_FOREACH(pc, &acpi_powerconsumers, ac_link)
680 if (pc->ac_consumer == consumer)
681 break;
682 return_PTR(pc);