acpi_powerres.c revision 78915
178915Smsmith/*- 278915Smsmith * Copyright (c) 2001 Michael Smith 378915Smsmith * All rights reserved. 478915Smsmith * 578915Smsmith * Redistribution and use in source and binary forms, with or without 678915Smsmith * modification, are permitted provided that the following conditions 778915Smsmith * are met: 878915Smsmith * 1. Redistributions of source code must retain the above copyright 978915Smsmith * notice, this list of conditions and the following disclaimer. 1078915Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1178915Smsmith * notice, this list of conditions and the following disclaimer in the 1278915Smsmith * documentation and/or other materials provided with the distribution. 1378915Smsmith * 1478915Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1578915Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1678915Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1778915Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1878915Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1978915Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2078915Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2178915Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2278915Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2378915Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2478915Smsmith * SUCH DAMAGE. 2578915Smsmith * 2678915Smsmith * $FreeBSD: head/sys/dev/acpica/acpi_powerres.c 78915 2001-06-28 06:17:16Z msmith $ 2778915Smsmith */ 2878915Smsmith 2978915Smsmith#include "opt_acpi.h" /* XXX trim includes */ 3078915Smsmith#include <sys/param.h> 3178915Smsmith#include <sys/kernel.h> 3278915Smsmith#include <sys/proc.h> 3378915Smsmith#include <sys/lock.h> 3478915Smsmith#include <sys/malloc.h> 3578915Smsmith#include <sys/mutex.h> 3678915Smsmith#include <sys/bus.h> 3778915Smsmith#include <sys/conf.h> 3878915Smsmith#include <sys/ioccom.h> 3978915Smsmith#include <sys/reboot.h> 4078915Smsmith#include <sys/sysctl.h> 4178915Smsmith#include <sys/systm.h> 4278915Smsmith#include <sys/ctype.h> 4378915Smsmith 4478915Smsmith#include <machine/clock.h> 4578915Smsmith 4678915Smsmith#include <machine/resource.h> 4778915Smsmith 4878915Smsmith#include "acpi.h" 4978915Smsmith 5078915Smsmith#include <dev/acpica/acpivar.h> 5178915Smsmith#include <dev/acpica/acpiio.h> 5278915Smsmith 5378915Smsmith/* 5478915Smsmith * ACPI power resource management. 5578915Smsmith * 5678915Smsmith * Power resource behaviour is slightly complicated by the fact that 5778915Smsmith * a single power resource may provide power for more than one device. 5878915Smsmith * Thus, we must track the device(s) being powered by a given power 5978915Smsmith * resource, and only deactivate it when there are no powered devices. 6078915Smsmith * 6178915Smsmith * Note that this only manages resources for known devices. There is an 6278915Smsmith * ugly case where we may turn of power to a device which is in use because 6378915Smsmith * we don't know that it depends on a given resource. We should perhaps 6478915Smsmith * try to be smarter about this, but a more complete solution would involve 6578915Smsmith * scanning all of the ACPI namespace to find devices we're not currently 6678915Smsmith * aware of, and this raises questions about whether they should be left 6778915Smsmith * on, turned off, etc. 6878915Smsmith * 6978915Smsmith * XXX locking 7078915Smsmith */ 7178915Smsmith 7278915SmsmithMALLOC_DEFINE(M_ACPIPWR, "acpipwr", "ACPI power resources"); 7378915Smsmith 7478915Smsmith/* 7578915Smsmith * Hooks for the ACPI CA debugging infrastructure 7678915Smsmith */ 7778915Smsmith#define _COMPONENT ACPI_POWER_CONTROL 7878915SmsmithMODULE_NAME("POWERRES") 7978915Smsmith 8078915Smsmith/* 8178915Smsmith * A relationship between a power resource and a consumer. 8278915Smsmith */ 8378915Smsmithstruct acpi_powerreference { 8478915Smsmith struct acpi_powerconsumer *ar_consumer; 8578915Smsmith struct acpi_powerresource *ar_resource; 8678915Smsmith TAILQ_ENTRY(acpi_powerreference) ar_rlink; /* link on resource list */ 8778915Smsmith TAILQ_ENTRY(acpi_powerreference) ar_clink; /* link on consumer */ 8878915Smsmith}; 8978915Smsmith 9078915Smsmith/* 9178915Smsmith * A power-managed device. 9278915Smsmith */ 9378915Smsmithstruct acpi_powerconsumer { 9478915Smsmith ACPI_HANDLE ac_consumer; /* device which is powered */ 9578915Smsmith int ac_state; 9678915Smsmith TAILQ_ENTRY(acpi_powerconsumer) ac_link; 9778915Smsmith TAILQ_HEAD(,acpi_powerreference) ac_references; 9878915Smsmith}; 9978915Smsmith 10078915Smsmith/* 10178915Smsmith * A power resource. 10278915Smsmith */ 10378915Smsmithstruct acpi_powerresource { 10478915Smsmith TAILQ_ENTRY(acpi_powerresource) ap_link; 10578915Smsmith TAILQ_HEAD(,acpi_powerreference) ap_references; 10678915Smsmith ACPI_HANDLE ap_resource; /* the resource's handle */ 10778915Smsmith ACPI_INTEGER ap_systemlevel; 10878915Smsmith ACPI_INTEGER ap_order; 10978915Smsmith int ap_state; 11078915Smsmith#define ACPI_PWR_OFF 0 11178915Smsmith#define ACPI_PWR_ON 1 11278915Smsmith}; 11378915Smsmith 11478915SmsmithTAILQ_HEAD(acpi_powerresource_list, acpi_powerresource) acpi_powerresources; 11578915SmsmithTAILQ_HEAD(acpi_powerconsumer_list, acpi_powerconsumer) acpi_powerconsumers; 11678915Smsmith 11778915Smsmithstatic ACPI_STATUS acpi_pwr_register_consumer(ACPI_HANDLE consumer); 11878915Smsmithstatic ACPI_STATUS acpi_pwr_deregister_consumer(ACPI_HANDLE consumer); 11978915Smsmithstatic ACPI_STATUS acpi_pwr_register_resource(ACPI_HANDLE res); 12078915Smsmithstatic ACPI_STATUS acpi_pwr_deregister_resource(ACPI_HANDLE res); 12178915Smsmithstatic void acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg); 12278915Smsmithstatic ACPI_STATUS acpi_pwr_switch_power(void); 12378915Smsmithstatic struct acpi_powerresource *acpi_pwr_find_resource(ACPI_HANDLE res); 12478915Smsmithstatic struct acpi_powerconsumer *acpi_pwr_find_consumer(ACPI_HANDLE consumer); 12578915Smsmith 12678915Smsmith/* 12778915Smsmith * Initialise our lists. 12878915Smsmith */ 12978915Smsmithstatic void 13078915Smsmithacpi_pwr_init(void *junk) 13178915Smsmith{ 13278915Smsmith TAILQ_INIT(&acpi_powerresources); 13378915Smsmith TAILQ_INIT(&acpi_powerconsumers); 13478915Smsmith} 13578915SmsmithSYSINIT(acpi_powerresource, SI_SUB_TUNABLES, SI_ORDER_ANY, acpi_pwr_init, NULL); 13678915Smsmith 13778915Smsmith/* 13878915Smsmith * Register a power resource. 13978915Smsmith * 14078915Smsmith * It's OK to call this if we already know about the resource. 14178915Smsmith */ 14278915Smsmithstatic ACPI_STATUS 14378915Smsmithacpi_pwr_register_resource(ACPI_HANDLE res) 14478915Smsmith{ 14578915Smsmith ACPI_STATUS status; 14678915Smsmith ACPI_BUFFER buf; 14778915Smsmith ACPI_OPERAND_OBJECT *obj; 14878915Smsmith struct acpi_powerresource *rp, *srp; 14978915Smsmith 15078915Smsmith FUNCTION_TRACE(__func__); 15178915Smsmith 15278915Smsmith rp = NULL; 15378915Smsmith obj = NULL; 15478915Smsmith 15578915Smsmith /* look to see if we know about this resource */ 15678915Smsmith if (acpi_pwr_find_resource(res) != NULL) 15778915Smsmith return_ACPI_STATUS(AE_OK); /* already know about it */ 15878915Smsmith 15978915Smsmith /* allocate a new resource */ 16078915Smsmith if ((rp = malloc(sizeof(*rp), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) { 16178915Smsmith status = AE_NO_MEMORY; 16278915Smsmith goto out; 16378915Smsmith } 16478915Smsmith TAILQ_INIT(&rp->ap_references); 16578915Smsmith rp->ap_resource = res; 16678915Smsmith 16778915Smsmith /* get the Power Resource object */ 16878915Smsmith if ((status = acpi_EvaluateIntoBuffer(res, NULL, NULL, &buf)) != AE_OK) { 16978915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("no power resource object\n")); 17078915Smsmith goto out; 17178915Smsmith } 17278915Smsmith obj = buf.Pointer; 17378915Smsmith if (obj->Common.Type != ACPI_TYPE_POWER) { 17478915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("bad power resource object\n")); 17578915Smsmith status = AE_TYPE; 17678915Smsmith goto out; 17778915Smsmith } 17878915Smsmith rp->ap_systemlevel = obj->PowerResource.SystemLevel; 17978915Smsmith rp->ap_order = obj->PowerResource.ResourceOrder; 18078915Smsmith 18178915Smsmith /* get the current state of the resource */ 18278915Smsmith if ((status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &rp->ap_state)) != AE_OK) { 18378915Smsmith /* XXX is this an error? */ 18478915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("can't get current power resource state\n")); 18578915Smsmith goto out; 18678915Smsmith } 18778915Smsmith 18878915Smsmith /* sort the resource into the list */ 18978915Smsmith status = AE_OK; 19078915Smsmith srp = TAILQ_FIRST(&acpi_powerresources); 19178915Smsmith if ((srp == NULL) || (rp->ap_order < srp->ap_order)) { 19278915Smsmith TAILQ_INSERT_HEAD(&acpi_powerresources, rp, ap_link); 19378915Smsmith goto out; 19478915Smsmith } 19578915Smsmith TAILQ_FOREACH(srp, &acpi_powerresources, ap_link) 19678915Smsmith if (rp->ap_order < srp->ap_order) { 19778915Smsmith TAILQ_INSERT_BEFORE(srp, rp, ap_link); 19878915Smsmith goto out; 19978915Smsmith } 20078915Smsmith TAILQ_INSERT_TAIL(&acpi_powerresources, rp, ap_link); 20178915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("registered power resource %s\n", acpi_name(res))); 20278915Smsmith 20378915Smsmith out: 20478915Smsmith if (obj != NULL) 20578915Smsmith AcpiOsFree(obj); 20678915Smsmith if ((status != AE_OK) && (rp != NULL)) 20778915Smsmith free(rp, M_ACPIPWR); 20878915Smsmith return_ACPI_STATUS(status); 20978915Smsmith} 21078915Smsmith 21178915Smsmith/* 21278915Smsmith * Deregister a power resource. 21378915Smsmith */ 21478915Smsmithstatic ACPI_STATUS 21578915Smsmithacpi_pwr_deregister_resource(ACPI_HANDLE res) 21678915Smsmith{ 21778915Smsmith struct acpi_powerresource *rp; 21878915Smsmith 21978915Smsmith FUNCTION_TRACE(__func__); 22078915Smsmith 22178915Smsmith rp = NULL; 22278915Smsmith 22378915Smsmith /* find the resource */ 22478915Smsmith if ((rp = acpi_pwr_find_resource(res)) == NULL) 22578915Smsmith return_ACPI_STATUS(AE_BAD_PARAMETER); 22678915Smsmith 22778915Smsmith /* check that there are no consumers referencing this resource */ 22878915Smsmith if (TAILQ_FIRST(&rp->ap_references) != NULL) 22978915Smsmith return_ACPI_STATUS(AE_BAD_PARAMETER); 23078915Smsmith 23178915Smsmith /* pull it off the list and free it */ 23278915Smsmith TAILQ_REMOVE(&acpi_powerresources, rp, ap_link); 23378915Smsmith free(rp, M_ACPIPWR); 23478915Smsmith 23578915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("deregistered power resource %s\n", acpi_name(res))); 23678915Smsmith 23778915Smsmith return_ACPI_STATUS(AE_OK); 23878915Smsmith} 23978915Smsmith 24078915Smsmith/* 24178915Smsmith * Register a power consumer. 24278915Smsmith * 24378915Smsmith * It's OK to call this if we already know about the consumer. 24478915Smsmith */ 24578915Smsmithstatic ACPI_STATUS 24678915Smsmithacpi_pwr_register_consumer(ACPI_HANDLE consumer) 24778915Smsmith{ 24878915Smsmith struct acpi_powerconsumer *pc; 24978915Smsmith 25078915Smsmith FUNCTION_TRACE(__func__); 25178915Smsmith 25278915Smsmith /* check to see whether we know about this consumer already */ 25378915Smsmith if ((pc = acpi_pwr_find_consumer(consumer)) != NULL) 25478915Smsmith return_ACPI_STATUS(AE_OK); 25578915Smsmith 25678915Smsmith /* allocate a new power consumer */ 25778915Smsmith if ((pc = malloc(sizeof(*pc), M_ACPIPWR, M_NOWAIT)) == NULL) 25878915Smsmith return_ACPI_STATUS(AE_NO_MEMORY); 25978915Smsmith TAILQ_INSERT_HEAD(&acpi_powerconsumers, pc, ac_link); 26078915Smsmith TAILQ_INIT(&pc->ac_references); 26178915Smsmith pc->ac_consumer = consumer; 26278915Smsmith 26378915Smsmith pc->ac_state = ACPI_STATE_UNKNOWN; /* XXX we should try to find its current state */ 26478915Smsmith 26578915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("registered power consumer %s\n", acpi_name(consumer))); 26678915Smsmith 26778915Smsmith return_ACPI_STATUS(AE_OK); 26878915Smsmith} 26978915Smsmith 27078915Smsmith/* 27178915Smsmith * Deregister a power consumer. 27278915Smsmith * 27378915Smsmith * This should only be done once the consumer has been powered off. 27478915Smsmith * (XXX is this correct? Check once implemented) 27578915Smsmith */ 27678915Smsmithstatic ACPI_STATUS 27778915Smsmithacpi_pwr_deregister_consumer(ACPI_HANDLE consumer) 27878915Smsmith{ 27978915Smsmith struct acpi_powerconsumer *pc; 28078915Smsmith 28178915Smsmith FUNCTION_TRACE(__func__); 28278915Smsmith 28378915Smsmith /* find the consumer */ 28478915Smsmith if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) 28578915Smsmith return_ACPI_STATUS(AE_BAD_PARAMETER); 28678915Smsmith 28778915Smsmith /* make sure the consumer's not referencing anything right now */ 28878915Smsmith if (TAILQ_FIRST(&pc->ac_references) != NULL) 28978915Smsmith return_ACPI_STATUS(AE_BAD_PARAMETER); 29078915Smsmith 29178915Smsmith /* pull the consumer off the list and free it */ 29278915Smsmith TAILQ_REMOVE(&acpi_powerconsumers, pc, ac_link); 29378915Smsmith 29478915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("deregistered power consumer %s\n", acpi_name(consumer))); 29578915Smsmith 29678915Smsmith return_ACPI_STATUS(AE_OK); 29778915Smsmith} 29878915Smsmith 29978915Smsmith/* 30078915Smsmith * Set a power consumer to a particular power state. 30178915Smsmith */ 30278915SmsmithACPI_STATUS 30378915Smsmithacpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state) 30478915Smsmith{ 30578915Smsmith struct acpi_powerconsumer *pc; 30678915Smsmith struct acpi_powerreference *pr; 30778915Smsmith ACPI_HANDLE method_handle, reslist_handle; 30878915Smsmith ACPI_BUFFER reslist_buffer; 30978915Smsmith ACPI_OBJECT *reslist_object; 31078915Smsmith ACPI_STATUS status; 31178915Smsmith char *method_name, *reslist_name; 31278915Smsmith int res_changed; 31378915Smsmith 31478915Smsmith FUNCTION_TRACE(__func__); 31578915Smsmith 31678915Smsmith /* find the consumer */ 31778915Smsmith if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) { 31878915Smsmith if ((status = acpi_pwr_register_consumer(consumer)) != AE_OK) 31978915Smsmith return_ACPI_STATUS(status); 32078915Smsmith if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) { 32178915Smsmith return_ACPI_STATUS(AE_ERROR); /* something very wrong */ 32278915Smsmith } 32378915Smsmith } 32478915Smsmith 32578915Smsmith /* check for valid transitions */ 32678915Smsmith if ((pc->ac_state == ACPI_STATE_D3) && (state != ACPI_STATE_D0)) 32778915Smsmith return_ACPI_STATUS(AE_BAD_PARAMETER); /* can only go to D0 from D3 */ 32878915Smsmith 32978915Smsmith /* find transition mechanism(s) */ 33078915Smsmith switch(state) { 33178915Smsmith case ACPI_STATE_D0: 33278915Smsmith method_name = "_PS0"; 33378915Smsmith reslist_name = "_PR0"; 33478915Smsmith break; 33578915Smsmith case ACPI_STATE_D1: 33678915Smsmith method_name = "_PS1"; 33778915Smsmith reslist_name = "_PR1"; 33878915Smsmith break; 33978915Smsmith case ACPI_STATE_D2: 34078915Smsmith method_name = "_PS2"; 34178915Smsmith reslist_name = "_PR2"; 34278915Smsmith break; 34378915Smsmith case ACPI_STATE_D3: 34478915Smsmith method_name = "_PS3"; 34578915Smsmith reslist_name = "_PR3"; 34678915Smsmith break; 34778915Smsmith default: 34878915Smsmith return_ACPI_STATUS(AE_BAD_PARAMETER); 34978915Smsmith } 35078915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("setup to switch %s D%d -> D%d\n", 35178915Smsmith acpi_name(consumer), pc->ac_state, state)); 35278915Smsmith 35378915Smsmith /* 35478915Smsmith * Verify that this state is supported, ie. one of method or 35578915Smsmith * reslist must be present. We need to do this before we go 35678915Smsmith * dereferencing resources (since we might be trying to go to 35778915Smsmith * a state we don't support). 35878915Smsmith * 35978915Smsmith * Note that if any states are supported, the device has to 36078915Smsmith * support D0 and D3. It's never an error to try to go to 36178915Smsmith * D0. 36278915Smsmith */ 36378915Smsmith if (AcpiGetHandle(consumer, method_name, &method_handle) != AE_OK) 36478915Smsmith method_handle = NULL; 36578915Smsmith if (AcpiGetHandle(consumer, reslist_name, &reslist_handle) != AE_OK) 36678915Smsmith reslist_handle = NULL; 36778915Smsmith if ((reslist_handle == NULL) && (method_handle == NULL)) { 36878915Smsmith if (state == ACPI_STATE_D0) { 36978915Smsmith pc->ac_state = ACPI_STATE_D0; 37078915Smsmith return_ACPI_STATUS(AE_OK); 37178915Smsmith } 37278915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("attempt to set unsupported state D%d\n", 37378915Smsmith state)); 37478915Smsmith return_ACPI_STATUS(AE_BAD_PARAMETER); 37578915Smsmith } 37678915Smsmith 37778915Smsmith /* 37878915Smsmith * Check that we can actually fetch the list of power resources 37978915Smsmith */ 38078915Smsmith if (reslist_handle != NULL) { 38178915Smsmith if ((status = acpi_EvaluateIntoBuffer(reslist_handle, NULL, NULL, &reslist_buffer)) != AE_OK) { 38278915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("can't evaluate resource list %s\n", 38378915Smsmith acpi_name(reslist_handle))); 38478915Smsmith return_ACPI_STATUS(status); 38578915Smsmith } 38678915Smsmith reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer; 38778915Smsmith if (reslist_object->Type != ACPI_TYPE_PACKAGE) { 38878915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("resource list is not ACPI_TYPE_PACKAGE (%d)\n", 38978915Smsmith reslist_object->Type)); 39078915Smsmith return_ACPI_STATUS(AE_TYPE); 39178915Smsmith } 39278915Smsmith } else { 39378915Smsmith reslist_object = NULL; 39478915Smsmith } 39578915Smsmith 39678915Smsmith /* 39778915Smsmith * Now we are ready to switch, so kill off any current power resource references. 39878915Smsmith */ 39978915Smsmith res_changed = 0; 40078915Smsmith TAILQ_FOREACH(pr, &pc->ac_references, ar_clink) { 40178915Smsmith TAILQ_REMOVE(&pr->ar_resource->ap_references, pr, ar_rlink); 40278915Smsmith res_changed = 1; 40378915Smsmith } 40478915Smsmith 40578915Smsmith /* 40678915Smsmith * Add new power resource references, if we have any. Traverse the 40778915Smsmith * package that we got from evaluating reslist_handle, and look up each 40878915Smsmith * of the resources that are referenced. 40978915Smsmith */ 41078915Smsmith if (reslist_object != NULL) { 41178915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("referencing %d new resources\n", 41278915Smsmith reslist_object->Package.Count)); 41378915Smsmith acpi_ForeachPackageObject(reslist_object, acpi_pwr_reference_resource, pc); 41478915Smsmith res_changed = 1; 41578915Smsmith } 41678915Smsmith 41778915Smsmith /* 41878915Smsmith * If we changed anything in the resource list, we need to run a switch 41978915Smsmith * pass now. 42078915Smsmith */ 42178915Smsmith if ((status = acpi_pwr_switch_power()) != AE_OK) { 42278915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("failed to correctly switch resources to move %s to D%d\n", 42378915Smsmith acpi_name(consumer), state)); 42478915Smsmith return_ACPI_STATUS(status); /* XXX is this appropriate? Should we return to previous state? */ 42578915Smsmith } 42678915Smsmith 42778915Smsmith /* invoke power state switch method (if present) */ 42878915Smsmith if (method_handle != NULL) { 42978915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("invoking state transition method %s\n", 43078915Smsmith acpi_name(method_handle))); 43178915Smsmith if ((status = AcpiEvaluateObject(method_handle, NULL, NULL, NULL)) != AE_OK) 43278915Smsmith pc->ac_state = ACPI_STATE_UNKNOWN; 43378915Smsmith return_ACPI_STATUS(status); /* XXX is this appropriate? Should we return to previous state? */ 43478915Smsmith } 43578915Smsmith 43678915Smsmith /* transition was successful */ 43778915Smsmith pc->ac_state = state; 43878915Smsmith return_ACPI_STATUS(AE_OK); 43978915Smsmith} 44078915Smsmith 44178915Smsmith/* 44278915Smsmith * Called to create a reference between a power consumer and a power resource 44378915Smsmith * identified in the object. 44478915Smsmith */ 44578915Smsmithstatic void 44678915Smsmithacpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg) 44778915Smsmith{ 44878915Smsmith struct acpi_powerconsumer *pc = (struct acpi_powerconsumer *)arg; 44978915Smsmith 45078915Smsmith FUNCTION_TRACE(__func__); 45178915Smsmith 45278915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("called to create a reference using object type %d\n", 45378915Smsmith obj->Type)); 45478915Smsmith 45578915Smsmith return_VOID; 45678915Smsmith} 45778915Smsmith 45878915Smsmith 45978915Smsmith/* 46078915Smsmith * Switch power resources to conform to the desired state. 46178915Smsmith * 46278915Smsmith * Consumers may have modified the power resource list in an arbitrary 46378915Smsmith * fashion; we sweep it in sequence order. 46478915Smsmith */ 46578915Smsmithstatic ACPI_STATUS 46678915Smsmithacpi_pwr_switch_power(void) 46778915Smsmith{ 46878915Smsmith struct acpi_powerresource *rp; 46978915Smsmith ACPI_STATUS status; 47078915Smsmith int cur; 47178915Smsmith 47278915Smsmith FUNCTION_TRACE(__func__); 47378915Smsmith 47478915Smsmith /* 47578915Smsmith * Sweep the list forwards turning things on. 47678915Smsmith */ 47778915Smsmith TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) { 47878915Smsmith if (rp->ap_state != ACPI_PWR_ON) 47978915Smsmith continue; /* not turning this one on */ 48078915Smsmith 48178915Smsmith /* we could cache this if we trusted it not to change under us */ 48278915Smsmith if ((status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur)) != AE_OK) { 48378915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("can't get status of %s - %d\n", 48478915Smsmith acpi_name(rp->ap_resource), status)); 48578915Smsmith continue; /* XXX is this correct? Always switch if in doubt? */ 48678915Smsmith } 48778915Smsmith 48878915Smsmith /* 48978915Smsmith * Switch if required. Note that we ignore the result of the switch 49078915Smsmith * effort; we don't know what to do if it fails, so checking wouldn't 49178915Smsmith * help much. 49278915Smsmith */ 49378915Smsmith if (cur != ACPI_PWR_ON) 49478915Smsmith AcpiEvaluateObject(rp->ap_resource, "_ON", NULL, NULL); 49578915Smsmith } 49678915Smsmith 49778915Smsmith /* 49878915Smsmith * Sweep the list backwards turning things off. 49978915Smsmith */ 50078915Smsmith TAILQ_FOREACH_REVERSE(rp, &acpi_powerresources, acpi_powerresource_list, ap_link) { 50178915Smsmith if (rp->ap_state != ACPI_PWR_OFF) 50278915Smsmith continue; /* not turning this one off */ 50378915Smsmith 50478915Smsmith /* we could cache this if we trusted it not to change under us */ 50578915Smsmith if ((status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur)) != AE_OK) { 50678915Smsmith DEBUG_PRINT(TRACE_OBJECTS, ("can't get status of %s - %d\n", 50778915Smsmith acpi_name(rp->ap_resource), status)); 50878915Smsmith continue; /* XXX is this correct? Always switch if in doubt? */ 50978915Smsmith } 51078915Smsmith 51178915Smsmith /* 51278915Smsmith * Switch if required. Note that we ignore the result of the switch 51378915Smsmith * effort; we don't know what to do if it fails, so checking wouldn't 51478915Smsmith * help much. 51578915Smsmith */ 51678915Smsmith if (cur != ACPI_PWR_OFF) 51778915Smsmith AcpiEvaluateObject(rp->ap_resource, "_OFF", NULL, NULL); 51878915Smsmith } 51978915Smsmith return_ACPI_STATUS(AE_OK); 52078915Smsmith} 52178915Smsmith 52278915Smsmith/* 52378915Smsmith * Find a power resource's control structure. 52478915Smsmith */ 52578915Smsmithstatic struct acpi_powerresource * 52678915Smsmithacpi_pwr_find_resource(ACPI_HANDLE res) 52778915Smsmith{ 52878915Smsmith struct acpi_powerresource *rp; 52978915Smsmith 53078915Smsmith FUNCTION_TRACE(__func__); 53178915Smsmith 53278915Smsmith TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) 53378915Smsmith if (rp->ap_resource == res) 53478915Smsmith break; 53578915Smsmith return_VALUE(rp); 53678915Smsmith} 53778915Smsmith 53878915Smsmith/* 53978915Smsmith * Find a power consumer's control structure. 54078915Smsmith */ 54178915Smsmithstatic struct acpi_powerconsumer * 54278915Smsmithacpi_pwr_find_consumer(ACPI_HANDLE consumer) 54378915Smsmith{ 54478915Smsmith struct acpi_powerconsumer *pc; 54578915Smsmith 54678915Smsmith FUNCTION_TRACE(__func__); 54778915Smsmith 54878915Smsmith TAILQ_FOREACH(pc, &acpi_powerconsumers, ac_link) 54978915Smsmith if (pc->ac_consumer == consumer) 55078915Smsmith break; 55178915Smsmith return_VALUE(pc); 55278915Smsmith} 55378915Smsmith 554