diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 754eac84d3d2..c3e3f76976f5 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -706,6 +706,27 @@ acpi_enable_fixed_events(struct acpi_softc *sc) first_time = 0; } +/* + * Returns true if the device is actually present and should + * be attached to. This requires the present, enabled, UI-visible + * and diagnostics-passed bits to be set. + */ +BOOLEAN +acpi_DeviceIsPresent(device_t dev) +{ + ACPI_HANDLE h; + ACPI_DEVICE_INFO devinfo; + ACPI_STATUS error; + + if ((h = acpi_get_handle(dev)) == NULL) + return(FALSE); + if ((error = AcpiGetObjectInfo(h, &devinfo)) != AE_OK) + return(FALSE); + if ((devinfo.Valid & ACPI_VALID_HID) && (devinfo.CurrentStatus & 0xf)) + return(TRUE); + return(FALSE); +} + /* * Match a HID string against a device */ @@ -727,6 +748,46 @@ acpi_MatchHid(device_t dev, char *hid) return(FALSE); } +/* + * Return the handle of a named object within our scope, ie. that of (parent) + * or one if its parents. + */ +ACPI_STATUS +acpi_GetHandleInScope(ACPI_HANDLE parent, char *path, ACPI_HANDLE *result) +{ + ACPI_HANDLE r; + ACPI_STATUS status; + + /* walk back up the tree to the root */ + for (;;) { + status = AcpiGetHandle(parent, path, &r); + if (status == AE_OK) { + *result = r; + return(AE_OK); + } + if (status != AE_NOT_FOUND) + return(AE_OK); + if (AcpiGetParent(parent, &r) != AE_OK) + return(AE_NOT_FOUND); + parent = r; + } +} + +/* + * Allocate a buffer with a preset data size. + */ +ACPI_BUFFER * +acpi_AllocBuffer(int size) +{ + ACPI_BUFFER *buf; + + if ((buf = malloc(size + sizeof(*buf), M_ACPIDEV, M_NOWAIT)) == NULL) + return(NULL); + buf->Length = size; + buf->Pointer = (void *)(buf + 1); + return(buf); +} + /* * Perform the tedious double-get procedure required for fetching something into * an ACPI_BUFFER that has not been initialised. @@ -747,20 +808,75 @@ acpi_GetIntoBuffer(ACPI_HANDLE handle, ACPI_STATUS (*func)(ACPI_HANDLE, ACPI_BUF } /* - * Allocate a buffer with a preset data size. + * Perform the tedious double-evaluate procedure for evaluating something into + * an ACPI_BUFFER that has not been initialised. Note that this evaluates + * twice, so avoid applying this to things that may have side-effects. + * + * This is like AcpiEvaluateObject with automatic buffer allocation. */ -ACPI_BUFFER * -acpi_AllocBuffer(int size) +ACPI_STATUS +acpi_EvaluateIntoBuffer(ACPI_HANDLE object, ACPI_STRING pathname, ACPI_OBJECT_LIST *params, + ACPI_BUFFER *buf) { - ACPI_BUFFER *buf; + ACPI_STATUS status; + + buf->Length = 0; + buf->Pointer = NULL; - if ((buf = malloc(size + sizeof(*buf), M_ACPIDEV, M_NOWAIT)) == NULL) - return(NULL); - buf->Length = size; - buf->Pointer = (void *)(buf + 1); - return(buf); + if ((status = AcpiEvaluateObject(object, pathname, params, buf)) != AE_BUFFER_OVERFLOW) + return(status); + if ((buf->Pointer = AcpiOsCallocate(buf->Length)) == NULL) + return(AE_NO_MEMORY); + return(AcpiEvaluateObject(object, pathname, params, buf)); } +/* + * Evaluate a path that should return an integer. + */ +ACPI_STATUS +acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int *number) +{ + ACPI_STATUS error; + ACPI_BUFFER buf; + ACPI_OBJECT param; + + if (handle == NULL) + handle = ACPI_ROOT_OBJECT; + buf.Pointer = ¶m; + buf.Length = sizeof(param); + if ((error = AcpiEvaluateObject(handle, path, NULL, &buf)) == AE_OK) { + if (param.Type == ACPI_TYPE_INTEGER) { + *number = param.Integer.Value; + } else { + error = AE_TYPE; + } + } + return(error); +} + +/* + * Iterate over the elements of an a package object, calling the supplied + * function for each element. + * + * XXX possible enhancement might be to abort traversal on error. + */ +ACPI_STATUS +acpi_ForeachPackageObject(ACPI_OBJECT *pkg, void (* func)(ACPI_OBJECT *comp, void *arg), void *arg) +{ + ACPI_OBJECT *comp; + int i; + + if ((pkg == NULL) || (pkg->Type != ACPI_TYPE_PACKAGE)) + return(AE_BAD_PARAMETER); + + /* iterate over components */ + for (i = 0, comp = pkg->Package.Elements; i < pkg->Package.Count; i++, comp++) + func(comp, arg); + + return(AE_OK); +} + + static ACPI_STATUS __inline acpi_wakeup(UINT8 state) { @@ -952,51 +1068,6 @@ acpi_Disable(struct acpi_softc *sc) return_ACPI_STATUS(status); } -/* - * Returns true if the device is actually present and should - * be attached to. This requires the present, enabled, UI-visible - * and diagnostics-passed bits to be set. - */ -BOOLEAN -acpi_DeviceIsPresent(device_t dev) -{ - ACPI_HANDLE h; - ACPI_DEVICE_INFO devinfo; - ACPI_STATUS error; - - if ((h = acpi_get_handle(dev)) == NULL) - return(FALSE); - if ((error = AcpiGetObjectInfo(h, &devinfo)) != AE_OK) - return(FALSE); - if ((devinfo.Valid & ACPI_VALID_HID) && (devinfo.CurrentStatus & 0xf)) - return(TRUE); - return(FALSE); -} - -/* - * Evaluate a path that should return an integer. - */ -ACPI_STATUS -acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int *number) -{ - ACPI_STATUS error; - ACPI_BUFFER buf; - ACPI_OBJECT param; - - if (handle == NULL) - handle = ACPI_ROOT_OBJECT; - buf.Pointer = ¶m; - buf.Length = sizeof(param); - if ((error = AcpiEvaluateObject(handle, path, NULL, &buf)) == AE_OK) { - if (param.Type == ACPI_TYPE_INTEGER) { - *number = param.Integer.Value; - } else { - error = AE_TYPE; - } - } - return(error); -} - /* * ACPI Event Handlers */ @@ -1347,63 +1418,67 @@ struct debugtag }; static struct debugtag dbg_layer[] = { - {"GLOBAL", 0x00000001}, - {"COMMON", 0x00000002}, - {"PARSER", 0x00000004}, - {"DISPATCHER", 0x00000008}, - {"INTERPRETER", 0x00000010}, - {"NAMESPACE", 0x00000020}, - {"RESOURCE_MANAGER", 0x00000040}, - {"TABLE_MANAGER", 0x00000080}, - {"EVENT_HANDLING", 0x00000100}, - {"HARDWARE", 0x00000200}, - {"MISCELLANEOUS", 0x00000400}, - {"OS_DEPENDENT", 0x00000800}, - {"BUS_MANAGER", 0x00001000}, - {"PROCESSOR_CONTROL", 0x00002000}, - {"SYSTEM_CONTROL", 0x00004000}, - {"THERMAL_CONTROL", 0x00008000}, - {"POWER_CONTROL", 0x00010000}, - {"EMBEDDED_CONTROLLER", 0x00020000}, - {"BATTERY", 0x00040000}, - {"DEBUGGER", 0x00100000}, - {"ALL_COMPONENTS", 0x001FFFFF}, + {"ACPI_UTILITIES", ACPI_UTILITIES}, + {"ACPI_HARDWARE", ACPI_HARDWARE}, + {"ACPI_EVENTS", ACPI_EVENTS}, + {"ACPI_TABLES", ACPI_TABLES}, + {"ACPI_NAMESPACE", ACPI_NAMESPACE}, + {"ACPI_PARSER", ACPI_PARSER}, + {"ACPI_DISPATCHER", ACPI_DISPATCHER}, + {"ACPI_EXECUTER", ACPI_EXECUTER}, + {"ACPI_RESOURCES", ACPI_RESOURCES}, + {"ACPI_DEVICES", ACPI_DEVICES}, + {"ACPI_POWER", ACPI_POWER}, + {"ACPI_BUS_MANAGER", ACPI_BUS_MANAGER}, + {"ACPI_POWER_CONTROL", ACPI_POWER_CONTROL}, + {"ACPI_EMBEDDED_CONTROLLER", ACPI_EMBEDDED_CONTROLLER}, + {"ACPI_PROCESSOR_CONTROL", ACPI_PROCESSOR_CONTROL}, + {"ACPI_AC_ADAPTER", ACPI_AC_ADAPTER}, + {"ACPI_BATTERY", ACPI_BATTERY}, + {"ACPI_BUTTON", ACPI_BUTTON}, + {"ACPI_SYSTEM", ACPI_SYSTEM}, + {"ACPI_THERMAL_ZONE", ACPI_THERMAL_ZONE}, + {"ACPI_DEBUGGER", ACPI_DEBUGGER}, + {"ACPI_OS_SERVICES", ACPI_OS_SERVICES}, + {"ACPI_ALL_COMPONENTS", ACPI_ALL_COMPONENTS}, {NULL, 0} }; static struct debugtag dbg_level[] = { - {"ACPI_OK", 0x00000001}, - {"ACPI_INFO", 0x00000002}, - {"ACPI_WARN", 0x00000004}, - {"ACPI_ERROR", 0x00000008}, - {"ACPI_FATAL", 0x00000010}, - {"ACPI_DEBUG_OBJECT", 0x00000020}, - {"ACPI_ALL", 0x0000003F}, - {"TRACE_PARSE", 0x00000100}, - {"TRACE_DISPATCH", 0x00000200}, - {"TRACE_LOAD", 0x00000400}, - {"TRACE_EXEC", 0x00000800}, - {"TRACE_NAMES", 0x00001000}, - {"TRACE_OPREGION", 0x00002000}, - {"TRACE_BFIELD", 0x00004000}, - {"TRACE_TRASH", 0x00008000}, - {"TRACE_TABLES", 0x00010000}, - {"TRACE_FUNCTIONS", 0x00020000}, - {"TRACE_VALUES", 0x00040000}, - {"TRACE_OBJECTS", 0x00080000}, - {"TRACE_ALLOCATIONS", 0x00100000}, - {"TRACE_RESOURCES", 0x00200000}, - {"TRACE_IO", 0x00400000}, - {"TRACE_INTERRUPTS", 0x00800000}, - {"TRACE_USER_REQUESTS", 0x01000000}, - {"TRACE_PACKAGE", 0x02000000}, - {"TRACE_MUTEX", 0x04000000}, - {"TRACE_ALL", 0x0FFFFF00}, - {"VERBOSE_AML_DISASSEMBLE", 0x10000000}, - {"VERBOSE_INFO", 0x20000000}, - {"VERBOSE_TABLES", 0x40000000}, - {"VERBOSE_EVENTS", 0x80000000}, - {"VERBOSE_ALL", 0xF0000000}, + {"ACPI_OK", ACPI_OK}, + {"ACPI_INFO", ACPI_INFO}, + {"ACPI_WARN", ACPI_WARN}, + {"ACPI_ERROR", ACPI_ERROR}, + {"ACPI_FATAL", ACPI_FATAL}, + {"ACPI_DEBUG_OBJECT", ACPI_DEBUG_OBJECT}, + {"ACPI_ALL", ACPI_ALL}, + {"TRACE_THREADS", TRACE_THREADS}, + {"TRACE_PARSE", TRACE_PARSE}, + {"TRACE_DISPATCH", TRACE_DISPATCH}, + {"TRACE_LOAD", TRACE_LOAD}, + {"TRACE_EXEC", TRACE_EXEC}, + {"TRACE_NAMES", TRACE_NAMES}, + {"TRACE_OPREGION", TRACE_OPREGION}, + {"TRACE_BFIELD", TRACE_BFIELD}, + {"TRACE_TRASH", TRACE_TRASH}, + {"TRACE_TABLES", TRACE_TABLES}, + {"TRACE_FUNCTIONS", TRACE_FUNCTIONS}, + {"TRACE_VALUES", TRACE_VALUES}, + {"TRACE_OBJECTS", TRACE_OBJECTS}, + {"TRACE_ALLOCATIONS", TRACE_ALLOCATIONS}, + {"TRACE_RESOURCES", TRACE_RESOURCES}, + {"TRACE_IO", TRACE_IO}, + {"TRACE_INTERRUPTS", TRACE_INTERRUPTS}, + {"TRACE_USER_REQUESTS", TRACE_USER_REQUESTS}, + {"TRACE_PACKAGE", TRACE_PACKAGE}, + {"TRACE_MUTEX", TRACE_MUTEX}, + {"TRACE_INIT", TRACE_INIT}, + {"TRACE_ALL", TRACE_ALL}, + {"VERBOSE_AML_DISASSEMBLE", VERBOSE_AML_DISASSEMBLE}, + {"VERBOSE_INFO", VERBOSE_INFO}, + {"VERBOSE_TABLES", VERBOSE_TABLES}, + {"VERBOSE_EVENTS", VERBOSE_EVENTS}, + {"VERBOSE_ALL", VERBOSE_ALL}, {NULL, 0} }; diff --git a/sys/dev/acpica/acpi_powerres.c b/sys/dev/acpica/acpi_powerres.c new file mode 100644 index 000000000000..b5a4b6bc9d2b --- /dev/null +++ b/sys/dev/acpica/acpi_powerres.c @@ -0,0 +1,553 @@ +/*- + * Copyright (c) 2001 Michael Smith + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include "opt_acpi.h" /* XXX trim includes */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "acpi.h" + +#include +#include + +/* + * ACPI power resource management. + * + * Power resource behaviour is slightly complicated by the fact that + * a single power resource may provide power for more than one device. + * Thus, we must track the device(s) being powered by a given power + * resource, and only deactivate it when there are no powered devices. + * + * Note that this only manages resources for known devices. There is an + * ugly case where we may turn of power to a device which is in use because + * we don't know that it depends on a given resource. We should perhaps + * try to be smarter about this, but a more complete solution would involve + * scanning all of the ACPI namespace to find devices we're not currently + * aware of, and this raises questions about whether they should be left + * on, turned off, etc. + * + * XXX locking + */ + +MALLOC_DEFINE(M_ACPIPWR, "acpipwr", "ACPI power resources"); + +/* + * Hooks for the ACPI CA debugging infrastructure + */ +#define _COMPONENT ACPI_POWER_CONTROL +MODULE_NAME("POWERRES") + +/* + * A relationship between a power resource and a consumer. + */ +struct acpi_powerreference { + struct acpi_powerconsumer *ar_consumer; + struct acpi_powerresource *ar_resource; + TAILQ_ENTRY(acpi_powerreference) ar_rlink; /* link on resource list */ + TAILQ_ENTRY(acpi_powerreference) ar_clink; /* link on consumer */ +}; + +/* + * A power-managed device. + */ +struct acpi_powerconsumer { + ACPI_HANDLE ac_consumer; /* device which is powered */ + int ac_state; + TAILQ_ENTRY(acpi_powerconsumer) ac_link; + TAILQ_HEAD(,acpi_powerreference) ac_references; +}; + +/* + * A power resource. + */ +struct acpi_powerresource { + TAILQ_ENTRY(acpi_powerresource) ap_link; + TAILQ_HEAD(,acpi_powerreference) ap_references; + ACPI_HANDLE ap_resource; /* the resource's handle */ + ACPI_INTEGER ap_systemlevel; + ACPI_INTEGER ap_order; + int ap_state; +#define ACPI_PWR_OFF 0 +#define ACPI_PWR_ON 1 +}; + +TAILQ_HEAD(acpi_powerresource_list, acpi_powerresource) acpi_powerresources; +TAILQ_HEAD(acpi_powerconsumer_list, acpi_powerconsumer) acpi_powerconsumers; + +static ACPI_STATUS acpi_pwr_register_consumer(ACPI_HANDLE consumer); +static ACPI_STATUS acpi_pwr_deregister_consumer(ACPI_HANDLE consumer); +static ACPI_STATUS acpi_pwr_register_resource(ACPI_HANDLE res); +static ACPI_STATUS acpi_pwr_deregister_resource(ACPI_HANDLE res); +static void acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg); +static ACPI_STATUS acpi_pwr_switch_power(void); +static struct acpi_powerresource *acpi_pwr_find_resource(ACPI_HANDLE res); +static struct acpi_powerconsumer *acpi_pwr_find_consumer(ACPI_HANDLE consumer); + +/* + * Initialise our lists. + */ +static void +acpi_pwr_init(void *junk) +{ + TAILQ_INIT(&acpi_powerresources); + TAILQ_INIT(&acpi_powerconsumers); +} +SYSINIT(acpi_powerresource, SI_SUB_TUNABLES, SI_ORDER_ANY, acpi_pwr_init, NULL); + +/* + * Register a power resource. + * + * It's OK to call this if we already know about the resource. + */ +static ACPI_STATUS +acpi_pwr_register_resource(ACPI_HANDLE res) +{ + ACPI_STATUS status; + ACPI_BUFFER buf; + ACPI_OPERAND_OBJECT *obj; + struct acpi_powerresource *rp, *srp; + + FUNCTION_TRACE(__func__); + + rp = NULL; + obj = NULL; + + /* look to see if we know about this resource */ + if (acpi_pwr_find_resource(res) != NULL) + return_ACPI_STATUS(AE_OK); /* already know about it */ + + /* allocate a new resource */ + if ((rp = malloc(sizeof(*rp), M_ACPIPWR, M_NOWAIT | M_ZERO)) == NULL) { + status = AE_NO_MEMORY; + goto out; + } + TAILQ_INIT(&rp->ap_references); + rp->ap_resource = res; + + /* get the Power Resource object */ + if ((status = acpi_EvaluateIntoBuffer(res, NULL, NULL, &buf)) != AE_OK) { + DEBUG_PRINT(TRACE_OBJECTS, ("no power resource object\n")); + goto out; + } + obj = buf.Pointer; + if (obj->Common.Type != ACPI_TYPE_POWER) { + DEBUG_PRINT(TRACE_OBJECTS, ("bad power resource object\n")); + status = AE_TYPE; + goto out; + } + rp->ap_systemlevel = obj->PowerResource.SystemLevel; + rp->ap_order = obj->PowerResource.ResourceOrder; + + /* get the current state of the resource */ + if ((status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &rp->ap_state)) != AE_OK) { + /* XXX is this an error? */ + DEBUG_PRINT(TRACE_OBJECTS, ("can't get current power resource state\n")); + goto out; + } + + /* sort the resource into the list */ + status = AE_OK; + srp = TAILQ_FIRST(&acpi_powerresources); + if ((srp == NULL) || (rp->ap_order < srp->ap_order)) { + TAILQ_INSERT_HEAD(&acpi_powerresources, rp, ap_link); + goto out; + } + TAILQ_FOREACH(srp, &acpi_powerresources, ap_link) + if (rp->ap_order < srp->ap_order) { + TAILQ_INSERT_BEFORE(srp, rp, ap_link); + goto out; + } + TAILQ_INSERT_TAIL(&acpi_powerresources, rp, ap_link); + DEBUG_PRINT(TRACE_OBJECTS, ("registered power resource %s\n", acpi_name(res))); + + out: + if (obj != NULL) + AcpiOsFree(obj); + if ((status != AE_OK) && (rp != NULL)) + free(rp, M_ACPIPWR); + return_ACPI_STATUS(status); +} + +/* + * Deregister a power resource. + */ +static ACPI_STATUS +acpi_pwr_deregister_resource(ACPI_HANDLE res) +{ + struct acpi_powerresource *rp; + + FUNCTION_TRACE(__func__); + + rp = NULL; + + /* find the resource */ + if ((rp = acpi_pwr_find_resource(res)) == NULL) + return_ACPI_STATUS(AE_BAD_PARAMETER); + + /* check that there are no consumers referencing this resource */ + if (TAILQ_FIRST(&rp->ap_references) != NULL) + return_ACPI_STATUS(AE_BAD_PARAMETER); + + /* pull it off the list and free it */ + TAILQ_REMOVE(&acpi_powerresources, rp, ap_link); + free(rp, M_ACPIPWR); + + DEBUG_PRINT(TRACE_OBJECTS, ("deregistered power resource %s\n", acpi_name(res))); + + return_ACPI_STATUS(AE_OK); +} + +/* + * Register a power consumer. + * + * It's OK to call this if we already know about the consumer. + */ +static ACPI_STATUS +acpi_pwr_register_consumer(ACPI_HANDLE consumer) +{ + struct acpi_powerconsumer *pc; + + FUNCTION_TRACE(__func__); + + /* check to see whether we know about this consumer already */ + if ((pc = acpi_pwr_find_consumer(consumer)) != NULL) + return_ACPI_STATUS(AE_OK); + + /* allocate a new power consumer */ + if ((pc = malloc(sizeof(*pc), M_ACPIPWR, M_NOWAIT)) == NULL) + return_ACPI_STATUS(AE_NO_MEMORY); + TAILQ_INSERT_HEAD(&acpi_powerconsumers, pc, ac_link); + TAILQ_INIT(&pc->ac_references); + pc->ac_consumer = consumer; + + pc->ac_state = ACPI_STATE_UNKNOWN; /* XXX we should try to find its current state */ + + DEBUG_PRINT(TRACE_OBJECTS, ("registered power consumer %s\n", acpi_name(consumer))); + + return_ACPI_STATUS(AE_OK); +} + +/* + * Deregister a power consumer. + * + * This should only be done once the consumer has been powered off. + * (XXX is this correct? Check once implemented) + */ +static ACPI_STATUS +acpi_pwr_deregister_consumer(ACPI_HANDLE consumer) +{ + struct acpi_powerconsumer *pc; + + FUNCTION_TRACE(__func__); + + /* find the consumer */ + if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) + return_ACPI_STATUS(AE_BAD_PARAMETER); + + /* make sure the consumer's not referencing anything right now */ + if (TAILQ_FIRST(&pc->ac_references) != NULL) + return_ACPI_STATUS(AE_BAD_PARAMETER); + + /* pull the consumer off the list and free it */ + TAILQ_REMOVE(&acpi_powerconsumers, pc, ac_link); + + DEBUG_PRINT(TRACE_OBJECTS, ("deregistered power consumer %s\n", acpi_name(consumer))); + + return_ACPI_STATUS(AE_OK); +} + +/* + * Set a power consumer to a particular power state. + */ +ACPI_STATUS +acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state) +{ + struct acpi_powerconsumer *pc; + struct acpi_powerreference *pr; + ACPI_HANDLE method_handle, reslist_handle; + ACPI_BUFFER reslist_buffer; + ACPI_OBJECT *reslist_object; + ACPI_STATUS status; + char *method_name, *reslist_name; + int res_changed; + + FUNCTION_TRACE(__func__); + + /* find the consumer */ + if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) { + if ((status = acpi_pwr_register_consumer(consumer)) != AE_OK) + return_ACPI_STATUS(status); + if ((pc = acpi_pwr_find_consumer(consumer)) == NULL) { + return_ACPI_STATUS(AE_ERROR); /* something very wrong */ + } + } + + /* check for valid transitions */ + if ((pc->ac_state == ACPI_STATE_D3) && (state != ACPI_STATE_D0)) + return_ACPI_STATUS(AE_BAD_PARAMETER); /* can only go to D0 from D3 */ + + /* find transition mechanism(s) */ + switch(state) { + case ACPI_STATE_D0: + method_name = "_PS0"; + reslist_name = "_PR0"; + break; + case ACPI_STATE_D1: + method_name = "_PS1"; + reslist_name = "_PR1"; + break; + case ACPI_STATE_D2: + method_name = "_PS2"; + reslist_name = "_PR2"; + break; + case ACPI_STATE_D3: + method_name = "_PS3"; + reslist_name = "_PR3"; + break; + default: + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + DEBUG_PRINT(TRACE_OBJECTS, ("setup to switch %s D%d -> D%d\n", + acpi_name(consumer), pc->ac_state, state)); + + /* + * Verify that this state is supported, ie. one of method or + * reslist must be present. We need to do this before we go + * dereferencing resources (since we might be trying to go to + * a state we don't support). + * + * Note that if any states are supported, the device has to + * support D0 and D3. It's never an error to try to go to + * D0. + */ + if (AcpiGetHandle(consumer, method_name, &method_handle) != AE_OK) + method_handle = NULL; + if (AcpiGetHandle(consumer, reslist_name, &reslist_handle) != AE_OK) + reslist_handle = NULL; + if ((reslist_handle == NULL) && (method_handle == NULL)) { + if (state == ACPI_STATE_D0) { + pc->ac_state = ACPI_STATE_D0; + return_ACPI_STATUS(AE_OK); + } + DEBUG_PRINT(TRACE_OBJECTS, ("attempt to set unsupported state D%d\n", + state)); + return_ACPI_STATUS(AE_BAD_PARAMETER); + } + + /* + * Check that we can actually fetch the list of power resources + */ + if (reslist_handle != NULL) { + if ((status = acpi_EvaluateIntoBuffer(reslist_handle, NULL, NULL, &reslist_buffer)) != AE_OK) { + DEBUG_PRINT(TRACE_OBJECTS, ("can't evaluate resource list %s\n", + acpi_name(reslist_handle))); + return_ACPI_STATUS(status); + } + reslist_object = (ACPI_OBJECT *)reslist_buffer.Pointer; + if (reslist_object->Type != ACPI_TYPE_PACKAGE) { + DEBUG_PRINT(TRACE_OBJECTS, ("resource list is not ACPI_TYPE_PACKAGE (%d)\n", + reslist_object->Type)); + return_ACPI_STATUS(AE_TYPE); + } + } else { + reslist_object = NULL; + } + + /* + * Now we are ready to switch, so kill off any current power resource references. + */ + res_changed = 0; + TAILQ_FOREACH(pr, &pc->ac_references, ar_clink) { + TAILQ_REMOVE(&pr->ar_resource->ap_references, pr, ar_rlink); + res_changed = 1; + } + + /* + * Add new power resource references, if we have any. Traverse the + * package that we got from evaluating reslist_handle, and look up each + * of the resources that are referenced. + */ + if (reslist_object != NULL) { + DEBUG_PRINT(TRACE_OBJECTS, ("referencing %d new resources\n", + reslist_object->Package.Count)); + acpi_ForeachPackageObject(reslist_object, acpi_pwr_reference_resource, pc); + res_changed = 1; + } + + /* + * If we changed anything in the resource list, we need to run a switch + * pass now. + */ + if ((status = acpi_pwr_switch_power()) != AE_OK) { + DEBUG_PRINT(TRACE_OBJECTS, ("failed to correctly switch resources to move %s to D%d\n", + acpi_name(consumer), state)); + return_ACPI_STATUS(status); /* XXX is this appropriate? Should we return to previous state? */ + } + + /* invoke power state switch method (if present) */ + if (method_handle != NULL) { + DEBUG_PRINT(TRACE_OBJECTS, ("invoking state transition method %s\n", + acpi_name(method_handle))); + if ((status = AcpiEvaluateObject(method_handle, NULL, NULL, NULL)) != AE_OK) + pc->ac_state = ACPI_STATE_UNKNOWN; + return_ACPI_STATUS(status); /* XXX is this appropriate? Should we return to previous state? */ + } + + /* transition was successful */ + pc->ac_state = state; + return_ACPI_STATUS(AE_OK); +} + +/* + * Called to create a reference between a power consumer and a power resource + * identified in the object. + */ +static void +acpi_pwr_reference_resource(ACPI_OBJECT *obj, void *arg) +{ + struct acpi_powerconsumer *pc = (struct acpi_powerconsumer *)arg; + + FUNCTION_TRACE(__func__); + + DEBUG_PRINT(TRACE_OBJECTS, ("called to create a reference using object type %d\n", + obj->Type)); + + return_VOID; +} + + +/* + * Switch power resources to conform to the desired state. + * + * Consumers may have modified the power resource list in an arbitrary + * fashion; we sweep it in sequence order. + */ +static ACPI_STATUS +acpi_pwr_switch_power(void) +{ + struct acpi_powerresource *rp; + ACPI_STATUS status; + int cur; + + FUNCTION_TRACE(__func__); + + /* + * Sweep the list forwards turning things on. + */ + TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) { + if (rp->ap_state != ACPI_PWR_ON) + continue; /* not turning this one on */ + + /* we could cache this if we trusted it not to change under us */ + if ((status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur)) != AE_OK) { + DEBUG_PRINT(TRACE_OBJECTS, ("can't get status of %s - %d\n", + acpi_name(rp->ap_resource), status)); + continue; /* XXX is this correct? Always switch if in doubt? */ + } + + /* + * Switch if required. Note that we ignore the result of the switch + * effort; we don't know what to do if it fails, so checking wouldn't + * help much. + */ + if (cur != ACPI_PWR_ON) + AcpiEvaluateObject(rp->ap_resource, "_ON", NULL, NULL); + } + + /* + * Sweep the list backwards turning things off. + */ + TAILQ_FOREACH_REVERSE(rp, &acpi_powerresources, acpi_powerresource_list, ap_link) { + if (rp->ap_state != ACPI_PWR_OFF) + continue; /* not turning this one off */ + + /* we could cache this if we trusted it not to change under us */ + if ((status = acpi_EvaluateInteger(rp->ap_resource, "_STA", &cur)) != AE_OK) { + DEBUG_PRINT(TRACE_OBJECTS, ("can't get status of %s - %d\n", + acpi_name(rp->ap_resource), status)); + continue; /* XXX is this correct? Always switch if in doubt? */ + } + + /* + * Switch if required. Note that we ignore the result of the switch + * effort; we don't know what to do if it fails, so checking wouldn't + * help much. + */ + if (cur != ACPI_PWR_OFF) + AcpiEvaluateObject(rp->ap_resource, "_OFF", NULL, NULL); + } + return_ACPI_STATUS(AE_OK); +} + +/* + * Find a power resource's control structure. + */ +static struct acpi_powerresource * +acpi_pwr_find_resource(ACPI_HANDLE res) +{ + struct acpi_powerresource *rp; + + FUNCTION_TRACE(__func__); + + TAILQ_FOREACH(rp, &acpi_powerresources, ap_link) + if (rp->ap_resource == res) + break; + return_VALUE(rp); +} + +/* + * Find a power consumer's control structure. + */ +static struct acpi_powerconsumer * +acpi_pwr_find_consumer(ACPI_HANDLE consumer) +{ + struct acpi_powerconsumer *pc; + + FUNCTION_TRACE(__func__); + + TAILQ_FOREACH(pc, &acpi_powerconsumers, ac_link) + if (pc->ac_consumer == consumer) + break; + return_VALUE(pc); +} + diff --git a/sys/dev/acpica/acpi_thermal.c b/sys/dev/acpica/acpi_thermal.c index 7b3cd4e43ef0..d381b5dd2941 100644 --- a/sys/dev/acpica/acpi_thermal.c +++ b/sys/dev/acpica/acpi_thermal.c @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2000 Michael Smith + * Copyright (c) 2000, 2001 Michael Smith * Copyright (c) 2000 BSDi * All rights reserved. * @@ -31,6 +31,7 @@ #include #include #include +#include #include "acpi.h" @@ -45,16 +46,50 @@ MODULE_NAME("THERMAL") #define TZ_ZEROC 2732 #define TZ_KELVTOC(x) (((x) - TZ_ZEROC) / 10), (((x) - TZ_ZEROC) % 10) +#define TZ_NOTIFY_TEMPERATURE 0x80 +#define TZ_NOTIFY_DEVICES 0x81 +#define TZ_NOTIFY_LEVELS 0x82 + +#define TZ_POLLRATE (hz * 10) /* every ten seconds */ + +#define TZ_NUMLEVELS 10 /* defined by ACPI spec */ +struct acpi_tz_state { + int ac[TZ_NUMLEVELS]; + ACPI_BUFFER al[TZ_NUMLEVELS]; + int crt; + int hot; + ACPI_BUFFER psl; + int psv; + int tc1; + int tc2; + int tsp; + int tzp; +}; + + struct acpi_tz_softc { - device_t tz_dev; - ACPI_HANDLE tz_handle; - int tz_tmp; + device_t tz_dev; + ACPI_HANDLE tz_handle; + struct callout_handle tz_timeout; + int tz_current; +#define TZ_STATE_NONE 0 +#define TZ_STATE_PSV 1 +#define TZ_STATE_AC0 2 +#define TZ_STATE_HOT (TZ_STATE_AC0 + TZ_NUMLEVELS) +#define TZ_STATE_CRT (TZ_STATE_AC0 + TZ_NUMLEVELS + 1) + + struct acpi_tz_state tz_state; }; static int acpi_tz_probe(device_t dev); static int acpi_tz_attach(device_t dev); -static void acpi_tz_check_tripping_point(void *context); +static int acpi_tz_establish(struct acpi_tz_softc *sc); +static void acpi_tz_all_off(struct acpi_tz_softc *sc); +static void acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg); +static void acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg); +static void acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data); static void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context); +static void acpi_tz_timeout(void *arg); static device_method_t acpi_tz_methods[] = { /* Device interface */ @@ -73,25 +108,31 @@ static driver_t acpi_tz_driver = { devclass_t acpi_tz_devclass; DRIVER_MODULE(acpi_tz, acpi, acpi_tz_driver, acpi_tz_devclass, 0, 0); +/* + * Match an ACPI thermal zone. + */ static int acpi_tz_probe(device_t dev) { - FUNCTION_TRACE(__func__); + /* no FUNCTION_TRACE - too noisy */ if ((acpi_get_type(dev) == ACPI_TYPE_THERMAL) && !acpi_disabled("thermal")) { device_set_desc(dev, "thermal zone"); - return_VALUE(0); + return(-10); } - return_VALUE(ENXIO); + return(ENXIO); } +/* + * Attach to an ACPI thermal zone. + */ static int acpi_tz_attach(device_t dev) { struct acpi_tz_softc *sc; - struct acpi_softc *acpi_sc; + int error; FUNCTION_TRACE(__func__); @@ -99,17 +140,19 @@ acpi_tz_attach(device_t dev) sc->tz_dev = dev; sc->tz_handle = acpi_get_handle(dev); + /* + * Parse the current state of the thermal zone and build control + * structures. + */ + if ((error = acpi_tz_establish(sc)) != 0) + return_VALUE(error); + + /* + * Register for any Notify events sent to this zone. + */ AcpiInstallNotifyHandler(sc->tz_handle, ACPI_DEVICE_NOTIFY, acpi_tz_notify_handler, dev); - if (device_get_unit(dev) == 0) { - acpi_sc = acpi_device_get_parent_softc(dev); - SYSCTL_ADD_UINT(&acpi_sc->acpi_sysctl_ctx, - SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), - OID_AUTO, "temperature", CTLFLAG_RD, - &sc->tz_tmp, 0, ""); - } - /* * Don't bother evaluating/printing the temperature at this point; * on many systems it'll be bogus until the EC is running. @@ -117,43 +160,306 @@ acpi_tz_attach(device_t dev) return_VALUE(0); } -static void -acpi_tz_check_tripping_point(void *context) +/* + * Parse the current state of this thermal zone and set up to use it. + * + * Note that we may have previous state, which will have to be discarded. + */ +static int +acpi_tz_establish(struct acpi_tz_softc *sc) { - struct acpi_tz_softc *sc; - device_t dev = context; - ACPI_STATUS status; - int tp; + ACPI_OBJECT *obj; + int i; + char nbuf[8]; + + FUNCTION_TRACE(__func__); + + /* + * Power everything off and erase any existing state. + */ + acpi_tz_all_off(sc); + for (i = 0; i < TZ_NUMLEVELS; i++) + if (sc->tz_state.al[i].Pointer != NULL) + AcpiOsFree(sc->tz_state.al[i].Pointer); + if (sc->tz_state.psl.Pointer != NULL) + AcpiOsFree(sc->tz_state.psl.Pointer); + bzero(&sc->tz_state, sizeof(sc->tz_state)); + + /* kill the timeout (harmless if not running */ + untimeout(acpi_tz_timeout, sc, sc->tz_timeout); + + /* + * Evaluate thermal zone parameters. + */ + for (i = 0; i < TZ_NUMLEVELS; i++) { + sprintf(nbuf, "_AC%d", i); + acpi_tz_getparam(sc, nbuf, &sc->tz_state.ac[i]); + sprintf(nbuf, "_AL%d", i); + acpi_EvaluateIntoBuffer(sc->tz_handle, nbuf, NULL, &sc->tz_state.al[i]); + obj = (ACPI_OBJECT *)sc->tz_state.al[i].Pointer; + if (obj != NULL) { + /* should be a package containing a list of power objects */ + if (obj->Type != ACPI_TYPE_PACKAGE) { + device_printf(sc->tz_dev, "%s has unknown object type %d, rejecting\n", + nbuf, obj->Type); + return_VALUE(ENXIO); + } + } + } + acpi_tz_getparam(sc, "_CRT", &sc->tz_state.crt); + acpi_tz_getparam(sc, "_HOT", &sc->tz_state.hot); + acpi_EvaluateIntoBuffer(sc->tz_handle, "_PSL", NULL, &sc->tz_state.psl); + acpi_tz_getparam(sc, "_PSV", &sc->tz_state.psv); + acpi_tz_getparam(sc, "_TC1", &sc->tz_state.tc1); + acpi_tz_getparam(sc, "_TC2", &sc->tz_state.tc2); + acpi_tz_getparam(sc, "_TSP", &sc->tz_state.tsp); + acpi_tz_getparam(sc, "_TZP", &sc->tz_state.tzp); + + /* + * Power off everything that we've just been given. + */ + acpi_tz_all_off(sc); + + /* + * Do we need to poll the thermal zone? Ignore the suggested + * rate. + */ + if (sc->tz_state.tzp != 0) + sc->tz_timeout = timeout(acpi_tz_timeout, sc, TZ_POLLRATE); + + + return_VALUE(0); +} + +/* + * Evaluate the condition of a thermal zone, take appropriate actions. + */ +static void +acpi_tz_monitor(struct acpi_tz_softc *sc) +{ + int temp, new; + int i; FUNCTION_TRACE(__func__); - sc = device_get_softc(dev); - if ((status = acpi_EvaluateInteger(sc->tz_handle, "_TMP", &tp)) != AE_OK) { - device_printf(dev, "can't evaluate _TMP method - %s\n", acpi_strerror(status)); + /* + * Get the current temperature. + */ + if ((acpi_EvaluateInteger(sc->tz_handle, "_TMP", &temp)) != AE_OK) { + device_printf(sc->tz_dev, "error fetching current temperature\n"); + /* XXX disable zone? go to max cooling? */ return_VOID; } + + /* + * Work out what we ought to be doing right now. + */ + new = TZ_STATE_NONE; + if ((sc->tz_state.psv != -1) && (temp > sc->tz_state.psv)) + new = TZ_STATE_PSV; + for (i = 0; i < TZ_NUMLEVELS; i++) + if ((sc->tz_state.ac[i] != -1) && (temp > sc->tz_state.ac[i])) + new = TZ_STATE_AC0 + i; + if ((sc->tz_state.hot != -1) && (temp > sc->tz_state.hot)) + new = TZ_STATE_HOT; + if ((sc->tz_state.crt != -1) && (temp > sc->tz_state.crt)) + new = TZ_STATE_CRT; + + /* + * If our state has not changed, do nothing. + */ + if (new == sc->tz_current) + return_VOID; - sc->tz_tmp = (tp - TZ_ZEROC) / 10; - if (bootverbose) { - device_printf(dev, "%dC\n", sc->tz_tmp); + /* + * XXX if we're in a passive-cooling mode, revert to full-speed operation. + */ + if (sc->tz_current == TZ_STATE_PSV) { + /* XXX implement */ } + + /* + * If we're in an active-cooling mode, turn off the current cooler(s). + */ + if ((sc->tz_current >= TZ_STATE_AC0) && (sc->tz_current < (TZ_STATE_AC0 + TZ_NUMLEVELS))) + acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_state.al[sc->tz_current - TZ_STATE_AC0].Pointer, + acpi_tz_switch_cooler_off, sc); + + /* + * XXX If the new mode is passive-cooling, make appropriate adjustments. + */ + + /* + * If the new mode is an active-cooling mode, turn on the new cooler(s). + */ + if ((new >= TZ_STATE_AC0) && (new < (TZ_STATE_AC0 + TZ_NUMLEVELS))) + acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_state.al[new - TZ_STATE_AC0].Pointer, + acpi_tz_switch_cooler_on, sc); + + /* + * If we're _HOT or _CRT, shut down now! + */ + if ((new == TZ_STATE_HOT) || (new == TZ_STATE_CRT)) { + device_printf(sc->tz_dev, "WARNING - emergency thermal shutdown in progress.\n"); + shutdown_nice(RB_POWEROFF); + } + + /* gone to new state */ + sc->tz_current = new; + return_VOID; } -#define ACPI_TZ_STATUS_CHANGE 0x80 -#define ACPI_TZ_TRIPPOINT_CHANGE 0x81 +/* + * Turn off all the cooling devices. + */ +static void +acpi_tz_all_off(struct acpi_tz_softc *sc) +{ + int i; + + FUNCTION_TRACE(__func__); + + /* + * Scan all the _AL objects, and turn them all off. + */ + for (i = 0; i < TZ_NUMLEVELS; i++) { + if (sc->tz_state.al[i].Pointer == NULL) + continue; + acpi_ForeachPackageObject((ACPI_OBJECT *)sc->tz_state.al[i].Pointer, + acpi_tz_switch_cooler_off, sc); + } + + /* + * XXX revert any passive-cooling options. + */ + + sc->tz_current = TZ_STATE_NONE; + return_VOID; +} + +/* + * Given an object, verify that it's a reference to a device of some sort, + * and try to switch it off. + */ +static void +acpi_tz_switch_cooler_off(ACPI_OBJECT *obj, void *arg) +{ + struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; + ACPI_HANDLE cooler; + + FUNCTION_TRACE(__func__); + + switch(obj->Type) { + case ACPI_TYPE_STRING: + DEBUG_PRINT(TRACE_OBJECTS, ("called to turn %s off\n", obj->String.Pointer)); + + /* + * Find the handle for the device and turn it off. + * The String object here seems to contain a fully-qualified path, so we + * don't have to search for it in our parents. + * + * XXX This may not always be the case. + */ + if (AcpiGetHandle(obj->String.Pointer, NULL, &cooler) == AE_OK) + acpi_pwr_switch_consumer(cooler, ACPI_STATE_D3); + break; + + default: + DEBUG_PRINT(TRACE_OBJECTS, ("called to handle unsupported object type %d\n", + obj->Type)); + break; + } + return_VOID; +} + +/* + * Given an object, verify that it's a reference to a device of some sort, + * and try to switch it on. + * + * XXX replication of off/on function code is bad, mmmkay? + */ +static void +acpi_tz_switch_cooler_on(ACPI_OBJECT *obj, void *arg) +{ + struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; + ACPI_HANDLE cooler, parent; + + FUNCTION_TRACE(__func__); + + switch(obj->Type) { + case ACPI_TYPE_STRING: + DEBUG_PRINT(TRACE_OBJECTS, ("called to turn %s off\n", obj->String.Pointer)); + + /* find the handle for the device and turn it off */ + if (acpi_GetHandleInScope(sc->tz_handle, obj->String.Pointer, &cooler) == AE_OK) + acpi_pwr_switch_consumer(cooler, ACPI_STATE_D0); + break; + + default: + DEBUG_PRINT(TRACE_OBJECTS, ("called to handle unsupported object type %d\n", + obj->Type)); + break; + } + return_VOID; +} + +/* + * Read/debug-print a parameter, default it to -1. + */ +static void +acpi_tz_getparam(struct acpi_tz_softc *sc, char *node, int *data) +{ + + FUNCTION_TRACE(__func__); + + if (acpi_EvaluateInteger(sc->tz_handle, node, data) != AE_OK) { + *data = -1; + } else { + DEBUG_PRINT(TRACE_VALUES, ("%s.%s = %d\n", acpi_name(sc->tz_handle), + node, *data)); + } + return_VOID; +} + +/* + * Respond to a Notify event sent to the zone. + */ static void acpi_tz_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) { + struct acpi_tz_softc *sc = (struct acpi_tz_softc *)context; + FUNCTION_TRACE(__func__); - switch(notify){ - case ACPI_TZ_STATUS_CHANGE: - case ACPI_TZ_TRIPPOINT_CHANGE: - /*Check trip point*/ - AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_tz_check_tripping_point, context); - break; + switch(notify) { + case TZ_NOTIFY_TEMPERATURE: + acpi_tz_monitor(sc); /* temperature change occurred */ + break; + case TZ_NOTIFY_DEVICES: + case TZ_NOTIFY_LEVELS: + acpi_tz_establish(sc); /* zone devices/setpoints changed */ + break; + default: + device_printf(sc->tz_dev, "unknown Notify event 0x%x\n", notify); + break; } return_VOID; } +/* + * Poll the thermal zone. + */ +static void +acpi_tz_timeout(void *arg) +{ + struct acpi_tz_softc *sc = (struct acpi_tz_softc *)arg; + + /* check temperature, take action */ + acpi_tz_monitor(sc); + + /* XXX passive cooling actions? */ + + /* re-register ourself */ + sc->tz_timeout = timeout(acpi_tz_timeout, sc, TZ_POLLRATE); +} diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h index 4e3930675681..66c61d4987ab 100644 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -164,16 +164,23 @@ extern void acpi_EnterDebugger(void); #define STEP(x) #endif +extern BOOLEAN acpi_DeviceIsPresent(device_t dev); extern BOOLEAN acpi_MatchHid(device_t dev, char *hid); +extern ACPI_STATUS acpi_GetHandleInScope(ACPI_HANDLE parent, char *path, ACPI_HANDLE *result); +extern ACPI_BUFFER *acpi_AllocBuffer(int size); extern ACPI_STATUS acpi_GetIntoBuffer(ACPI_HANDLE handle, ACPI_STATUS (*func)(ACPI_HANDLE, ACPI_BUFFER *), ACPI_BUFFER *buf); -extern ACPI_BUFFER *acpi_AllocBuffer(int size); +extern ACPI_STATUS acpi_EvaluateIntoBuffer(ACPI_HANDLE object, ACPI_STRING pathname, + ACPI_OBJECT_LIST *params, ACPI_BUFFER *buf); +extern ACPI_STATUS acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int *number); +extern ACPI_STATUS acpi_ForeachPackageObject(ACPI_OBJECT *obj, + void (* func)(ACPI_OBJECT *comp, void *arg), + void *arg); + extern ACPI_STATUS acpi_SetSleepState(struct acpi_softc *sc, int state); extern ACPI_STATUS acpi_Enable(struct acpi_softc *sc); extern ACPI_STATUS acpi_Disable(struct acpi_softc *sc); -extern BOOLEAN acpi_DeviceIsPresent(device_t dev); -extern ACPI_STATUS acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int *number); struct acpi_parse_resource_set { void (* set_init)(device_t dev, void **context); @@ -214,6 +221,11 @@ typedef void (*acpi_event_handler_t) __P((void *, int)); EVENTHANDLER_DECLARE(acpi_sleep_event, acpi_event_handler_t); EVENTHANDLER_DECLARE(acpi_wakeup_event, acpi_event_handler_t); +/* + * Device power control. + */ +extern ACPI_STATUS acpi_pwr_switch_consumer(ACPI_HANDLE consumer, int state); + /* * Misc. */