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