File:  [DragonFly] / src / sys / dev / acpica / Attic / acpi_powerres.c
Revision 1.1: download - view: text, annotated - select for diffs
Wed Sep 24 03:32:16 2003 UTC (10 years, 10 months ago) by drhodus
Branches: MAIN
CVS tags: HEAD


*  Intel ACPI 20030228 distribution with local DragonFly changes.

*  OSPM ACPI driver.  Note that this driver does not include
   support for PCI interrupt routing or enumeration of ISA bridges or
   Host to PCI bridges.  While functional on some machines, this driver
   should be considered experimental and should be tested prior to being
   deployed in a production environment.


Original work done by John Baldwin
  Sponsored by:   The Weather Channel

    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.1 2003/09/24 03:32:16 drhodus 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:     if ((rp = malloc(sizeof(*rp), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) {
  161: 	status = AE_NO_MEMORY;
  162: 	goto out;
  163:     }
  164:     TAILQ_INIT(&rp->ap_references);
  165:     rp->ap_resource = res;
  166: 
  167:     /* get the Power Resource object */
  168:     buf.Length = ACPI_ALLOCATE_BUFFER;
  169:     if (ACPI_FAILURE(status = AcpiEvaluateObject(res, NULL, NULL, &buf))) {
  170: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "no power resource object\n"));
  171: 	goto out;
  172:     }
  173:     obj = buf.Pointer;
  174:     if (obj->Type != ACPI_TYPE_POWER) {
  175: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "questionable power resource object %s\n", acpi_name(res)));
  176: 	status = AE_TYPE;
  177: 	goto out;
  178:     }
  179:     rp->ap_systemlevel = obj->PowerResource.SystemLevel;
  180:     rp->ap_order = obj->PowerResource.ResourceOrder;
  181:     
  182:     /* sort the resource into the list */
  183:     status = AE_OK;
  184:     srp = TAILQ_FIRST(&acpi_powerresources);
  185:     if ((srp == NULL) || (rp->ap_order < srp->ap_order)) {
  186: 	TAILQ_INSERT_HEAD(&acpi_powerresources, rp, ap_link);
  187: 	goto done;
  188:     }
  189:     TAILQ_FOREACH(srp, &acpi_powerresources, ap_link)
  190: 	if (rp->ap_order < srp->ap_order) {
  191: 	    TAILQ_INSERT_BEFORE(srp, rp, ap_link);
  192: 	    goto done;
  193: 	}
  194:     TAILQ_INSERT_TAIL(&acpi_powerresources, rp, ap_link);
  195: 
  196:  done:
  197:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "registered power resource %s\n", acpi_name(res)));
  198:  out:
  199:     if (buf.Pointer != NULL)
  200: 	AcpiOsFree(buf.Pointer);
  201:     if (ACPI_FAILURE(status) && (rp != NULL))
  202: 	free(rp, M_ACPIPWR);
  203:     return_ACPI_STATUS(status);
  204: }
  205: 
  206: /*
  207:  * Deregister a power resource.
  208:  */
  209: static ACPI_STATUS
  210: acpi_pwr_deregister_resource(ACPI_HANDLE res)
  211: {
  212:     struct acpi_powerresource	*rp;
  213: 
  214:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  215: 
  216:     rp = NULL;
  217:     
  218:     /* find the resource */
  219:     if ((rp = acpi_pwr_find_resource(res)) == NULL)
  220: 	return_ACPI_STATUS(AE_BAD_PARAMETER);
  221: 
  222:     /* check that there are no consumers referencing this resource */
  223:     if (TAILQ_FIRST(&rp->ap_references) != NULL)
  224: 	return_ACPI_STATUS(AE_BAD_PARAMETER);
  225: 
  226:     /* pull it off the list and free it */
  227:     TAILQ_REMOVE(&acpi_powerresources, rp, ap_link);
  228:     free(rp, M_ACPIPWR);
  229: 
  230:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power resource %s\n", acpi_name(res)));
  231: 
  232:     return_ACPI_STATUS(AE_OK);
  233: }
  234: 
  235: /*
  236:  * Register a power consumer.  
  237:  *
  238:  * It's OK to call this if we already know about the consumer.
  239:  */
  240: static ACPI_STATUS
  241: acpi_pwr_register_consumer(ACPI_HANDLE consumer)
  242: {
  243:     struct acpi_powerconsumer	*pc;
  244:     
  245:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  246: 
  247:     /* check to see whether we know about this consumer already */
  248:     if ((pc = acpi_pwr_find_consumer(consumer)) != NULL)
  249: 	return_ACPI_STATUS(AE_OK);
  250:     
  251:     /* allocate a new power consumer */
  252:     if ((pc = malloc(sizeof(*pc), M_ACPIPWR, M_NOWAIT)) == NULL)
  253: 	return_ACPI_STATUS(AE_NO_MEMORY);
  254:     TAILQ_INSERT_HEAD(&acpi_powerconsumers, pc, ac_link);
  255:     TAILQ_INIT(&pc->ac_references);
  256:     pc->ac_consumer = consumer;
  257: 
  258:     pc->ac_state = ACPI_STATE_UNKNOWN;	/* XXX we should try to find its current state */
  259: 
  260:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "registered power consumer %s\n", acpi_name(consumer)));
  261:     
  262:     return_ACPI_STATUS(AE_OK);
  263: }
  264: 
  265: /*
  266:  * Deregister a power consumer.
  267:  *
  268:  * This should only be done once the consumer has been powered off.
  269:  * (XXX is this correct?  Check once implemented)
  270:  */
  271: static ACPI_STATUS
  272: acpi_pwr_deregister_consumer(ACPI_HANDLE consumer)
  273: {
  274:     struct acpi_powerconsumer	*pc;
  275:     
  276:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  277: 
  278:     /* find the consumer */
  279:     if ((pc = acpi_pwr_find_consumer(consumer)) == NULL)
  280: 	return_ACPI_STATUS(AE_BAD_PARAMETER);
  281:     
  282:     /* make sure the consumer's not referencing anything right now */
  283:     if (TAILQ_FIRST(&pc->ac_references) != NULL)
  284: 	return_ACPI_STATUS(AE_BAD_PARAMETER);
  285: 
  286:     /* pull the consumer off the list and free it */
  287:     TAILQ_REMOVE(&acpi_powerconsumers, pc, ac_link);
  288: 
  289:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "deregistered power consumer %s\n", acpi_name(consumer)));
  290: 
  291:     return_ACPI_STATUS(AE_OK);
  292: }
  293: 
  294: /*
  295:  * Set a power consumer to a particular power state.
  296:  */
  297: ACPI_STATUS
  298: acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state)
  299: {
  300:     struct acpi_powerconsumer	*pc;
  301:     struct acpi_powerreference	*pr;
  302:     ACPI_HANDLE			method_handle, reslist_handle, pr0_handle;
  303:     ACPI_BUFFER			reslist_buffer;
  304:     ACPI_OBJECT			*reslist_object;
  305:     ACPI_STATUS			status;
  306:     char			*method_name, *reslist_name;
  307:     int				res_changed;
  308: 
  309:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  310: 
  311:     /* find the consumer */
  312:     if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) {
  313: 	if (ACPI_FAILURE(status = acpi_pwr_register_consumer(consumer)))
  314: 	    return_ACPI_STATUS(status);
  315: 	if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) {
  316: 	    return_ACPI_STATUS(AE_ERROR);	/* something very wrong */
  317: 	}
  318:     }
  319: 
  320:     /* check for valid transitions */
  321:     if ((pc->ac_state == ACPI_STATE_D3) && (state != ACPI_STATE_D0))
  322: 	return_ACPI_STATUS(AE_BAD_PARAMETER);	/* can only go to D0 from D3 */
  323: 
  324:     /* find transition mechanism(s) */
  325:     switch(state) {
  326:     case ACPI_STATE_D0:
  327: 	method_name = "_PS0";
  328: 	reslist_name = "_PR0";
  329: 	break;
  330:     case ACPI_STATE_D1:
  331: 	method_name = "_PS1";
  332: 	reslist_name = "_PR1";
  333: 	break;
  334:     case ACPI_STATE_D2:
  335: 	method_name = "_PS2";
  336: 	reslist_name = "_PR2";
  337: 	break;
  338:     case ACPI_STATE_D3:
  339: 	method_name = "_PS3";
  340: 	reslist_name = "_PR3";
  341: 	break;
  342:     default:
  343: 	return_ACPI_STATUS(AE_BAD_PARAMETER);
  344:     }
  345:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "setup to switch %s D%d -> D%d\n",
  346: 		      acpi_name(consumer), pc->ac_state, state));
  347: 
  348:     /*
  349:      * Verify that this state is supported, ie. one of method or
  350:      * reslist must be present.  We need to do this before we go 
  351:      * dereferencing resources (since we might be trying to go to
  352:      * a state we don't support).
  353:      *
  354:      * Note that if any states are supported, the device has to
  355:      * support D0 and D3.  It's never an error to try to go to
  356:      * D0.
  357:      */
  358:     reslist_buffer.Pointer = NULL;
  359:     reslist_object = NULL;
  360:     if (ACPI_FAILURE(AcpiGetHandle(consumer, method_name, &method_handle)))
  361: 	method_handle = NULL;
  362:     if (ACPI_FAILURE(AcpiGetHandle(consumer, reslist_name, &reslist_handle)))
  363: 	reslist_handle = NULL;
  364:     if ((reslist_handle == NULL) && (method_handle == NULL)) {
  365: 	if (state == ACPI_STATE_D0) {
  366: 	    pc->ac_state = ACPI_STATE_D0;
  367: 	    return_ACPI_STATUS(AE_OK);
  368: 	}
  369: 	if (state != ACPI_STATE_D3) {
  370: 	    goto bad;
  371: 	}
  372: 
  373: 	/* turn off the resources listed in _PR0 to go to D3. */
  374: 	if (ACPI_FAILURE(AcpiGetHandle(consumer, "_PR0", &pr0_handle))) {
  375: 	    goto bad;
  376: 	}
  377: 	reslist_buffer.Length = ACPI_ALLOCATE_BUFFER;
  378: 	if (ACPI_FAILURE(status = AcpiEvaluateObject(pr0_handle, NULL, NULL, &reslist_buffer))) {
  379: 	    goto bad;
  380: 	}
  381: 	reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer;
  382: 	if ((reslist_object->Type != ACPI_TYPE_PACKAGE) ||
  383: 	    (reslist_object->Package.Count == 0)) {
  384: 	    goto bad;
  385: 	}
  386: 	AcpiOsFree(reslist_buffer.Pointer);
  387: 	reslist_buffer.Pointer = NULL;
  388: 	reslist_object = NULL;
  389:     }
  390: 
  391:     /*
  392:      * Check that we can actually fetch the list of power resources
  393:      */
  394:     if (reslist_handle != NULL) {
  395: 	reslist_buffer.Length = ACPI_ALLOCATE_BUFFER;
  396: 	if (ACPI_FAILURE(status = AcpiEvaluateObject(reslist_handle, NULL, NULL, &reslist_buffer))) {
  397: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't evaluate resource list %s\n",
  398: 			      acpi_name(reslist_handle)));
  399: 	    goto out;
  400: 	}
  401: 	reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer;
  402: 	if (reslist_object->Type != ACPI_TYPE_PACKAGE) {
  403: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "resource list is not ACPI_TYPE_PACKAGE (%d)\n",
  404: 			      reslist_object->Type));
  405: 	    status = AE_TYPE;
  406: 	    goto out;
  407: 	}
  408:     }
  409: 
  410:     /*
  411:      * Now we are ready to switch, so  kill off any current power resource references.
  412:      */
  413:     res_changed = 0;
  414:     while((pr = TAILQ_FIRST(&pc->ac_references)) != NULL) {
  415: 	res_changed = 1;
  416: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "removing reference to %s\n", acpi_name(pr->ar_resource->ap_resource)));
  417: 	TAILQ_REMOVE(&pr->ar_resource->ap_references, pr, ar_rlink);
  418: 	TAILQ_REMOVE(&pc->ac_references, pr, ar_clink);
  419: 	free(pr, M_ACPIPWR);
  420:     }
  421: 
  422:     /*
  423:      * Add new power resource references, if we have any.  Traverse the
  424:      * package that we got from evaluating reslist_handle, and look up each
  425:      * of the resources that are referenced.
  426:      */
  427:     if (reslist_object != NULL) {
  428: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "referencing %d new resources\n", 
  429: 			  reslist_object->Package.Count));
  430: 	acpi_ForeachPackageObject(reslist_object, acpi_pwr_reference_resource, pc);
  431: 	res_changed = 1;
  432:     }
  433: 
  434:     /*
  435:      * If we changed anything in the resource list, we need to run a switch
  436:      * pass now.
  437:      */
  438:     if (ACPI_FAILURE(status = acpi_pwr_switch_power())) {
  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? */
  442:     }
  443: 
  444:     /* invoke power state switch method (if present) */
  445:     if (method_handle != NULL) {
  446: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "invoking state transition method %s\n",
  447: 			  acpi_name(method_handle)));
  448: 	if (ACPI_FAILURE(status = AcpiEvaluateObject(method_handle, NULL, NULL, NULL))) {
  449: 		ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to set state - %s\n",
  450: 				  AcpiFormatException(status)));
  451: 		pc->ac_state = ACPI_STATE_UNKNOWN;
  452: 		goto out;	/* XXX Should we return to previous state? */
  453: 	}
  454:     }
  455: 	
  456:     /* transition was successful */
  457:     pc->ac_state = state;
  458:     return_ACPI_STATUS(AE_OK);
  459: 
  460:  bad:
  461:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "attempt to set unsupported state D%d\n", 
  462: 		      state));
  463:     status = AE_BAD_PARAMETER;
  464: 
  465:  out:
  466:     if (reslist_buffer.Pointer != NULL)
  467: 	AcpiOsFree(reslist_buffer.Pointer);
  468:     return_ACPI_STATUS(status);
  469: }
  470: 
  471: /*
  472:  * Called to create a reference between a power consumer and a power resource
  473:  * identified in the object.
  474:  */
  475: static void
  476: acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg)
  477: {
  478:     struct acpi_powerconsumer	*pc = (struct acpi_powerconsumer *)arg;
  479:     struct acpi_powerreference	*pr;
  480:     struct acpi_powerresource	*rp;
  481:     ACPI_HANDLE			res;
  482:     ACPI_STATUS			status;
  483: 
  484:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  485: 
  486:     /* check the object type */
  487:     switch (obj->Type) {
  488:     case ACPI_TYPE_ANY:
  489: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "building reference from %s to %s\n",
  490: 			  acpi_name(pc->ac_consumer), acpi_name(obj->Reference.Handle)));
  491: 
  492: 	res = obj->Reference.Handle;
  493: 	break;
  494: 
  495:     case ACPI_TYPE_STRING:
  496: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "building reference from %s to %s\n",
  497: 			  acpi_name(pc->ac_consumer), obj->String.Pointer));
  498: 
  499: 	/* get the handle of the resource */
  500: 	if (ACPI_FAILURE(status = AcpiGetHandle(NULL, obj->String.Pointer, &res))) {
  501: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't find power resource %s\n", 
  502: 			      obj->String.Pointer));
  503: 	    return_VOID;
  504: 	}
  505: 	break;
  506: 
  507:     default:
  508: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "don't know how to create a power reference to object type %d\n", 
  509: 			  obj->Type));
  510: 	return_VOID;
  511:     }
  512: 
  513:     /* create/look up the resource */
  514:     if (ACPI_FAILURE(status = acpi_pwr_register_resource(res))) {
  515: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't register power resource %s - %s\n",
  516: 			  obj->String.Pointer, AcpiFormatException(status)));
  517: 	return_VOID;
  518:     }
  519:     if ((rp = acpi_pwr_find_resource(res)) == NULL) {
  520: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "power resource list corrupted\n"));
  521: 	return_VOID;
  522:     }
  523:     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "found power resource %s\n", acpi_name(rp->ap_resource)));
  524: 
  525:     /* create a reference between the consumer and resource */
  526:     if ((pr = malloc(sizeof(*pr), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) {
  527: 	ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "couldn't allocate memory for a power consumer reference\n"));
  528: 	return_VOID;
  529:     }
  530:     pr->ar_consumer = pc;
  531:     pr->ar_resource = rp;
  532:     TAILQ_INSERT_TAIL(&pc->ac_references, pr, ar_clink);
  533:     TAILQ_INSERT_TAIL(&rp->ap_references, pr, ar_rlink);
  534:     
  535:     return_VOID;
  536: }
  537: 
  538: 
  539: /*
  540:  * Switch power resources to conform to the desired state.
  541:  *
  542:  * Consumers may have modified the power resource list in an arbitrary
  543:  * fashion; we sweep it in sequence order.
  544:  */
  545: static ACPI_STATUS
  546: acpi_pwr_switch_power(void)
  547: {
  548:     struct acpi_powerresource	*rp;
  549:     ACPI_STATUS			status;
  550:     int				cur;
  551: 
  552:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  553: 
  554:     /*
  555:      * Sweep the list forwards turning things on.
  556:      */
  557:     TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) {
  558: 	if (TAILQ_FIRST(&rp->ap_references) == NULL) {
  559: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s has no references, not turning on\n",
  560: 			      acpi_name(rp->ap_resource)));
  561: 	    continue;
  562: 	}
  563: 
  564: 	/* we could cache this if we trusted it not to change under us */
  565: 	if (ACPI_FAILURE(status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur))) {
  566: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n",
  567: 			      acpi_name(rp->ap_resource), status));
  568: 	    continue;	/* XXX is this correct?  Always switch if in doubt? */
  569: 	}
  570: 
  571: 	/*
  572: 	 * Switch if required.  Note that we ignore the result of the switch
  573: 	 * effort; we don't know what to do if it fails, so checking wouldn't
  574: 	 * help much.
  575: 	 */
  576: 	if (cur != ACPI_PWR_ON) {
  577: 	    if (ACPI_FAILURE(status = AcpiEvaluateObject(rp->ap_resource, "_ON", NULL, NULL))) {
  578: 		ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to switch %s on - %s\n", 
  579: 				  acpi_name(rp->ap_resource), AcpiFormatException(status)));
  580: 	    } else {
  581: 		ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s on\n", acpi_name(rp->ap_resource)));
  582: 	    }
  583: 	} else {
  584: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s is already on\n", acpi_name(rp->ap_resource)));
  585: 	}
  586:     }
  587:     
  588:     /*
  589:      * Sweep the list backwards turning things off.
  590:      */
  591:     TAILQ_FOREACH_REVERSE(rp, &acpi_powerresources, acpi_powerresource_list, ap_link) {
  592: 	if (TAILQ_FIRST(&rp->ap_references) != NULL) {
  593: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s has references, not turning off\n",
  594: 			      acpi_name(rp->ap_resource)));
  595: 	    continue;
  596: 	}
  597: 
  598: 	/* we could cache this if we trusted it not to change under us */
  599: 	if (ACPI_FAILURE(status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur))) {
  600: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "can't get status of %s - %d\n",
  601: 			      acpi_name(rp->ap_resource), status));
  602: 	    continue;	/* XXX is this correct?  Always switch if in doubt? */
  603: 	}
  604: 
  605: 	/*
  606: 	 * Switch if required.  Note that we ignore the result of the switch
  607: 	 * effort; we don't know what to do if it fails, so checking wouldn't
  608: 	 * help much.
  609: 	 */
  610: 	if (cur != ACPI_PWR_OFF) {
  611: 	    if (ACPI_FAILURE(status = AcpiEvaluateObject(rp->ap_resource, "_OFF", NULL, NULL))) {
  612: 		ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "failed to switch %s off - %s\n", 
  613: 				  acpi_name(rp->ap_resource), AcpiFormatException(status)));
  614: 	    } else {
  615: 		ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "switched %s off\n", acpi_name(rp->ap_resource)));
  616: 	    }
  617: 	} else {
  618: 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "%s is already off\n", acpi_name(rp->ap_resource)));
  619: 	}
  620:     }
  621:     return_ACPI_STATUS(AE_OK);
  622: }
  623: 
  624: /*
  625:  * Find a power resource's control structure.
  626:  */
  627: static struct acpi_powerresource *
  628: acpi_pwr_find_resource(ACPI_HANDLE res)
  629: {
  630:     struct acpi_powerresource	*rp;
  631:     
  632:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  633: 
  634:     TAILQ_FOREACH(rp, &acpi_powerresources, ap_link)
  635: 	if (rp->ap_resource == res)
  636: 	    break;
  637:     return_PTR(rp);
  638: }
  639: 
  640: /*
  641:  * Find a power consumer's control structure.
  642:  */
  643: static struct acpi_powerconsumer *
  644: acpi_pwr_find_consumer(ACPI_HANDLE consumer)
  645: {
  646:     struct acpi_powerconsumer	*pc;
  647:     
  648:     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
  649: 
  650:     TAILQ_FOREACH(pc, &acpi_powerconsumers, ac_link)
  651: 	if (pc->ac_consumer == consumer)
  652: 	    break;
  653:     return_PTR(pc);
  654: }
  655: