File:  [DragonFly] / src / sys / dev / acpica / Attic / acpi_powerres.c
Revision 1.2: download - view: text, annotated - select for diffs
Wed May 5 22:19:23 2004 UTC (10 years, 2 months ago) by dillon
Branches: MAIN
CVS tags: HEAD
Use M_INTWAIT instead of M_NOWAIT for the rest of the acpica support code.
Also remove (now unneeded) NULL checks.

    1: /*-
    2:  * Copyright (c) 2001 Michael Smith
    3:  * All rights reserved.
    4:  *
    5:  * Redistribution and use in source and binary forms, with or without
    6:  * modification, are permitted provided that the following conditions
    7:  * are met:
    8:  * 1. Redistributions of source code must retain the above copyright
    9:  *    notice, this list of conditions and the following disclaimer.
   10:  * 2. Redistributions in binary form must reproduce the above copyright
   11:  *    notice, this list of conditions and the following disclaimer in the
   12:  *    documentation and/or other materials provided with the distribution.
   13:  *
   14:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24:  * SUCH DAMAGE.
   25:  *
   26:  *	$FreeBSD: src/sys/dev/acpica/acpi_powerres.c,v 1.14.6.1 2003/08/22 20:49:20 jhb Exp $
   27:  *      $DragonFly: src/sys/dev/acpica/acpi_powerres.c,v 1.2 2004/05/05 22:19:23 dillon Exp $ 
   28:  */
   29: 
   30: #include "opt_acpi.h"		/* XXX trim includes */
   31: #include <sys/param.h>
   32: #include <sys/kernel.h>
   33: #include <sys/proc.h>
   34: #include <sys/malloc.h>
   35: #include <sys/bus.h>
   36: #include <sys/conf.h>
   37: #include <sys/ioccom.h>
   38: #include <sys/reboot.h>
   39: #include <sys/sysctl.h>
   40: #include <sys/systm.h>
   41: #include <sys/ctype.h>
   42: 
   43: #include <machine/clock.h>
   44: 
   45: #include <machine/resource.h>
   46: 
   47: #include "acpi.h"
   48: 
   49: #include <dev/acpica/acpivar.h>
   50: #include <dev/acpica/acpiio.h>
   51: 
   52: /*
   53:  * ACPI power resource management.
   54:  *
   55:  * Power resource behaviour is slightly complicated by the fact that
   56:  * a single power resource may provide power for more than one device.
   57:  * Thus, we must track the device(s) being powered by a given power
   58:  * resource, and only deactivate it when there are no powered devices.
   59:  *
   60:  * Note that this only manages resources for known devices.  There is an
   61:  * ugly case where we may turn of power to a device which is in use because
   62:  * we don't know that it depends on a given resource.  We should perhaps
   63:  * try to be smarter about this, but a more complete solution would involve
   64:  * scanning all of the ACPI namespace to find devices we're not currently
   65:  * aware of, and this raises questions about whether they should be left 
   66:  * on, turned off, etc.
   67:  *
   68:  * XXX locking
   69:  */
   70: 
   71: MALLOC_DEFINE(M_ACPIPWR, "acpipwr", "ACPI power resources");
   72: 
   73: /*
   74:  * Hooks for the ACPI CA debugging infrastructure
   75:  */
   76: #define _COMPONENT	ACPI_POWER
   77: ACPI_MODULE_NAME("POWERRES")
   78: 
   79: /* return values from _STA on a power resource */
   80: #define ACPI_PWR_OFF	0
   81: #define ACPI_PWR_ON	1
   82: 
   83: /*
   84:  * A relationship between a power resource and a consumer.
   85:  */
   86: struct acpi_powerreference {
   87:     struct acpi_powerconsumer	*ar_consumer;
   88:     struct acpi_powerresource	*ar_resource;
   89:     TAILQ_ENTRY(acpi_powerreference) ar_rlink;	/* link on resource list */
   90:     TAILQ_ENTRY(acpi_powerreference) ar_clink;	/* link on consumer */
   91: };
   92:     
   93: /*
   94:  * A power-managed device.
   95:  */
   96: struct acpi_powerconsumer {
   97:     ACPI_HANDLE		ac_consumer;		/* device which is powered */
   98:     int			ac_state;
   99:     TAILQ_ENTRY(acpi_powerconsumer) ac_link;
  100:     TAILQ_HEAD(,acpi_powerreference) ac_references;
  101: };
  102: 
  103: /*
  104:  * A power resource.
  105:  */
  106: struct acpi_powerresource {
  107:     TAILQ_ENTRY(acpi_powerresource) ap_link;
  108:     TAILQ_HEAD(,acpi_powerreference) ap_references;
  109:     ACPI_HANDLE		ap_resource;		/* the resource's handle */
  110:     ACPI_INTEGER	ap_systemlevel;
  111:     ACPI_INTEGER	ap_order;
  112: };
  113: 
  114: static TAILQ_HEAD(acpi_powerresource_list, acpi_powerresource)	acpi_powerresources;
  115: static TAILQ_HEAD(acpi_powerconsumer_list, acpi_powerconsumer)	acpi_powerconsumers;
  116: 
  117: static ACPI_STATUS		acpi_pwr_register_consumer(ACPI_HANDLE consumer);
  118: static ACPI_STATUS		acpi_pwr_deregister_consumer(ACPI_HANDLE consumer);
  119: static ACPI_STATUS		acpi_pwr_register_resource(ACPI_HANDLE res);
  120: static ACPI_STATUS		acpi_pwr_deregister_resource(ACPI_HANDLE res);
  121: static void			acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg);
  122: static ACPI_STATUS		acpi_pwr_switch_power(void);
  123: static struct acpi_powerresource *acpi_pwr_find_resource(ACPI_HANDLE res);
  124: static struct acpi_powerconsumer *acpi_pwr_find_consumer(ACPI_HANDLE consumer);
  125: 
  126: /*
  127:  * Initialise our lists.
  128:  */    
  129: static void
  130: acpi_pwr_init(void *junk)
  131: {
  132:     TAILQ_INIT(&acpi_powerresources);
  133:     TAILQ_INIT(&acpi_powerconsumers);
  134: }
  135: SYSINIT(acpi_powerresource, SI_SUB_TUNABLES, SI_ORDER_ANY, acpi_pwr_init, NULL);
  136: 
  137: /*
  138:  * Register a power resource.
  139:  *
  140:  * It's OK to call this if we already know about the resource.
  141:  */
  142: static ACPI_STATUS
  143: acpi_pwr_register_resource(ACPI_HANDLE res)
  144: {
  145:     ACPI_STATUS			status;
  146:     ACPI_BUFFER			buf;
  147:     ACPI_OBJECT			*obj;
  148:     struct acpi_powerresource	*rp, *srp;
  149: 
  150:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  151: 
  152:     rp = NULL;
  153:     buf.Pointer = NULL;
  154:     
  155:     /* look to see if we know about this resource */
  156:     if (acpi_pwr_find_resource(res) != NULL)
  157: 	return_ACPI_STATUS(AE_OK);		/* already know about it */
  158: 
  159:     /* allocate a new resource */
  160:     rp = malloc(sizeof(*rp), M_ACPIPWR, M_INTWAIT | M_ZERO);
  161:     TAILQ_INIT(&rp->ap_references);
  162:     rp->ap_resource = res;
  163: 
  164:     /* get the Power Resource object */
  165:     buf.Length = ACPI_ALLOCATE_BUFFER;
  166:     if (ACPI_FAILURE(status = AcpiEvaluateObject(res, NULL, NULL, &buf))) {
  167: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "no power resource object\n"));
  168: 	goto out;
  169:     }
  170:     obj = buf.Pointer;
  171:     if (obj->Type != ACPI_TYPE_POWER) {
  172: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "questionable power resource object %s\n", acpi_name(res)));
  173: 	status = AE_TYPE;
  174: 	goto out;
  175:     }
  176:     rp->ap_systemlevel = obj->PowerResource.SystemLevel;
  177:     rp->ap_order = obj->PowerResource.ResourceOrder;
  178:     
  179:     /* sort the resource into the list */
  180:     status = AE_OK;
  181:     srp = TAILQ_FIRST(&acpi_powerresources);
  182:     if ((srp == NULL) || (rp->ap_order < srp->ap_order)) {
  183: 	TAILQ_INSERT_HEAD(&acpi_powerresources, rp, ap_link);
  184: 	goto done;
  185:     }
  186:     TAILQ_FOREACH(srp, &acpi_powerresources, ap_link)
  187: 	if (rp->ap_order < srp->ap_order) {
  188: 	    TAILQ_INSERT_BEFORE(srp, rp, ap_link);
  189: 	    goto done;
  190: 	}
  191:     TAILQ_INSERT_TAIL(&acpi_powerresources, rp, ap_link);
  192: 
  193:  done:
  194:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "registered power resource %s\n", acpi_name(res)));
  195:  out:
  196:     if (buf.Pointer != NULL)
  197: 	AcpiOsFree(buf.Pointer);
  198:     if (ACPI_FAILURE(status) && (rp != NULL))
  199: 	free(rp, M_ACPIPWR);
  200:     return_ACPI_STATUS(status);
  201: }
  202: 
  203: /*
  204:  * Deregister a power resource.
  205:  */
  206: static ACPI_STATUS
  207: acpi_pwr_deregister_resource(ACPI_HANDLE res)
  208: {
  209:     struct acpi_powerresource	*rp;
  210: 
  211:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  212: 
  213:     rp = NULL;
  214:     
  215:     /* find the resource */
  216:     if ((rp = acpi_pwr_find_resource(res)) == NULL)
  217: 	return_ACPI_STATUS(AE_BAD_PARAMETER);
  218: 
  219:     /* check that there are no consumers referencing this resource */
  220:     if (TAILQ_FIRST(&rp->ap_references) != NULL)
  221: 	return_ACPI_STATUS(AE_BAD_PARAMETER);
  222: 
  223:     /* pull it off the list and free it */
  224:     TAILQ_REMOVE(&acpi_powerresources, rp, ap_link);
  225:     free(rp, M_ACPIPWR);
  226: 
  227:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power resource %s\n", acpi_name(res)));
  228: 
  229:     return_ACPI_STATUS(AE_OK);
  230: }
  231: 
  232: /*
  233:  * Register a power consumer.  
  234:  *
  235:  * It's OK to call this if we already know about the consumer.
  236:  */
  237: static ACPI_STATUS
  238: acpi_pwr_register_consumer(ACPI_HANDLE consumer)
  239: {
  240:     struct acpi_powerconsumer	*pc;
  241:     
  242:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  243: 
  244:     /* check to see whether we know about this consumer already */
  245:     if ((pc = acpi_pwr_find_consumer(consumer)) != NULL)
  246: 	return_ACPI_STATUS(AE_OK);
  247:     
  248:     /* allocate a new power consumer */
  249:     pc = malloc(sizeof(*pc), M_ACPIPWR, M_INTWAIT);
  250:     TAILQ_INSERT_HEAD(&acpi_powerconsumers, pc, ac_link);
  251:     TAILQ_INIT(&pc->ac_references);
  252:     pc->ac_consumer = consumer;
  253: 
  254:     pc->ac_state = ACPI_STATE_UNKNOWN;	/* XXX we should try to find its current state */
  255: 
  256:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "registered power consumer %s\n", acpi_name(consumer)));
  257:     
  258:     return_ACPI_STATUS(AE_OK);
  259: }
  260: 
  261: /*
  262:  * Deregister a power consumer.
  263:  *
  264:  * This should only be done once the consumer has been powered off.
  265:  * (XXX is this correct?  Check once implemented)
  266:  */
  267: static ACPI_STATUS
  268: acpi_pwr_deregister_consumer(ACPI_HANDLE consumer)
  269: {
  270:     struct acpi_powerconsumer	*pc;
  271:     
  272:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  273: 
  274:     /* find the consumer */
  275:     if ((pc = acpi_pwr_find_consumer(consumer)) == NULL)
  276: 	return_ACPI_STATUS(AE_BAD_PARAMETER);
  277:     
  278:     /* make sure the consumer's not referencing anything right now */
  279:     if (TAILQ_FIRST(&pc->ac_references) != NULL)
  280: 	return_ACPI_STATUS(AE_BAD_PARAMETER);
  281: 
  282:     /* pull the consumer off the list and free it */
  283:     TAILQ_REMOVE(&acpi_powerconsumers, pc, ac_link);
  284: 
  285:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power consumer %s\n", acpi_name(consumer)));
  286: 
  287:     return_ACPI_STATUS(AE_OK);
  288: }
  289: 
  290: /*
  291:  * Set a power consumer to a particular power state.
  292:  */
  293: ACPI_STATUS
  294: acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
  295: {
  296:     struct acpi_powerconsumer	*pc;
  297:     struct acpi_powerreference	*pr;
  298:     ACPI_HANDLE			method_handle, reslist_handle, pr0_handle;
  299:     ACPI_BUFFER			reslist_buffer;
  300:     ACPI_OBJECT			*reslist_object;
  301:     ACPI_STATUS			status;
  302:     char			*method_name, *reslist_name;
  303:     int				res_changed;
  304: 
  305:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  306: 
  307:     /* find the consumer */
  308:     if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) {
  309: 	if (ACPI_FAILURE(status = acpi_pwr_register_consumer(consumer)))
  310: 	    return_ACPI_STATUS(status);
  311: 	if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) {
  312: 	    return_ACPI_STATUS(AE_ERROR);	/* something very wrong */
  313: 	}
  314:     }
  315: 
  316:     /* check for valid transitions */
  317:     if ((pc->ac_state == ACPI_STATE_D3) && (state != ACPI_STATE_D0))
  318: 	return_ACPI_STATUS(AE_BAD_PARAMETER);	/* can only go to D0 from D3 */
  319: 
  320:     /* find transition mechanism(s) */
  321:     switch(state) {
  322:     case ACPI_STATE_D0:
  323: 	method_name = "_PS0";
  324: 	reslist_name = "_PR0";
  325: 	break;
  326:     case ACPI_STATE_D1:
  327: 	method_name = "_PS1";
  328: 	reslist_name = "_PR1";
  329: 	break;
  330:     case ACPI_STATE_D2:
  331: 	method_name = "_PS2";
  332: 	reslist_name = "_PR2";
  333: 	break;
  334:     case ACPI_STATE_D3:
  335: 	method_name = "_PS3";
  336: 	reslist_name = "_PR3";
  337: 	break;
  338:     default:
  339: 	return_ACPI_STATUS(AE_BAD_PARAMETER);
  340:     }
  341:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "setup to switch %s D%d -> D%d\n",
  342: 		      acpi_name(consumer), pc->ac_state, state));
  343: 
  344:     /*
  345:      * Verify that this state is supported, ie. one of method or
  346:      * reslist must be present.  We need to do this before we go 
  347:      * dereferencing resources (since we might be trying to go to
  348:      * a state we don't support).
  349:      *
  350:      * Note that if any states are supported, the device has to
  351:      * support D0 and D3.  It's never an error to try to go to
  352:      * D0.
  353:      */
  354:     reslist_buffer.Pointer = NULL;
  355:     reslist_object = NULL;
  356:     if (ACPI_FAILURE(AcpiGetHandle(consumer, method_name, &method_handle)))
  357: 	method_handle = NULL;
  358:     if (ACPI_FAILURE(AcpiGetHandle(consumer, reslist_name, &reslist_handle)))
  359: 	reslist_handle = NULL;
  360:     if ((reslist_handle == NULL) && (method_handle == NULL)) {
  361: 	if (state == ACPI_STATE_D0) {
  362: 	    pc->ac_state = ACPI_STATE_D0;
  363: 	    return_ACPI_STATUS(AE_OK);
  364: 	}
  365: 	if (state != ACPI_STATE_D3) {
  366: 	    goto bad;
  367: 	}
  368: 
  369: 	/* turn off the resources listed in _PR0 to go to D3. */
  370: 	if (ACPI_FAILURE(AcpiGetHandle(consumer, "_PR0", &pr0_handle))) {
  371: 	    goto bad;
  372: 	}
  373: 	reslist_buffer.Length = ACPI_ALLOCATE_BUFFER;
  374: 	if (ACPI_FAILURE(status = AcpiEvaluateObject(pr0_handle, NULL, NULL, &reslist_buffer))) {
  375: 	    goto bad;
  376: 	}
  377: 	reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer;
  378: 	if ((reslist_object->Type != ACPI_TYPE_PACKAGE) ||
  379: 	    (reslist_object->Package.Count == 0)) {
  380: 	    goto bad;
  381: 	}
  382: 	AcpiOsFree(reslist_buffer.Pointer);
  383: 	reslist_buffer.Pointer = NULL;
  384: 	reslist_object = NULL;
  385:     }
  386: 
  387:     /*
  388:      * Check that we can actually fetch the list of power resources
  389:      */
  390:     if (reslist_handle != NULL) {
  391: 	reslist_buffer.Length = ACPI_ALLOCATE_BUFFER;
  392: 	if (ACPI_FAILURE(status = AcpiEvaluateObject(reslist_handle, NULL, NULL, &reslist_buffer))) {
  393: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't evaluate resource list %s\n",
  394: 			      acpi_name(reslist_handle)));
  395: 	    goto out;
  396: 	}
  397: 	reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer;
  398: 	if (reslist_object->Type != ACPI_TYPE_PACKAGE) {
  399: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "resource list is not ACPI_TYPE_PACKAGE (%d)\n",
  400: 			      reslist_object->Type));
  401: 	    status = AE_TYPE;
  402: 	    goto out;
  403: 	}
  404:     }
  405: 
  406:     /*
  407:      * Now we are ready to switch, so  kill off any current power resource references.
  408:      */
  409:     res_changed = 0;
  410:     while((pr = TAILQ_FIRST(&pc->ac_references)) != NULL) {
  411: 	res_changed = 1;
  412: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "removing reference to %s\n", acpi_name(pr->ar_resource->ap_resource)));
  413: 	TAILQ_REMOVE(&pr->ar_resource->ap_references, pr, ar_rlink);
  414: 	TAILQ_REMOVE(&pc->ac_references, pr, ar_clink);
  415: 	free(pr, M_ACPIPWR);
  416:     }
  417: 
  418:     /*
  419:      * Add new power resource references, if we have any.  Traverse the
  420:      * package that we got from evaluating reslist_handle, and look up each
  421:      * of the resources that are referenced.
  422:      */
  423:     if (reslist_object != NULL) {
  424: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "referencing %d new resources\n", 
  425: 			  reslist_object->Package.Count));
  426: 	acpi_ForeachPackageObject(reslist_object, acpi_pwr_reference_resource, pc);
  427: 	res_changed = 1;
  428:     }
  429: 
  430:     /*
  431:      * If we changed anything in the resource list, we need to run a switch
  432:      * pass now.
  433:      */
  434:     if (ACPI_FAILURE(status = acpi_pwr_switch_power())) {
  435: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to correctly switch resources to move %s to D%d\n",
  436: 			  acpi_name(consumer), state));
  437: 	goto out;		/* XXX is this appropriate?  Should we return to previous state? */
  438:     }
  439: 
  440:     /* invoke power state switch method (if present) */
  441:     if (method_handle != NULL) {
  442: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "invoking state transition method %s\n",
  443: 			  acpi_name(method_handle)));
  444: 	if (ACPI_FAILURE(status = AcpiEvaluateObject(method_handle, NULL, NULL, NULL))) {
  445: 		ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to set state - %s\n",
  446: 				  AcpiFormatException(status)));
  447: 		pc->ac_state = ACPI_STATE_UNKNOWN;
  448: 		goto out;	/* XXX Should we return to previous state? */
  449: 	}
  450:     }
  451: 	
  452:     /* transition was successful */
  453:     pc->ac_state = state;
  454:     return_ACPI_STATUS(AE_OK);
  455: 
  456:  bad:
  457:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "attempt to set unsupported state D%d\n", 
  458: 		      state));
  459:     status = AE_BAD_PARAMETER;
  460: 
  461:  out:
  462:     if (reslist_buffer.Pointer != NULL)
  463: 	AcpiOsFree(reslist_buffer.Pointer);
  464:     return_ACPI_STATUS(status);
  465: }
  466: 
  467: /*
  468:  * Called to create a reference between a power consumer and a power resource
  469:  * identified in the object.
  470:  */
  471: static void
  472: acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg)
  473: {
  474:     struct acpi_powerconsumer	*pc = (struct acpi_powerconsumer *)arg;
  475:     struct acpi_powerreference	*pr;
  476:     struct acpi_powerresource	*rp;
  477:     ACPI_HANDLE			res;
  478:     ACPI_STATUS			status;
  479: 
  480:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  481: 
  482:     /* check the object type */
  483:     switch (obj->Type) {
  484:     case ACPI_TYPE_ANY:
  485: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "building reference from %s to %s\n",
  486: 			  acpi_name(pc->ac_consumer), acpi_name(obj->Reference.Handle)));
  487: 
  488: 	res = obj->Reference.Handle;
  489: 	break;
  490: 
  491:     case ACPI_TYPE_STRING:
  492: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "building reference from %s to %s\n",
  493: 			  acpi_name(pc->ac_consumer), obj->String.Pointer));
  494: 
  495: 	/* get the handle of the resource */
  496: 	if (ACPI_FAILURE(status = AcpiGetHandle(NULL, obj->String.Pointer, &res))) {
  497: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't find power resource %s\n", 
  498: 			      obj->String.Pointer));
  499: 	    return_VOID;
  500: 	}
  501: 	break;
  502: 
  503:     default:
  504: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "don't know how to create a power reference to object type %d\n", 
  505: 			  obj->Type));
  506: 	return_VOID;
  507:     }
  508: 
  509:     /* create/look up the resource */
  510:     if (ACPI_FAILURE(status = acpi_pwr_register_resource(res))) {
  511: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't register power resource %s - %s\n",
  512: 			  obj->String.Pointer, AcpiFormatException(status)));
  513: 	return_VOID;
  514:     }
  515:     if ((rp = acpi_pwr_find_resource(res)) == NULL) {
  516: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "power resource list corrupted\n"));
  517: 	return_VOID;
  518:     }
  519:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "found power resource %s\n", acpi_name(rp->ap_resource)));
  520: 
  521:     /* create a reference between the consumer and resource */
  522:     pr = malloc(sizeof(*pr), M_ACPIPWR, M_INTWAIT | M_ZERO);
  523:     pr->ar_consumer = pc;
  524:     pr->ar_resource = rp;
  525:     TAILQ_INSERT_TAIL(&pc->ac_references, pr, ar_clink);
  526:     TAILQ_INSERT_TAIL(&rp->ap_references, pr, ar_rlink);
  527:     
  528:     return_VOID;
  529: }
  530: 
  531: 
  532: /*
  533:  * Switch power resources to conform to the desired state.
  534:  *
  535:  * Consumers may have modified the power resource list in an arbitrary
  536:  * fashion; we sweep it in sequence order.
  537:  */
  538: static ACPI_STATUS
  539: acpi_pwr_switch_power(void)
  540: {
  541:     struct acpi_powerresource	*rp;
  542:     ACPI_STATUS			status;
  543:     int				cur;
  544: 
  545:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  546: 
  547:     /*
  548:      * Sweep the list forwards turning things on.
  549:      */
  550:     TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) {
  551: 	if (TAILQ_FIRST(&rp->ap_references) == NULL) {
  552: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s has no references, not turning on\n",
  553: 			      acpi_name(rp->ap_resource)));
  554: 	    continue;
  555: 	}
  556: 
  557: 	/* we could cache this if we trusted it not to change under us */
  558: 	if (ACPI_FAILURE(status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur))) {
  559: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n",
  560: 			      acpi_name(rp->ap_resource), status));
  561: 	    continue;	/* XXX is this correct?  Always switch if in doubt? */
  562: 	}
  563: 
  564: 	/*
  565: 	 * Switch if required.  Note that we ignore the result of the switch
  566: 	 * effort; we don't know what to do if it fails, so checking wouldn't
  567: 	 * help much.
  568: 	 */
  569: 	if (cur != ACPI_PWR_ON) {
  570: 	    if (ACPI_FAILURE(status = AcpiEvaluateObject(rp->ap_resource, "_ON", NULL, NULL))) {
  571: 		ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to switch %s on - %s\n", 
  572: 				  acpi_name(rp->ap_resource), AcpiFormatException(status)));
  573: 	    } else {
  574: 		ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s on\n", acpi_name(rp->ap_resource)));
  575: 	    }
  576: 	} else {
  577: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s is already on\n", acpi_name(rp->ap_resource)));
  578: 	}
  579:     }
  580:     
  581:     /*
  582:      * Sweep the list backwards turning things off.
  583:      */
  584:     TAILQ_FOREACH_REVERSE(rp, &acpi_powerresources, acpi_powerresource_list, ap_link) {
  585: 	if (TAILQ_FIRST(&rp->ap_references) != NULL) {
  586: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s has references, not turning off\n",
  587: 			      acpi_name(rp->ap_resource)));
  588: 	    continue;
  589: 	}
  590: 
  591: 	/* we could cache this if we trusted it not to change under us */
  592: 	if (ACPI_FAILURE(status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur))) {
  593: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n",
  594: 			      acpi_name(rp->ap_resource), status));
  595: 	    continue;	/* XXX is this correct?  Always switch if in doubt? */
  596: 	}
  597: 
  598: 	/*
  599: 	 * Switch if required.  Note that we ignore the result of the switch
  600: 	 * effort; we don't know what to do if it fails, so checking wouldn't
  601: 	 * help much.
  602: 	 */
  603: 	if (cur != ACPI_PWR_OFF) {
  604: 	    if (ACPI_FAILURE(status = AcpiEvaluateObject(rp->ap_resource, "_OFF", NULL, NULL))) {
  605: 		ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to switch %s off - %s\n", 
  606: 				  acpi_name(rp->ap_resource), AcpiFormatException(status)));
  607: 	    } else {
  608: 		ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s off\n", acpi_name(rp->ap_resource)));
  609: 	    }
  610: 	} else {
  611: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s is already off\n", acpi_name(rp->ap_resource)));
  612: 	}
  613:     }
  614:     return_ACPI_STATUS(AE_OK);
  615: }
  616: 
  617: /*
  618:  * Find a power resource's control structure.
  619:  */
  620: static struct acpi_powerresource *
  621: acpi_pwr_find_resource(ACPI_HANDLE res)
  622: {
  623:     struct acpi_powerresource	*rp;
  624:     
  625:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  626: 
  627:     TAILQ_FOREACH(rp, &acpi_powerresources, ap_link)
  628: 	if (rp->ap_resource == res)
  629: 	    break;
  630:     return_PTR(rp);
  631: }
  632: 
  633: /*
  634:  * Find a power consumer's control structure.
  635:  */
  636: static struct acpi_powerconsumer *
  637: acpi_pwr_find_consumer(ACPI_HANDLE consumer)
  638: {
  639:     struct acpi_powerconsumer	*pc;
  640:     
  641:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  642: 
  643:     TAILQ_FOREACH(pc, &acpi_powerconsumers, ac_link)
  644: 	if (pc->ac_consumer == consumer)
  645: 	    break;
  646:     return_PTR(pc);
  647: }
  648: