acpi.c revision 79282
1187692Snwhitehorn/*-
2187692Snwhitehorn * Copyright (c) 2000 Takanori Watanabe <takawata@jp.freebsd.org>
3187692Snwhitehorn * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
4187692Snwhitehorn * Copyright (c) 2000, 2001 Michael Smith
5187692Snwhitehorn * Copyright (c) 2000 BSDi
6187692Snwhitehorn * All rights reserved.
7187692Snwhitehorn *
8187692Snwhitehorn * Redistribution and use in source and binary forms, with or without
9187692Snwhitehorn * modification, are permitted provided that the following conditions
10187692Snwhitehorn * are met:
11187692Snwhitehorn * 1. Redistributions of source code must retain the above copyright
12187692Snwhitehorn *    notice, this list of conditions and the following disclaimer.
13187692Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
14187692Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
15187692Snwhitehorn *    documentation and/or other materials provided with the distribution.
16187692Snwhitehorn *
17187692Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18187692Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19187692Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20187692Snwhitehorn * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21187692Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22187692Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23187692Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24187692Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25187692Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26187692Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27187692Snwhitehorn * SUCH DAMAGE.
28187692Snwhitehorn *
29187692Snwhitehorn *	$FreeBSD: head/sys/dev/acpica/acpi.c 79282 2001-07-05 07:14:30Z msmith $
30187692Snwhitehorn */
31187692Snwhitehorn
32187692Snwhitehorn#include "opt_acpi.h"
33187692Snwhitehorn#include <sys/param.h>
34187692Snwhitehorn#include <sys/kernel.h>
35187692Snwhitehorn#include <sys/proc.h>
36187692Snwhitehorn#include <sys/lock.h>
37187692Snwhitehorn#include <sys/malloc.h>
38187692Snwhitehorn#include <sys/mutex.h>
39187692Snwhitehorn#include <sys/bus.h>
40187692Snwhitehorn#include <sys/conf.h>
41187692Snwhitehorn#include <sys/ioccom.h>
42187692Snwhitehorn#include <sys/reboot.h>
43187692Snwhitehorn#include <sys/sysctl.h>
44187692Snwhitehorn#include <sys/ctype.h>
45187692Snwhitehorn
46187692Snwhitehorn#include <machine/clock.h>
47187692Snwhitehorn
48187692Snwhitehorn#include <machine/resource.h>
49187692Snwhitehorn
50187692Snwhitehorn#include "acpi.h"
51187692Snwhitehorn
52187692Snwhitehorn#include <dev/acpica/acpivar.h>
53187692Snwhitehorn#include <dev/acpica/acpiio.h>
54187692Snwhitehorn
55187692SnwhitehornMALLOC_DEFINE(M_ACPIDEV, "acpidev", "ACPI devices");
56187692Snwhitehorn
57187692Snwhitehorn/*
58187692Snwhitehorn * Hooks for the ACPI CA debugging infrastructure
59187692Snwhitehorn */
60187692Snwhitehorn#define _COMPONENT	ACPI_BUS
61187692SnwhitehornMODULE_NAME("ACPI")
62187692Snwhitehorn
63187692Snwhitehorn/*
64187692Snwhitehorn * Character device
65187692Snwhitehorn */
66187692Snwhitehorn
67187692Snwhitehornstatic d_open_t		acpiopen;
68187692Snwhitehornstatic d_close_t	acpiclose;
69187692Snwhitehornstatic d_ioctl_t	acpiioctl;
70187692Snwhitehorn
71187692Snwhitehorn#define CDEV_MAJOR 152
72187692Snwhitehornstatic struct cdevsw acpi_cdevsw = {
73187692Snwhitehorn    acpiopen,
74187692Snwhitehorn    acpiclose,
75193640Sariff    noread,
76193640Sariff    nowrite,
77193640Sariff    acpiioctl,
78193640Sariff    nopoll,
79193640Sariff    nommap,
80187692Snwhitehorn    nostrategy,
81187692Snwhitehorn    "acpi",
82193640Sariff    CDEV_MAJOR,
83187692Snwhitehorn    nodump,
84187692Snwhitehorn    nopsize,
85187692Snwhitehorn    0
86187692Snwhitehorn};
87187692Snwhitehorn
88187692Snwhitehornstatic const char* sleep_state_names[] = {
89187692Snwhitehorn    "S0", "S1", "S2", "S3", "S4", "S5", "S4B" };
90187692Snwhitehorn
91187692Snwhitehorn/* this has to be static, as the softc is gone when we need it */
92187692Snwhitehornstatic int acpi_off_state = ACPI_STATE_S5;
93187692Snwhitehorn
94187692Snwhitehornstruct mtx	acpi_mutex;
95187692Snwhitehorn
96187692Snwhitehornstatic void	acpi_identify(driver_t *driver, device_t parent);
97187692Snwhitehornstatic int	acpi_probe(device_t dev);
98187692Snwhitehornstatic int	acpi_attach(device_t dev);
99187692Snwhitehornstatic device_t	acpi_add_child(device_t bus, int order, const char *name, int unit);
100187692Snwhitehornstatic int	acpi_print_resources(struct resource_list *rl, const char *name, int type,
101187692Snwhitehorn				     const char *format);
102187692Snwhitehornstatic int	acpi_print_child(device_t bus, device_t child);
103187692Snwhitehornstatic int	acpi_read_ivar(device_t dev, device_t child, int index, uintptr_t *result);
104187692Snwhitehornstatic int	acpi_write_ivar(device_t dev, device_t child, int index, uintptr_t value);
105187692Snwhitehornstatic int	acpi_set_resource(device_t dev, device_t child, int type, int rid, u_long start,
106187692Snwhitehorn				  u_long count);
107187692Snwhitehornstatic int	acpi_get_resource(device_t dev, device_t child, int type, int rid, u_long *startp,
108187692Snwhitehorn				  u_long *countp);
109187692Snwhitehornstatic struct resource *acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
110187692Snwhitehorn					    u_long start, u_long end, u_long count, u_int flags);
111187692Snwhitehornstatic int	acpi_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r);
112187692Snwhitehorn
113187692Snwhitehornstatic void	acpi_probe_children(device_t bus);
114187692Snwhitehornstatic ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status);
115187692Snwhitehorn
116187692Snwhitehornstatic void	acpi_shutdown_pre_sync(void *arg, int howto);
117187692Snwhitehornstatic void	acpi_shutdown_final(void *arg, int howto);
118187692Snwhitehorn
119187717Snwhitehornstatic void	acpi_enable_fixed_events(struct acpi_softc *sc);
120187692Snwhitehorn
121187692Snwhitehornstatic void	acpi_system_eventhandler_sleep(void *arg, int state);
122187692Snwhitehornstatic void	acpi_system_eventhandler_wakeup(void *arg, int state);
123187692Snwhitehornstatic int	acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS);
124187692Snwhitehorn
125187692Snwhitehornstatic device_method_t acpi_methods[] = {
126187692Snwhitehorn    /* Device interface */
127187692Snwhitehorn    DEVMETHOD(device_identify,		acpi_identify),
128187692Snwhitehorn    DEVMETHOD(device_probe,		acpi_probe),
129187692Snwhitehorn    DEVMETHOD(device_attach,		acpi_attach),
130187692Snwhitehorn    DEVMETHOD(device_shutdown,		bus_generic_shutdown),
131187692Snwhitehorn    DEVMETHOD(device_suspend,		bus_generic_suspend),
132187692Snwhitehorn    DEVMETHOD(device_resume,		bus_generic_resume),
133187692Snwhitehorn
134187692Snwhitehorn    /* Bus interface */
135187692Snwhitehorn    DEVMETHOD(bus_add_child,		acpi_add_child),
136187692Snwhitehorn    DEVMETHOD(bus_print_child,		acpi_print_child),
137187692Snwhitehorn    DEVMETHOD(bus_read_ivar,		acpi_read_ivar),
138187692Snwhitehorn    DEVMETHOD(bus_write_ivar,		acpi_write_ivar),
139187692Snwhitehorn    DEVMETHOD(bus_set_resource,		acpi_set_resource),
140187692Snwhitehorn    DEVMETHOD(bus_get_resource,		acpi_get_resource),
141187692Snwhitehorn    DEVMETHOD(bus_alloc_resource,	acpi_alloc_resource),
142187692Snwhitehorn    DEVMETHOD(bus_release_resource,	acpi_release_resource),
143187692Snwhitehorn    DEVMETHOD(bus_driver_added,		bus_generic_driver_added),
144187692Snwhitehorn    DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
145187692Snwhitehorn    DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
146187692Snwhitehorn    DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
147187692Snwhitehorn    DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
148187692Snwhitehorn
149187692Snwhitehorn    {0, 0}
150187692Snwhitehorn};
151187692Snwhitehorn
152187692Snwhitehornstatic driver_t acpi_driver = {
153187692Snwhitehorn    "acpi",
154187692Snwhitehorn    acpi_methods,
155187692Snwhitehorn    sizeof(struct acpi_softc),
156187692Snwhitehorn};
157187692Snwhitehorn
158187692Snwhitehorndevclass_t acpi_devclass;
159187692SnwhitehornDRIVER_MODULE(acpi, nexus, acpi_driver, acpi_devclass, 0, 0);
160187692Snwhitehorn
161223554SnwhitehornSYSCTL_INT(_debug, OID_AUTO, acpi_debug_layer, CTLFLAG_RW, &AcpiDbgLayer, 0, "");
162223554SnwhitehornSYSCTL_INT(_debug, OID_AUTO, acpi_debug_level, CTLFLAG_RW, &AcpiDbgLevel, 0, "");
163187692Snwhitehorn
164187692Snwhitehorn/*
165187692Snwhitehorn * Detect ACPI, perform early initialisation
166187692Snwhitehorn */
167187692Snwhitehornstatic void
168187692Snwhitehornacpi_identify(driver_t *driver, device_t parent)
169187692Snwhitehorn{
170223554Snwhitehorn    device_t			child;
171223554Snwhitehorn    ACPI_PHYSICAL_ADDRESS	rsdp;
172223554Snwhitehorn    int				error;
173223554Snwhitehorn#ifdef ENABLE_DEBUGGER
174223554Snwhitehorn    char			*debugpoint = getenv("debug.acpi.debugger");
175223554Snwhitehorn#endif
176223554Snwhitehorn
177223554Snwhitehorn    FUNCTION_TRACE(__func__);
178223554Snwhitehorn
179223554Snwhitehorn    if(!cold){
180187692Snwhitehorn	    printf("Don't load this driver from userland!!\n");
181187692Snwhitehorn	    return ;
182187692Snwhitehorn    }
183187692Snwhitehorn
184187692Snwhitehorn    /*
185187692Snwhitehorn     * Make sure we're not being doubly invoked.
186187692Snwhitehorn     */
187187692Snwhitehorn    if (device_find_child(parent, "acpi", 0) != NULL)
188187692Snwhitehorn	return_VOID;
189187692Snwhitehorn
190187692Snwhitehorn    /* initialise the ACPI mutex */
191187717Snwhitehorn    mtx_init(&acpi_mutex, "ACPI global lock", MTX_DEF);
192187692Snwhitehorn
193187692Snwhitehorn    /*
194187692Snwhitehorn     * Start up the ACPI CA subsystem.
195187692Snwhitehorn     */
196187717Snwhitehorn#ifdef ENABLE_DEBUGGER
197187717Snwhitehorn    if (debugpoint && !strcmp(debugpoint, "init"))
198187692Snwhitehorn	acpi_EnterDebugger();
199188259Snwhitehorn#endif
200187692Snwhitehorn    if ((error = AcpiInitializeSubsystem()) != AE_OK) {
201187692Snwhitehorn	printf("ACPI: initialisation failed: %s\n", acpi_strerror(error));
202187692Snwhitehorn	return_VOID;
203187692Snwhitehorn    }
204187692Snwhitehorn#ifdef ENABLE_DEBUGGER
205187692Snwhitehorn    if (debugpoint && !strcmp(debugpoint, "tables"))
206187692Snwhitehorn	acpi_EnterDebugger();
207187692Snwhitehorn#endif
208187692Snwhitehorn    if (((error = AcpiFindRootPointer(&rsdp)) != AE_OK) ||
209187692Snwhitehorn	((error = AcpiLoadTables(rsdp)) != AE_OK)) {
210187692Snwhitehorn	printf("ACPI: table load failed: %s\n", acpi_strerror(error));
211187692Snwhitehorn	return_VOID;
212187692Snwhitehorn    }
213187692Snwhitehorn
214187692Snwhitehorn    /*
215187692Snwhitehorn     * Attach the actual ACPI device.
216187692Snwhitehorn     */
217187692Snwhitehorn    if ((child = BUS_ADD_CHILD(parent, 0, "acpi", 0)) == NULL) {
218187692Snwhitehorn	    device_printf(parent, "ACPI: could not attach\n");
219187692Snwhitehorn	    return_VOID;
220187692Snwhitehorn    }
221187692Snwhitehorn}
222187692Snwhitehorn
223187692Snwhitehorn/*
224187692Snwhitehorn * Fetch some descriptive data from ACPI to put in our attach message
225187692Snwhitehorn */
226187692Snwhitehornstatic int
227187692Snwhitehornacpi_probe(device_t dev)
228187692Snwhitehorn{
229187692Snwhitehorn    ACPI_TABLE_HEADER	th;
230187692Snwhitehorn    char		buf[20];
231187692Snwhitehorn    ACPI_STATUS		status;
232187692Snwhitehorn    int			error;
233187692Snwhitehorn
234187692Snwhitehorn    FUNCTION_TRACE(__func__);
235187692Snwhitehorn    ACPI_LOCK;
236188259Snwhitehorn
237188259Snwhitehorn    if ((status = AcpiGetTableHeader(ACPI_TABLE_XSDT, 1, &th)) != AE_OK) {
238187692Snwhitehorn	device_printf(dev, "couldn't get XSDT header: %s\n", acpi_strerror(status));
239187692Snwhitehorn	error = ENXIO;
240187692Snwhitehorn    } else {
241187692Snwhitehorn	sprintf(buf, "%.6s %.8s", th.OemId, th.OemTableId);
242187692Snwhitehorn	device_set_desc_copy(dev, buf);
243187692Snwhitehorn	error = 0;
244187692Snwhitehorn    }
245187692Snwhitehorn    ACPI_UNLOCK;
246187692Snwhitehorn    return_VALUE(error);
247187692Snwhitehorn}
248187692Snwhitehorn
249187692Snwhitehornstatic int
250187692Snwhitehornacpi_attach(device_t dev)
251187692Snwhitehorn{
252187692Snwhitehorn    struct acpi_softc	*sc;
253188259Snwhitehorn    ACPI_STATUS		status;
254187692Snwhitehorn    int			error;
255187692Snwhitehorn#ifdef ENABLE_DEBUGGER
256187692Snwhitehorn    char		*debugpoint = getenv("debug.acpi.debugger");
257187692Snwhitehorn#endif
258188259Snwhitehorn
259187692Snwhitehorn    FUNCTION_TRACE(__func__);
260187692Snwhitehorn    ACPI_LOCK;
261187692Snwhitehorn    sc = device_get_softc(dev);
262187692Snwhitehorn    bzero(sc, sizeof(*sc));
263187692Snwhitehorn    sc->acpi_dev = dev;
264187692Snwhitehorn
265187692Snwhitehorn#ifdef ENABLE_DEBUGGER
266187692Snwhitehorn    if (debugpoint && !strcmp(debugpoint, "spaces"))
267187692Snwhitehorn	acpi_EnterDebugger();
268187692Snwhitehorn#endif
269187692Snwhitehorn
270187692Snwhitehorn    /*
271187692Snwhitehorn     * Install the default address space handlers.
272187692Snwhitehorn     */
273187692Snwhitehorn    error = ENXIO;
274187692Snwhitehorn    if ((status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
275187692Snwhitehorn						ACPI_ADR_SPACE_SYSTEM_MEMORY,
276187692Snwhitehorn						ACPI_DEFAULT_HANDLER,
277187692Snwhitehorn						NULL, NULL)) != AE_OK) {
278187692Snwhitehorn	device_printf(dev, "could not initialise SystemMemory handler: %s\n", acpi_strerror(status));
279187692Snwhitehorn	goto out;
280187692Snwhitehorn    }
281187692Snwhitehorn    if ((status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
282187692Snwhitehorn						ACPI_ADR_SPACE_SYSTEM_IO,
283187692Snwhitehorn						ACPI_DEFAULT_HANDLER,
284187692Snwhitehorn						NULL, NULL)) != AE_OK) {
285187692Snwhitehorn	device_printf(dev, "could not initialise SystemIO handler: %s\n", acpi_strerror(status));
286187692Snwhitehorn	goto out;
287187692Snwhitehorn    }
288187692Snwhitehorn    if ((status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
289187692Snwhitehorn						ACPI_ADR_SPACE_PCI_CONFIG,
290187692Snwhitehorn						ACPI_DEFAULT_HANDLER,
291187692Snwhitehorn						NULL, NULL)) != AE_OK) {
292187692Snwhitehorn	device_printf(dev, "could not initialise PciConfig handler: %s\n", acpi_strerror(status));
293187692Snwhitehorn	goto out;
294187692Snwhitehorn    }
295187692Snwhitehorn
296187692Snwhitehorn    /*
297187692Snwhitehorn     * Bring ACPI fully online.
298187692Snwhitehorn     *
299187692Snwhitehorn     * Note that we request that device _STA and _INI methods not be run (ACPI_NO_DEVICE_INIT)
300187692Snwhitehorn     * and the final object initialisation pass be skipped (ACPI_NO_OBJECT_INIT).
301187692Snwhitehorn     *
302187692Snwhitehorn     * XXX We need to arrange for the object init pass after we have attached all our
303187692Snwhitehorn     *     child devices.
304187692Snwhitehorn     */
305187692Snwhitehorn#ifdef ENABLE_DEBUGGER
306187692Snwhitehorn    if (debugpoint && !strcmp(debugpoint, "enable"))
307187692Snwhitehorn	acpi_EnterDebugger();
308187692Snwhitehorn#endif
309187692Snwhitehorn    if ((status = AcpiEnableSubsystem(ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT)) != AE_OK) {
310187692Snwhitehorn	device_printf(dev, "could not enable ACPI: %s\n", acpi_strerror(status));
311187692Snwhitehorn	goto out;
312187692Snwhitehorn    }
313187692Snwhitehorn
314187692Snwhitehorn    /*
315187692Snwhitehorn     * Setup our sysctl tree.
316187692Snwhitehorn     *
317187692Snwhitehorn     * XXX: This doesn't check to make sure that none of these fail.
318187692Snwhitehorn     */
319187692Snwhitehorn    sysctl_ctx_init(&sc->acpi_sysctl_ctx);
320187692Snwhitehorn    sc->acpi_sysctl_tree = SYSCTL_ADD_NODE(&sc->acpi_sysctl_ctx,
321187692Snwhitehorn			       SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
322187692Snwhitehorn			       device_get_name(dev), CTLFLAG_RD, 0, "");
323187692Snwhitehorn    SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
324187692Snwhitehorn	OID_AUTO, "power_button_state", CTLTYPE_STRING | CTLFLAG_RW,
325187692Snwhitehorn	&sc->acpi_power_button_sx, 0, acpi_sleep_state_sysctl, "A", "");
326187692Snwhitehorn    SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
327187692Snwhitehorn	OID_AUTO, "sleep_button_state", CTLTYPE_STRING | CTLFLAG_RW,
328187692Snwhitehorn	&sc->acpi_sleep_button_sx, 0, acpi_sleep_state_sysctl, "A", "");
329187692Snwhitehorn    SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
330187692Snwhitehorn	OID_AUTO, "lid_switch_state", CTLTYPE_STRING | CTLFLAG_RW,
331187692Snwhitehorn	&sc->acpi_lid_switch_sx, 0, acpi_sleep_state_sysctl, "A", "");
332187692Snwhitehorn
333187692Snwhitehorn    /*
334187692Snwhitehorn     * Dispatch the default sleep state to devices.
335187692Snwhitehorn     * TBD: should be configured from userland policy manager.
336187692Snwhitehorn     */
337187692Snwhitehorn    sc->acpi_power_button_sx = ACPI_POWER_BUTTON_DEFAULT_SX;
338187692Snwhitehorn    sc->acpi_sleep_button_sx = ACPI_SLEEP_BUTTON_DEFAULT_SX;
339187692Snwhitehorn    sc->acpi_lid_switch_sx = ACPI_LID_SWITCH_DEFAULT_SX;
340187692Snwhitehorn
341187692Snwhitehorn    acpi_enable_fixed_events(sc);
342187692Snwhitehorn
343187692Snwhitehorn    /*
344187692Snwhitehorn     * Scan the namespace and attach/initialise children.
345187692Snwhitehorn     */
346187692Snwhitehorn#ifdef ENABLE_DEBUGGER
347187692Snwhitehorn    if (debugpoint && !strcmp(debugpoint, "probe"))
348187692Snwhitehorn	acpi_EnterDebugger();
349187692Snwhitehorn#endif
350187692Snwhitehorn    if (!acpi_disabled("bus"))
351187692Snwhitehorn	acpi_probe_children(dev);
352187692Snwhitehorn
353187692Snwhitehorn    /*
354187692Snwhitehorn     * Register our shutdown handlers
355187692Snwhitehorn     */
356187692Snwhitehorn    EVENTHANDLER_REGISTER(shutdown_pre_sync, acpi_shutdown_pre_sync, sc, SHUTDOWN_PRI_LAST);
357187692Snwhitehorn    EVENTHANDLER_REGISTER(shutdown_final, acpi_shutdown_final, sc, SHUTDOWN_PRI_LAST);
358187692Snwhitehorn
359187692Snwhitehorn    /*
360187692Snwhitehorn     * Register our acpi event handlers.
361187692Snwhitehorn     * XXX should be configurable eg. via userland policy manager.
362187692Snwhitehorn     */
363187692Snwhitehorn    EVENTHANDLER_REGISTER(acpi_sleep_event, acpi_system_eventhandler_sleep, sc, ACPI_EVENT_PRI_LAST);
364187692Snwhitehorn    EVENTHANDLER_REGISTER(acpi_wakeup_event, acpi_system_eventhandler_wakeup, sc, ACPI_EVENT_PRI_LAST);
365187692Snwhitehorn
366187692Snwhitehorn    /*
367187692Snwhitehorn     * Flag our initial states.
368187692Snwhitehorn     */
369187692Snwhitehorn    sc->acpi_enabled = 1;
370187692Snwhitehorn    sc->acpi_sstate = ACPI_STATE_S0;
371187692Snwhitehorn
372187692Snwhitehorn    /*
373187692Snwhitehorn     * Create the control device
374187692Snwhitehorn     */
375187692Snwhitehorn    sc->acpi_dev_t = make_dev(&acpi_cdevsw, 0, 0, 5, 0660, "acpi");
376187692Snwhitehorn    sc->acpi_dev_t->si_drv1 = sc;
377187692Snwhitehorn
378187692Snwhitehorn#ifdef ENABLE_DEBUGGER
379187692Snwhitehorn    if (debugpoint && !strcmp(debugpoint, "running"))
380187692Snwhitehorn	acpi_EnterDebugger();
381187692Snwhitehorn#endif
382187692Snwhitehorn    error = 0;
383187692Snwhitehorn
384187692Snwhitehorn out:
385187692Snwhitehorn    ACPI_UNLOCK;
386187692Snwhitehorn    return_VALUE(error);
387187692Snwhitehorn}
388187692Snwhitehorn
389187692Snwhitehorn/*
390187692Snwhitehorn * Handle a new device being added
391187692Snwhitehorn */
392187692Snwhitehornstatic device_t
393187692Snwhitehornacpi_add_child(device_t bus, int order, const char *name, int unit)
394187692Snwhitehorn{
395187692Snwhitehorn    struct acpi_device	*ad;
396187692Snwhitehorn    device_t		child;
397187692Snwhitehorn
398187692Snwhitehorn    if ((ad = malloc(sizeof(*ad), M_ACPIDEV, M_NOWAIT)) == NULL)
399187692Snwhitehorn	return(NULL);
400187692Snwhitehorn    bzero(ad, sizeof(*ad));
401187692Snwhitehorn
402187692Snwhitehorn    resource_list_init(&ad->ad_rl);
403187692Snwhitehorn
404187692Snwhitehorn    child = device_add_child_ordered(bus, order, name, unit);
405187692Snwhitehorn    if (child != NULL)
406187692Snwhitehorn	device_set_ivars(child, ad);
407187692Snwhitehorn    return(child);
408187692Snwhitehorn}
409187692Snwhitehorn
410187692Snwhitehorn/*
411187692Snwhitehorn * Print child device resource usage
412187692Snwhitehorn */
413187692Snwhitehornstatic int
414187692Snwhitehornacpi_print_resources(struct resource_list *rl, const char *name, int type, const char *format)
415187692Snwhitehorn{
416187692Snwhitehorn    struct resource_list_entry	*rle;
417187692Snwhitehorn    int				printed, retval;
418187692Snwhitehorn
419187692Snwhitehorn    printed = 0;
420187692Snwhitehorn    retval = 0;
421187692Snwhitehorn
422187692Snwhitehorn    if (!SLIST_FIRST(rl))
423187692Snwhitehorn	return(0);
424187692Snwhitehorn
425187692Snwhitehorn    /* Yes, this is kinda cheating */
426187692Snwhitehorn    SLIST_FOREACH(rle, rl, link) {
427187692Snwhitehorn	if (rle->type == type) {
428187692Snwhitehorn	    if (printed == 0)
429187692Snwhitehorn		retval += printf(" %s ", name);
430187692Snwhitehorn	    else if (printed > 0)
431187692Snwhitehorn		retval += printf(",");
432187692Snwhitehorn	    printed++;
433187692Snwhitehorn	    retval += printf(format, rle->start);
434187692Snwhitehorn	    if (rle->count > 1) {
435187692Snwhitehorn		retval += printf("-");
436187692Snwhitehorn		retval += printf(format, rle->start +
437187692Snwhitehorn				 rle->count - 1);
438187692Snwhitehorn	    }
439187692Snwhitehorn	}
440187692Snwhitehorn    }
441187692Snwhitehorn    return(retval);
442187692Snwhitehorn}
443187692Snwhitehorn
444187692Snwhitehornstatic int
445187692Snwhitehornacpi_print_child(device_t bus, device_t child)
446187692Snwhitehorn{
447187692Snwhitehorn    struct acpi_device		*adev = device_get_ivars(child);
448187692Snwhitehorn    struct resource_list	*rl = &adev->ad_rl;
449187692Snwhitehorn    int retval = 0;
450187692Snwhitehorn
451187692Snwhitehorn    retval += bus_print_child_header(bus, child);
452187692Snwhitehorn    retval += acpi_print_resources(rl, "port",  SYS_RES_IOPORT, "%#lx");
453187692Snwhitehorn    retval += acpi_print_resources(rl, "iomem", SYS_RES_MEMORY, "%#lx");
454187692Snwhitehorn    retval += acpi_print_resources(rl, "irq",   SYS_RES_IRQ,    "%ld");
455187692Snwhitehorn    retval += bus_print_child_footer(bus, child);
456187692Snwhitehorn
457187692Snwhitehorn    return(retval);
458187692Snwhitehorn}
459187692Snwhitehorn
460187692Snwhitehorn
461187692Snwhitehorn/*
462187692Snwhitehorn * Handle per-device ivars
463187692Snwhitehorn */
464187692Snwhitehornstatic int
465187692Snwhitehornacpi_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
466187692Snwhitehorn{
467187692Snwhitehorn    struct acpi_device	*ad;
468187692Snwhitehorn
469187692Snwhitehorn    if ((ad = device_get_ivars(child)) == NULL) {
470187692Snwhitehorn	printf("device has no ivars\n");
471187692Snwhitehorn	return(ENOENT);
472187692Snwhitehorn    }
473187692Snwhitehorn
474187692Snwhitehorn    switch(index) {
475187692Snwhitehorn	/* ACPI ivars */
476187692Snwhitehorn    case ACPI_IVAR_HANDLE:
477187692Snwhitehorn	*(ACPI_HANDLE *)result = ad->ad_handle;
478187692Snwhitehorn	break;
479187692Snwhitehorn    case ACPI_IVAR_MAGIC:
480187692Snwhitehorn	*(int *)result = ad->ad_magic;
481187692Snwhitehorn	break;
482187692Snwhitehorn    case ACPI_IVAR_PRIVATE:
483187692Snwhitehorn	*(void **)result = ad->ad_private;
484187692Snwhitehorn	break;
485187692Snwhitehorn
486187692Snwhitehorn    default:
487187692Snwhitehorn	panic("bad ivar read request (%d)\n", index);
488187692Snwhitehorn	return(ENOENT);
489187692Snwhitehorn    }
490187692Snwhitehorn    return(0);
491187692Snwhitehorn}
492187692Snwhitehorn
493187692Snwhitehornstatic int
494187692Snwhitehornacpi_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
495187692Snwhitehorn{
496187692Snwhitehorn    struct acpi_device	*ad;
497187692Snwhitehorn
498187692Snwhitehorn    if ((ad = device_get_ivars(child)) == NULL) {
499187692Snwhitehorn	printf("device has no ivars\n");
500187692Snwhitehorn	return(ENOENT);
501187692Snwhitehorn    }
502187692Snwhitehorn
503187692Snwhitehorn    switch(index) {
504187692Snwhitehorn	/* ACPI ivars */
505187692Snwhitehorn    case ACPI_IVAR_HANDLE:
506187692Snwhitehorn	ad->ad_handle = (ACPI_HANDLE)value;
507187692Snwhitehorn	break;
508187692Snwhitehorn    case ACPI_IVAR_MAGIC:
509187692Snwhitehorn	ad->ad_magic = (int )value;
510187692Snwhitehorn	break;
511187692Snwhitehorn    case ACPI_IVAR_PRIVATE:
512187692Snwhitehorn	ad->ad_private = (void *)value;
513187692Snwhitehorn	break;
514187692Snwhitehorn
515187692Snwhitehorn    default:
516187692Snwhitehorn	panic("bad ivar write request (%d)\n", index);
517187692Snwhitehorn	return(ENOENT);
518187692Snwhitehorn    }
519187692Snwhitehorn    return(0);
520187692Snwhitehorn}
521187692Snwhitehorn
522187692Snwhitehorn/*
523187692Snwhitehorn * Handle child resource allocation/removal
524187692Snwhitehorn */
525187692Snwhitehornstatic int
526187692Snwhitehornacpi_set_resource(device_t dev, device_t child, int type, int rid, u_long start, u_long count)
527187692Snwhitehorn{
528187692Snwhitehorn    struct acpi_device		*ad = device_get_ivars(child);
529187692Snwhitehorn    struct resource_list	*rl = &ad->ad_rl;
530187692Snwhitehorn
531187692Snwhitehorn    resource_list_add(rl, type, rid, start, start + count -1, count);
532187692Snwhitehorn
533187692Snwhitehorn    return(0);
534187692Snwhitehorn}
535187692Snwhitehorn
536187692Snwhitehornstatic int
537187692Snwhitehornacpi_get_resource(device_t dev, device_t child, int type, int rid, u_long *startp, u_long *countp)
538187692Snwhitehorn{
539187692Snwhitehorn    struct acpi_device		*ad = device_get_ivars(child);
540187692Snwhitehorn    struct resource_list	*rl = &ad->ad_rl;
541187692Snwhitehorn    struct resource_list_entry	*rle;
542187692Snwhitehorn
543187692Snwhitehorn    rle = resource_list_find(rl, type, rid);
544187692Snwhitehorn    if (!rle)
545187692Snwhitehorn	return(ENOENT);
546187692Snwhitehorn
547187692Snwhitehorn    if (startp)
548187692Snwhitehorn	*startp = rle->start;
549187692Snwhitehorn    if (countp)
550187692Snwhitehorn	*countp = rle->count;
551193640Sariff
552187692Snwhitehorn    return(0);
553187692Snwhitehorn}
554187692Snwhitehorn
555187692Snwhitehornstatic struct resource *
556187692Snwhitehornacpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
557187692Snwhitehorn		    u_long start, u_long end, u_long count, u_int flags)
558187692Snwhitehorn{
559187692Snwhitehorn    struct acpi_device *ad = device_get_ivars(child);
560187692Snwhitehorn    struct resource_list *rl = &ad->ad_rl;
561187692Snwhitehorn
562187692Snwhitehorn    return(resource_list_alloc(rl, bus, child, type, rid, start, end, count, flags));
563187692Snwhitehorn}
564187692Snwhitehorn
565187692Snwhitehornstatic int
566187692Snwhitehornacpi_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r)
567187692Snwhitehorn{
568187692Snwhitehorn    struct acpi_device *ad = device_get_ivars(child);
569187692Snwhitehorn    struct resource_list *rl = &ad->ad_rl;
570187692Snwhitehorn
571187692Snwhitehorn    return(resource_list_release(rl, bus, child, type, rid, r));
572187692Snwhitehorn}
573187692Snwhitehorn
574187692Snwhitehorn/*
575187692Snwhitehorn * Scan relevant portions of the ACPI namespace and attach child devices.
576187692Snwhitehorn *
577187692Snwhitehorn * Note that we only expect to find devices in the \_TZ_, \_SI_ and \_SB_ scopes,
578187692Snwhitehorn * and \_TZ_ becomes obsolete in the ACPI 2.0 spec.
579187692Snwhitehorn */
580187692Snwhitehornstatic void
581187692Snwhitehornacpi_probe_children(device_t bus)
582187692Snwhitehorn{
583187692Snwhitehorn    ACPI_HANDLE		parent;
584187692Snwhitehorn    static char		*scopes[] = {"\\_TZ_", "\\_SI", "\\_SB_", NULL};
585187692Snwhitehorn    int			i;
586187692Snwhitehorn
587187692Snwhitehorn    FUNCTION_TRACE(__func__);
588187692Snwhitehorn    ACPI_ASSERTLOCK;
589187692Snwhitehorn
590187692Snwhitehorn    /*
591187692Snwhitehorn     * Create any static children by calling device identify methods.
592187692Snwhitehorn     */
593187692Snwhitehorn    DEBUG_PRINT(TRACE_OBJECTS, ("device identify routines\n"));
594187692Snwhitehorn    bus_generic_probe(bus);
595187692Snwhitehorn
596187692Snwhitehorn    /*
597187692Snwhitehorn     * Scan the namespace and insert placeholders for all the devices that
598187692Snwhitehorn     * we find.
599187692Snwhitehorn     *
600187692Snwhitehorn     * Note that we use AcpiWalkNamespace rather than AcpiGetDevices because
601187692Snwhitehorn     * we want to create nodes for all devices, not just those that are currently
602187692Snwhitehorn     * present. (This assumes that we don't want to create/remove devices as they
603187692Snwhitehorn     * appear, which might be smarter.)
604187692Snwhitehorn     */
605187692Snwhitehorn    DEBUG_PRINT(TRACE_OBJECTS, ("namespace scan\n"));
606187692Snwhitehorn    for (i = 0; scopes[i] != NULL; i++)
607187692Snwhitehorn	if ((AcpiGetHandle(ACPI_ROOT_OBJECT, scopes[i], &parent)) == AE_OK)
608187692Snwhitehorn	    AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100, acpi_probe_child, bus, NULL);
609187692Snwhitehorn
610187692Snwhitehorn    /*
611187692Snwhitehorn     * Scan all of the child devices we have created and let them probe/attach.
612187692Snwhitehorn     */
613187692Snwhitehorn    DEBUG_PRINT(TRACE_OBJECTS, ("first bus_generic_attach\n"));
614187692Snwhitehorn    bus_generic_attach(bus);
615187692Snwhitehorn
616187692Snwhitehorn    /*
617187692Snwhitehorn     * Some of these children may have attached others as part of their attach
618187692Snwhitehorn     * process (eg. the root PCI bus driver), so rescan.
619187692Snwhitehorn     */
620187692Snwhitehorn    DEBUG_PRINT(TRACE_OBJECTS, ("second bus_generic_attach\n"));
621187692Snwhitehorn    bus_generic_attach(bus);
622187692Snwhitehorn
623187692Snwhitehorn    return_VOID;
624187692Snwhitehorn}
625187692Snwhitehorn
626187692Snwhitehorn/*
627187692Snwhitehorn * Evaluate a child device and determine whether we might attach a device to
628187692Snwhitehorn * it.
629187692Snwhitehorn */
630187692Snwhitehornstatic ACPI_STATUS
631187692Snwhitehornacpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
632187692Snwhitehorn{
633187692Snwhitehorn    ACPI_OBJECT_TYPE	type;
634187692Snwhitehorn    device_t		child, bus = (device_t)context;
635187692Snwhitehorn
636187692Snwhitehorn    FUNCTION_TRACE(__func__);
637187692Snwhitehorn
638187692Snwhitehorn    /*
639187692Snwhitehorn     * Skip this device if we think we'll have trouble with it.
640187692Snwhitehorn     */
641187692Snwhitehorn    if (acpi_avoid(handle))
642187692Snwhitehorn	return_ACPI_STATUS(AE_OK);
643187692Snwhitehorn
644187692Snwhitehorn    if (AcpiGetType(handle, &type) == AE_OK) {
645187692Snwhitehorn	switch(type) {
646187692Snwhitehorn	case ACPI_TYPE_DEVICE:
647187692Snwhitehorn	case ACPI_TYPE_PROCESSOR:
648187692Snwhitehorn	case ACPI_TYPE_THERMAL:
649187692Snwhitehorn	case ACPI_TYPE_POWER:
650187692Snwhitehorn	    if (acpi_disabled("children"))
651187692Snwhitehorn		break;
652187692Snwhitehorn	    /*
653187692Snwhitehorn	     * Create a placeholder device for this node.  Sort the placeholder
654187692Snwhitehorn	     * so that the probe/attach passes will run breadth-first.
655187692Snwhitehorn	     */
656187692Snwhitehorn	    DEBUG_PRINT(TRACE_OBJECTS, ("scanning '%s'\n", acpi_name(handle)))
657187692Snwhitehorn	    child = BUS_ADD_CHILD(bus, level * 10, NULL, -1);
658187692Snwhitehorn	    acpi_set_handle(child, handle);
659187692Snwhitehorn	    DEBUG_EXEC(device_probe_and_attach(child));
660187692Snwhitehorn	    break;
661187692Snwhitehorn	}
662187692Snwhitehorn    }
663187692Snwhitehorn    return_ACPI_STATUS(AE_OK);
664187692Snwhitehorn}
665187692Snwhitehorn
666187692Snwhitehornstatic void
667187692Snwhitehornacpi_shutdown_pre_sync(void *arg, int howto)
668187692Snwhitehorn{
669187692Snwhitehorn
670187692Snwhitehorn    ACPI_ASSERTLOCK;
671187692Snwhitehorn
672187692Snwhitehorn    /*
673187692Snwhitehorn     * Disable all ACPI events before soft off, otherwise the system
674187692Snwhitehorn     * will be turned on again on some laptops.
675187692Snwhitehorn     *
676187692Snwhitehorn     * XXX this should probably be restricted to masking some events just
677187692Snwhitehorn     *     before powering down, since we may still need ACPI during the
678187692Snwhitehorn     *     shutdown process.
679187692Snwhitehorn     */
680187692Snwhitehorn    acpi_Disable((struct acpi_softc *)arg);
681187692Snwhitehorn}
682187692Snwhitehorn
683187692Snwhitehornstatic void
684187692Snwhitehornacpi_shutdown_final(void *arg, int howto)
685187692Snwhitehorn{
686187692Snwhitehorn    ACPI_STATUS	status;
687187692Snwhitehorn
688187692Snwhitehorn    ACPI_ASSERTLOCK;
689187692Snwhitehorn
690187692Snwhitehorn    if (howto & RB_POWEROFF) {
691187692Snwhitehorn	printf("Power system off using ACPI...\n");
692187692Snwhitehorn	if ((status = AcpiEnterSleepState(acpi_off_state)) != AE_OK) {
693187692Snwhitehorn	    printf("ACPI power-off failed - %s\n", acpi_strerror(status));
694187692Snwhitehorn	} else {
695187692Snwhitehorn	    DELAY(1000000);
696187692Snwhitehorn	    printf("ACPI power-off failed - timeout\n");
697187692Snwhitehorn	}
698187692Snwhitehorn    }
699187692Snwhitehorn}
700187692Snwhitehorn
701187692Snwhitehornstatic void
702187692Snwhitehornacpi_enable_fixed_events(struct acpi_softc *sc)
703187692Snwhitehorn{
704187692Snwhitehorn    static int	first_time = 1;
705187692Snwhitehorn#define MSGFORMAT "%s button is handled as a fixed feature programming model.\n"
706187692Snwhitehorn
707187692Snwhitehorn    ACPI_ASSERTLOCK;
708187692Snwhitehorn
709187692Snwhitehorn    /* Enable and clear fixed events and install handlers. */
710187692Snwhitehorn    if ((AcpiGbl_FADT != NULL) && (AcpiGbl_FADT->PwrButton == 0)) {
711187692Snwhitehorn	AcpiEnableEvent(ACPI_EVENT_POWER_BUTTON, ACPI_EVENT_FIXED);
712187692Snwhitehorn	AcpiClearEvent(ACPI_EVENT_POWER_BUTTON, ACPI_EVENT_FIXED);
713187692Snwhitehorn	AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
714187692Snwhitehorn				     acpi_eventhandler_power_button_for_sleep, sc);
715187692Snwhitehorn	if (first_time) {
716187692Snwhitehorn	    device_printf(sc->acpi_dev, MSGFORMAT, "power");
717187692Snwhitehorn	}
718187692Snwhitehorn    }
719187692Snwhitehorn    if ((AcpiGbl_FADT != NULL) && (AcpiGbl_FADT->SleepButton == 0)) {
720187692Snwhitehorn	AcpiEnableEvent(ACPI_EVENT_SLEEP_BUTTON, ACPI_EVENT_FIXED);
721187692Snwhitehorn	AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON, ACPI_EVENT_FIXED);
722187692Snwhitehorn	AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON,
723187692Snwhitehorn				     acpi_eventhandler_sleep_button_for_sleep, sc);
724187692Snwhitehorn	if (first_time) {
725187692Snwhitehorn	    device_printf(sc->acpi_dev, MSGFORMAT, "sleep");
726187692Snwhitehorn	}
727187692Snwhitehorn    }
728187692Snwhitehorn
729187692Snwhitehorn    first_time = 0;
730187692Snwhitehorn}
731187692Snwhitehorn
732187692Snwhitehorn/*
733187692Snwhitehorn * Returns true if the device is actually present and should
734187692Snwhitehorn * be attached to.  This requires the present, enabled, UI-visible
735187692Snwhitehorn * and diagnostics-passed bits to be set.
736187692Snwhitehorn */
737188259SnwhitehornBOOLEAN
738187692Snwhitehornacpi_DeviceIsPresent(device_t dev)
739188259Snwhitehorn{
740188259Snwhitehorn    ACPI_HANDLE		h;
741187692Snwhitehorn    ACPI_DEVICE_INFO	devinfo;
742187692Snwhitehorn    ACPI_STATUS		error;
743188259Snwhitehorn
744187692Snwhitehorn    ACPI_ASSERTLOCK;
745187692Snwhitehorn
746187692Snwhitehorn    if ((h = acpi_get_handle(dev)) == NULL)
747187692Snwhitehorn	return(FALSE);
748187692Snwhitehorn    if ((error = AcpiGetObjectInfo(h, &devinfo)) != AE_OK)
749187692Snwhitehorn	return(FALSE);
750187692Snwhitehorn    /* XXX 0xf is probably not appropriate */
751187692Snwhitehorn    if ((devinfo.Valid & ACPI_VALID_HID) && (devinfo.CurrentStatus & 0xf))
752187692Snwhitehorn	return(TRUE);
753187692Snwhitehorn    return(FALSE);
754187692Snwhitehorn}
755187692Snwhitehorn
756187692Snwhitehorn/*
757187692Snwhitehorn * Match a HID string against a device
758187692Snwhitehorn */
759187692SnwhitehornBOOLEAN
760187692Snwhitehornacpi_MatchHid(device_t dev, char *hid)
761187692Snwhitehorn{
762187692Snwhitehorn    ACPI_HANDLE		h;
763187692Snwhitehorn    ACPI_DEVICE_INFO	devinfo;
764    ACPI_STATUS		error;
765
766    ACPI_ASSERTLOCK;
767
768    if (hid == NULL)
769	return(FALSE);
770    if ((h = acpi_get_handle(dev)) == NULL)
771	return(FALSE);
772    if ((error = AcpiGetObjectInfo(h, &devinfo)) != AE_OK)
773	return(FALSE);
774    if ((devinfo.Valid & ACPI_VALID_HID) && !strcmp(hid, devinfo.HardwareId))
775	return(TRUE);
776    return(FALSE);
777}
778
779/*
780 * Return the handle of a named object within our scope, ie. that of (parent)
781 * or one if its parents.
782 */
783ACPI_STATUS
784acpi_GetHandleInScope(ACPI_HANDLE parent, char *path, ACPI_HANDLE *result)
785{
786    ACPI_HANDLE		r;
787    ACPI_STATUS		status;
788
789    ACPI_ASSERTLOCK;
790
791    /* walk back up the tree to the root */
792    for (;;) {
793	status = AcpiGetHandle(parent, path, &r);
794	if (status == AE_OK) {
795	    *result = r;
796	    return(AE_OK);
797	}
798	if (status != AE_NOT_FOUND)
799	    return(AE_OK);
800	if (AcpiGetParent(parent, &r) != AE_OK)
801	    return(AE_NOT_FOUND);
802	parent = r;
803    }
804}
805
806/*
807 * Allocate a buffer with a preset data size.
808 */
809ACPI_BUFFER *
810acpi_AllocBuffer(int size)
811{
812    ACPI_BUFFER	*buf;
813
814    if ((buf = malloc(size + sizeof(*buf), M_ACPIDEV, M_NOWAIT)) == NULL)
815	return(NULL);
816    buf->Length = size;
817    buf->Pointer = (void *)(buf + 1);
818    return(buf);
819}
820
821/*
822 * Perform the tedious double-get procedure required for fetching something into
823 * an ACPI_BUFFER that has not been initialised.
824 */
825ACPI_STATUS
826acpi_GetIntoBuffer(ACPI_HANDLE handle, ACPI_STATUS (*func)(ACPI_HANDLE, ACPI_BUFFER *), ACPI_BUFFER *buf)
827{
828    ACPI_STATUS	status;
829
830    ACPI_ASSERTLOCK;
831
832    buf->Length = 0;
833    buf->Pointer = NULL;
834
835    if ((status = func(handle, buf)) != AE_BUFFER_OVERFLOW)
836	return(status);
837    if ((buf->Pointer = AcpiOsCallocate(buf->Length)) == NULL)
838	return(AE_NO_MEMORY);
839    return(func(handle, buf));
840}
841
842/*
843 * Perform the tedious double-evaluate procedure for evaluating something into
844 * an ACPI_BUFFER that has not been initialised.  Note that this evaluates
845 * twice, so avoid applying this to things that may have side-effects.
846 *
847 * This is like AcpiEvaluateObject with automatic buffer allocation.
848 */
849ACPI_STATUS
850acpi_EvaluateIntoBuffer(ACPI_HANDLE object, ACPI_STRING pathname, ACPI_OBJECT_LIST *params,
851			ACPI_BUFFER *buf)
852{
853    ACPI_STATUS	status;
854
855    ACPI_ASSERTLOCK;
856
857    buf->Length = 0;
858    buf->Pointer = NULL;
859
860    if ((status = AcpiEvaluateObject(object, pathname, params, buf)) != AE_BUFFER_OVERFLOW)
861	return(status);
862    if ((buf->Pointer = AcpiOsCallocate(buf->Length)) == NULL)
863	return(AE_NO_MEMORY);
864    return(AcpiEvaluateObject(object, pathname, params, buf));
865}
866
867/*
868 * Evaluate a path that should return an integer.
869 */
870ACPI_STATUS
871acpi_EvaluateInteger(ACPI_HANDLE handle, char *path, int *number)
872{
873    ACPI_STATUS	error;
874    ACPI_BUFFER	buf;
875    ACPI_OBJECT	param;
876
877    ACPI_ASSERTLOCK;
878
879    if (handle == NULL)
880	handle = ACPI_ROOT_OBJECT;
881    buf.Pointer = &param;
882    buf.Length = sizeof(param);
883    if ((error = AcpiEvaluateObject(handle, path, NULL, &buf)) == AE_OK) {
884	if (param.Type == ACPI_TYPE_INTEGER) {
885	    *number = param.Integer.Value;
886	} else {
887	    error = AE_TYPE;
888	}
889    }
890    return(error);
891}
892
893/*
894 * Iterate over the elements of an a package object, calling the supplied
895 * function for each element.
896 *
897 * XXX possible enhancement might be to abort traversal on error.
898 */
899ACPI_STATUS
900acpi_ForeachPackageObject(ACPI_OBJECT *pkg, void (* func)(ACPI_OBJECT *comp, void *arg), void *arg)
901{
902    ACPI_OBJECT	*comp;
903    int		i;
904
905    if ((pkg == NULL) || (pkg->Type != ACPI_TYPE_PACKAGE))
906	return(AE_BAD_PARAMETER);
907
908    /* iterate over components */
909    for (i = 0, comp = pkg->Package.Elements; i < pkg->Package.Count; i++, comp++)
910	func(comp, arg);
911
912    return(AE_OK);
913}
914
915/*
916 * Find the (index)th resource object in a set.
917 */
918ACPI_STATUS
919acpi_FindIndexedResource(ACPI_RESOURCE *resbuf, int index, ACPI_RESOURCE **resp)
920{
921    u_int8_t		*p;
922    int			i;
923
924    p = (u_int8_t *)resbuf;
925    i = index;
926    while (i > 0) {
927	/* range check */
928	if (p > ((u_int8_t *)resbuf + resbuf->Length))
929	    return(AE_BAD_PARAMETER);
930	p += ((ACPI_RESOURCE *)p)->Length;
931	i--;
932    }
933    if (resp != NULL)
934	*resp = (ACPI_RESOURCE *)p;
935    return(AE_OK);
936}
937
938static ACPI_STATUS __inline
939acpi_wakeup(UINT8 state)
940{
941    UINT16			Count;
942    ACPI_STATUS		Status;
943    ACPI_OBJECT_LIST	Arg_list;
944    ACPI_OBJECT		Arg;
945    ACPI_OBJECT		Objects[3]; /* package plus 2 number objects */
946    ACPI_BUFFER		ReturnBuffer;
947
948    FUNCTION_TRACE_U32(__func__, state);
949    ACPI_ASSERTLOCK;
950
951    /* wait for the WAK_STS bit */
952    Count = 0;
953    while (!(AcpiHwRegisterBitAccess(ACPI_READ, ACPI_MTX_LOCK, WAK_STS))) {
954	AcpiOsSleepUsec(1000);
955	/*
956	 * Some BIOSes don't set WAK_STS at all,
957	 * give up waiting for wakeup if we time out.
958	 */
959	if (Count > 1000) {
960	    printf("ACPI: timed out waiting for WAK_STS, continuing\n");
961	    break;	/* giving up */
962	}
963	Count++;
964    }
965
966    /*
967     * Evaluate the _WAK method
968     */
969    bzero(&Arg_list, sizeof(Arg_list));
970    Arg_list.Count = 1;
971    Arg_list.Pointer = &Arg;
972
973    bzero(&Arg, sizeof(Arg));
974    Arg.Type = ACPI_TYPE_INTEGER;
975    Arg.Integer.Value = state;
976
977    /*
978     * Set up _WAK result code buffer.
979     *
980     * XXX should use acpi_EvaluateIntoBuffer
981     */
982    bzero(Objects, sizeof(Objects));
983    ReturnBuffer.Length = sizeof(Objects);
984    ReturnBuffer.Pointer = Objects;
985    AcpiEvaluateObject (NULL, "\\_WAK", &Arg_list, &ReturnBuffer);
986
987    Status = AE_OK;
988
989    /* Check result code for _WAK */
990    if (Objects[0].Type != ACPI_TYPE_PACKAGE ||
991	Objects[1].Type != ACPI_TYPE_INTEGER  ||
992	Objects[2].Type != ACPI_TYPE_INTEGER) {
993	/*
994	 * In many BIOSes, _WAK doesn't return a result code.
995	 * We don't need to worry about it too much :-).
996	 */
997	DEBUG_PRINT(ACPI_INFO,
998		    ("acpi_wakeup: _WAK result code is corrupted, "
999		     "but should be OK.\n"));
1000    } else {
1001	/* evaluate status code */
1002	switch (Objects[1].Integer.Value) {
1003	case 0x00000001:
1004	    DEBUG_PRINT(ACPI_ERROR,
1005			("acpi_wakeup: Wake was signaled "
1006			 "but failed due to lack of power.\n"));
1007	    Status = AE_ERROR;
1008	    break;
1009
1010	case 0x00000002:
1011	    DEBUG_PRINT(ACPI_ERROR,
1012			("acpi_wakeup: Wake was signaled "
1013			 "but failed due to thermal condition.\n"));
1014	    Status = AE_ERROR;
1015	    break;
1016	}
1017	/* evaluate PSS code */
1018	if (Objects[2].Integer.Value == 0) {
1019	    DEBUG_PRINT(ACPI_ERROR,
1020			("acpi_wakeup: The targeted S-state "
1021			 "was not entered because of too much current "
1022			 "being drawn from the power supply.\n"));
1023	    Status = AE_ERROR;
1024	}
1025    }
1026    return_ACPI_STATUS(Status);
1027}
1028
1029/*
1030 * Set the system sleep state
1031 *
1032 * Currently we only support S1 and S5
1033 */
1034ACPI_STATUS
1035acpi_SetSleepState(struct acpi_softc *sc, int state)
1036{
1037    ACPI_STATUS	status = AE_OK;
1038
1039    FUNCTION_TRACE_U32(__func__, state);
1040    ACPI_ASSERTLOCK;
1041
1042    switch (state) {
1043    case ACPI_STATE_S0:	/* XXX only for testing */
1044	status = AcpiEnterSleepState((UINT8)state);
1045	if (status != AE_OK) {
1046	    device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n", acpi_strerror(status));
1047	}
1048	break;
1049
1050    case ACPI_STATE_S1:
1051	/*
1052	 * Inform all devices that we are going to sleep.
1053	 */
1054	if (DEVICE_SUSPEND(root_bus) != 0) {
1055	    /*
1056	     * Re-wake the system.
1057	     *
1058	     * XXX note that a better two-pass approach with a 'veto' pass
1059	     *     followed by a "real thing" pass would be better, but the
1060	     *     current bus interface does not provide for this.
1061	     */
1062	    DEVICE_RESUME(root_bus);
1063	    return_ACPI_STATUS(AE_ERROR);
1064	}
1065	sc->acpi_sstate = state;
1066	status = AcpiEnterSleepState((UINT8)state);
1067	if (status != AE_OK) {
1068	    device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n", acpi_strerror(status));
1069	    break;
1070	}
1071	acpi_wakeup((UINT8)state);
1072	DEVICE_RESUME(root_bus);
1073	sc->acpi_sstate = ACPI_STATE_S0;
1074	acpi_enable_fixed_events(sc);
1075	break;
1076
1077    case ACPI_STATE_S3:
1078	acpi_off_state = ACPI_STATE_S3;
1079	/* FALLTHROUGH */
1080    case ACPI_STATE_S5:
1081	/*
1082	 * Shut down cleanly and power off.  This will call us back through the
1083	 * shutdown handlers.
1084	 */
1085	shutdown_nice(RB_POWEROFF);
1086	break;
1087
1088    default:
1089	status = AE_BAD_PARAMETER;
1090	break;
1091    }
1092    return_ACPI_STATUS(status);
1093}
1094
1095/*
1096 * Enable/Disable ACPI
1097 */
1098ACPI_STATUS
1099acpi_Enable(struct acpi_softc *sc)
1100{
1101    ACPI_STATUS	status;
1102    u_int32_t	flags;
1103
1104    FUNCTION_TRACE(__func__);
1105    ACPI_ASSERTLOCK;
1106
1107    flags = ACPI_NO_ADDRESS_SPACE_INIT | ACPI_NO_HARDWARE_INIT |
1108            ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT;
1109    if (!sc->acpi_enabled) {
1110	status = AcpiEnableSubsystem(flags);
1111    } else {
1112	status = AE_OK;
1113    }
1114    if (status == AE_OK)
1115	sc->acpi_enabled = 1;
1116    return_ACPI_STATUS(status);
1117}
1118
1119ACPI_STATUS
1120acpi_Disable(struct acpi_softc *sc)
1121{
1122    ACPI_STATUS	status;
1123
1124    FUNCTION_TRACE(__func__);
1125    ACPI_ASSERTLOCK;
1126
1127    if (sc->acpi_enabled) {
1128	status = AcpiDisable();
1129    } else {
1130	status = AE_OK;
1131    }
1132    if (status == AE_OK)
1133	sc->acpi_enabled = 0;
1134    return_ACPI_STATUS(status);
1135}
1136
1137/*
1138 * ACPI Event Handlers
1139 */
1140
1141/* System Event Handlers (registered by EVENTHANDLER_REGISTER) */
1142
1143static void
1144acpi_system_eventhandler_sleep(void *arg, int state)
1145{
1146    FUNCTION_TRACE_U32(__func__, state);
1147
1148    ACPI_LOCK;
1149    if (state >= ACPI_STATE_S0 && state <= ACPI_S_STATES_MAX)
1150	acpi_SetSleepState((struct acpi_softc *)arg, state);
1151    ACPI_UNLOCK;
1152    return_VOID;
1153}
1154
1155static void
1156acpi_system_eventhandler_wakeup(void *arg, int state)
1157{
1158    FUNCTION_TRACE_U32(__func__, state);
1159
1160    /* Well, what to do? :-) */
1161
1162    ACPI_LOCK;
1163    ACPI_UNLOCK;
1164
1165    return_VOID;
1166}
1167
1168/*
1169 * ACPICA Event Handlers (FixedEvent, also called from button notify handler)
1170 */
1171UINT32
1172acpi_eventhandler_power_button_for_sleep(void *context)
1173{
1174    struct acpi_softc	*sc = (struct acpi_softc *)context;
1175
1176    FUNCTION_TRACE(__func__);
1177
1178    EVENTHANDLER_INVOKE(acpi_sleep_event, sc->acpi_power_button_sx);
1179
1180    return_VALUE(INTERRUPT_HANDLED);
1181}
1182
1183UINT32
1184acpi_eventhandler_power_button_for_wakeup(void *context)
1185{
1186    struct acpi_softc	*sc = (struct acpi_softc *)context;
1187
1188    FUNCTION_TRACE(__func__);
1189
1190    EVENTHANDLER_INVOKE(acpi_wakeup_event, sc->acpi_power_button_sx);
1191
1192    return_VALUE(INTERRUPT_HANDLED);
1193}
1194
1195UINT32
1196acpi_eventhandler_sleep_button_for_sleep(void *context)
1197{
1198    struct acpi_softc	*sc = (struct acpi_softc *)context;
1199
1200    FUNCTION_TRACE(__func__);
1201
1202    EVENTHANDLER_INVOKE(acpi_sleep_event, sc->acpi_sleep_button_sx);
1203
1204    return_VALUE(INTERRUPT_HANDLED);
1205}
1206
1207UINT32
1208acpi_eventhandler_sleep_button_for_wakeup(void *context)
1209{
1210    struct acpi_softc	*sc = (struct acpi_softc *)context;
1211
1212    FUNCTION_TRACE(__func__);
1213
1214    EVENTHANDLER_INVOKE(acpi_wakeup_event, sc->acpi_sleep_button_sx);
1215
1216    return_VALUE(INTERRUPT_HANDLED);
1217}
1218
1219/*
1220 * XXX This is kinda ugly, and should not be here.
1221 */
1222struct acpi_staticbuf {
1223    ACPI_BUFFER	buffer;
1224    char	data[512];
1225};
1226
1227char *
1228acpi_strerror(ACPI_STATUS excep)
1229{
1230    static struct acpi_staticbuf	buf;
1231
1232    buf.buffer.Length = 512;
1233    buf.buffer.Pointer = &buf.data[0];
1234
1235    if (AcpiFormatException(excep, &buf.buffer) == AE_OK)
1236	return(buf.buffer.Pointer);
1237    return("(error formatting exception)");
1238}
1239
1240char *
1241acpi_name(ACPI_HANDLE handle)
1242{
1243    static struct acpi_staticbuf	buf;
1244
1245    ACPI_ASSERTLOCK;
1246
1247    buf.buffer.Length = 512;
1248    buf.buffer.Pointer = &buf.data[0];
1249
1250    if (AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf.buffer) == AE_OK)
1251	return(buf.buffer.Pointer);
1252    return("(unknown path)");
1253}
1254
1255/*
1256 * Debugging/bug-avoidance.  Avoid trying to fetch info on various
1257 * parts of the namespace.
1258 */
1259int
1260acpi_avoid(ACPI_HANDLE handle)
1261{
1262    char	*cp, *np;
1263    int		len;
1264
1265    np = acpi_name(handle);
1266    if (*np == '\\')
1267	np++;
1268    if ((cp = getenv("debug.acpi.avoid")) == NULL)
1269	return(0);
1270
1271    /* scan the avoid list checking for a match */
1272    for (;;) {
1273	while ((*cp != 0) && isspace(*cp))
1274	    cp++;
1275	if (*cp == 0)
1276	    break;
1277	len = 0;
1278	while ((cp[len] != 0) && !isspace(cp[len]))
1279	    len++;
1280	if (!strncmp(cp, np, len)) {
1281	    DEBUG_PRINT(TRACE_OBJECTS, ("avoiding '%s'\n", np));
1282	    return(1);
1283	}
1284	cp += len;
1285    }
1286    return(0);
1287}
1288
1289/*
1290 * Debugging/bug-avoidance.  Disable ACPI subsystem components.
1291 */
1292int
1293acpi_disabled(char *subsys)
1294{
1295    char	*cp;
1296    int		len;
1297
1298    if ((cp = getenv("debug.acpi.disable")) == NULL)
1299	return(0);
1300    if (!strcmp(cp, "all"))
1301	return(1);
1302
1303    /* scan the disable list checking for a match */
1304    for (;;) {
1305	while ((*cp != 0) && isspace(*cp))
1306	    cp++;
1307	if (*cp == 0)
1308	    break;
1309	len = 0;
1310	while ((cp[len] != 0) && !isspace(cp[len]))
1311	    len++;
1312	if (!strncmp(cp, subsys, len)) {
1313	    DEBUG_PRINT(TRACE_OBJECTS, ("disabled '%s'\n", subsys));
1314	    return(1);
1315	}
1316	cp += len;
1317    }
1318    return(0);
1319}
1320
1321/*
1322 * Control interface.
1323 *
1324 * We multiplex ioctls for all participating ACPI devices here.  Individual
1325 * drivers wanting to be accessible via /dev/acpi should use the register/deregister
1326 * interface to make their handlers visible.
1327 */
1328struct acpi_ioctl_hook
1329{
1330    TAILQ_ENTRY(acpi_ioctl_hook)	link;
1331    u_long				cmd;
1332    int					(* fn)(u_long cmd, caddr_t addr, void *arg);
1333    void				*arg;
1334};
1335
1336static TAILQ_HEAD(,acpi_ioctl_hook)	acpi_ioctl_hooks;
1337static int				acpi_ioctl_hooks_initted;
1338
1339/*
1340 * Register an ioctl handler.
1341 */
1342int
1343acpi_register_ioctl(u_long cmd, int (* fn)(u_long cmd, caddr_t addr, void *arg), void *arg)
1344{
1345    struct acpi_ioctl_hook	*hp;
1346
1347    if ((hp = malloc(sizeof(*hp), M_ACPIDEV, M_NOWAIT)) == NULL)
1348	return(ENOMEM);
1349    hp->cmd = cmd;
1350    hp->fn = fn;
1351    hp->arg = arg;
1352    if (acpi_ioctl_hooks_initted == 0) {
1353	TAILQ_INIT(&acpi_ioctl_hooks);
1354	acpi_ioctl_hooks_initted = 1;
1355    }
1356    TAILQ_INSERT_TAIL(&acpi_ioctl_hooks, hp, link);
1357    return(0);
1358}
1359
1360/*
1361 * Deregister an ioctl handler.
1362 */
1363void
1364acpi_deregister_ioctl(u_long cmd, int (* fn)(u_long cmd, caddr_t addr, void *arg))
1365{
1366    struct acpi_ioctl_hook	*hp;
1367
1368    TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link)
1369	if ((hp->cmd == cmd) && (hp->fn == fn))
1370	    break;
1371
1372    if (hp != NULL) {
1373	TAILQ_REMOVE(&acpi_ioctl_hooks, hp, link);
1374	free(hp, M_ACPIDEV);
1375    }
1376}
1377
1378static int
1379acpiopen(dev_t dev, int flag, int fmt, struct proc *p)
1380{
1381    return(0);
1382}
1383
1384static int
1385acpiclose(dev_t dev, int flag, int fmt, struct proc *p)
1386{
1387    return(0);
1388}
1389
1390static int
1391acpiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, struct proc *p)
1392{
1393    struct acpi_softc		*sc;
1394    struct acpi_ioctl_hook	*hp;
1395    int				error, xerror, state;
1396
1397    ACPI_LOCK;
1398
1399    error = state = 0;
1400    sc = dev->si_drv1;
1401
1402    /*
1403     * Scan the list of registered ioctls, looking for handlers.
1404     */
1405    if (acpi_ioctl_hooks_initted) {
1406	TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link) {
1407	    if (hp->cmd == cmd) {
1408		xerror = hp->fn(cmd, addr, hp->arg);
1409		if (xerror != 0)
1410		    error = xerror;
1411		goto out;
1412	    }
1413	}
1414    }
1415
1416    /*
1417     * Core system ioctls.
1418     */
1419    switch (cmd) {
1420    case ACPIIO_ENABLE:
1421	if (ACPI_FAILURE(acpi_Enable(sc)))
1422	    error = ENXIO;
1423	break;
1424
1425    case ACPIIO_DISABLE:
1426	if (ACPI_FAILURE(acpi_Disable(sc)))
1427	    error = ENXIO;
1428	break;
1429
1430    case ACPIIO_SETSLPSTATE:
1431	if (!sc->acpi_enabled) {
1432	    error = ENXIO;
1433	    break;
1434	}
1435	state = *(int *)addr;
1436	if (state >= ACPI_STATE_S0  && state <= ACPI_S_STATES_MAX) {
1437	    acpi_SetSleepState(sc, state);
1438	} else {
1439	    error = EINVAL;
1440	}
1441	break;
1442
1443    default:
1444	if (error == 0)
1445	    error = EINVAL;
1446	break;
1447    }
1448
1449out:
1450    ACPI_UNLOCK;
1451    return(error);
1452}
1453
1454static int
1455acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS)
1456{
1457    char sleep_state[10];
1458    int error;
1459    u_int new_state, old_state;
1460
1461    old_state = *(u_int *)oidp->oid_arg1;
1462    if (old_state > ACPI_S_STATES_MAX) {
1463	strcpy(sleep_state, "unknown");
1464    } else {
1465	strncpy(sleep_state, sleep_state_names[old_state],
1466		sizeof(sleep_state_names[old_state]));
1467    }
1468    error = sysctl_handle_string(oidp, sleep_state, sizeof(sleep_state), req);
1469    if (error == 0 && req->newptr != NULL) {
1470	for (new_state = ACPI_STATE_S0; new_state <= ACPI_S_STATES_MAX; new_state++) {
1471	    if (strncmp(sleep_state, sleep_state_names[new_state],
1472			sizeof(sleep_state)) == 0)
1473		break;
1474	}
1475	if ((new_state != old_state) && (new_state <= ACPI_S_STATES_MAX)) {
1476	    *(u_int *)oidp->oid_arg1 = new_state;
1477	} else {
1478	    error = EINVAL;
1479	}
1480    }
1481    return(error);
1482}
1483
1484#ifdef ACPI_DEBUG
1485/*
1486 * Support for parsing debug options from the kernel environment.
1487 *
1488 * Bits may be set in the AcpiDbgLayer and AcpiDbgLevel debug registers
1489 * by specifying the names of the bits in the debug.acpi.layer and
1490 * debug.acpi.level environment variables.  Bits may be unset by
1491 * prefixing the bit name with !.
1492 */
1493struct debugtag
1494{
1495    char	*name;
1496    UINT32	value;
1497};
1498
1499static struct debugtag	dbg_layer[] = {
1500    {"ACPI_UTILITIES",		ACPI_UTILITIES},
1501    {"ACPI_HARDWARE",		ACPI_HARDWARE},
1502    {"ACPI_EVENTS",		ACPI_EVENTS},
1503    {"ACPI_TABLES",		ACPI_TABLES},
1504    {"ACPI_NAMESPACE",		ACPI_NAMESPACE},
1505    {"ACPI_PARSER",		ACPI_PARSER},
1506    {"ACPI_DISPATCHER",		ACPI_DISPATCHER},
1507    {"ACPI_EXECUTER",		ACPI_EXECUTER},
1508    {"ACPI_RESOURCES",		ACPI_RESOURCES},
1509    {"ACPI_POWER",		ACPI_POWER},
1510    {"ACPI_BUS",		ACPI_BUS},
1511    {"ACPI_POWER",		ACPI_POWER},
1512    {"ACPI_EC", 		ACPI_EC},
1513    {"ACPI_PROCESSOR",		ACPI_PROCESSOR},
1514    {"ACPI_AC_ADAPTER",		ACPI_AC_ADAPTER},
1515    {"ACPI_BATTERY",		ACPI_BATTERY},
1516    {"ACPI_BUTTON",		ACPI_BUTTON},
1517    {"ACPI_SYSTEM",		ACPI_SYSTEM},
1518    {"ACPI_THERMAL",		ACPI_THERMAL},
1519    {"ACPI_DEBUGGER",		ACPI_DEBUGGER},
1520    {"ACPI_OS_SERVICES",	ACPI_OS_SERVICES},
1521    {"ACPI_ALL_COMPONENTS",	ACPI_ALL_COMPONENTS},
1522    {NULL, 0}
1523};
1524
1525static struct debugtag dbg_level[] = {
1526    {"ACPI_OK",			ACPI_OK},
1527    {"ACPI_INFO",		ACPI_INFO},
1528    {"ACPI_WARN",		ACPI_WARN},
1529    {"ACPI_ERROR",		ACPI_ERROR},
1530    {"ACPI_FATAL",		ACPI_FATAL},
1531    {"ACPI_DEBUG_OBJECT",	ACPI_DEBUG_OBJECT},
1532    {"ACPI_ALL",		ACPI_ALL},
1533    {"TRACE_THREADS",		TRACE_THREADS},
1534    {"TRACE_PARSE",		TRACE_PARSE},
1535    {"TRACE_DISPATCH",		TRACE_DISPATCH},
1536    {"TRACE_LOAD",		TRACE_LOAD},
1537    {"TRACE_EXEC",		TRACE_EXEC},
1538    {"TRACE_NAMES",		TRACE_NAMES},
1539    {"TRACE_OPREGION",		TRACE_OPREGION},
1540    {"TRACE_BFIELD",		TRACE_BFIELD},
1541    {"TRACE_TRASH",		TRACE_TRASH},
1542    {"TRACE_TABLES",		TRACE_TABLES},
1543    {"TRACE_FUNCTIONS",		TRACE_FUNCTIONS},
1544    {"TRACE_VALUES",		TRACE_VALUES},
1545    {"TRACE_OBJECTS",		TRACE_OBJECTS},
1546    {"TRACE_ALLOCATIONS",	TRACE_ALLOCATIONS},
1547    {"TRACE_RESOURCES",		TRACE_RESOURCES},
1548    {"TRACE_IO",		TRACE_IO},
1549    {"TRACE_INTERRUPTS",	TRACE_INTERRUPTS},
1550    {"TRACE_USER_REQUESTS",	TRACE_USER_REQUESTS},
1551    {"TRACE_PACKAGE",		TRACE_PACKAGE},
1552    {"TRACE_MUTEX",		TRACE_MUTEX},
1553    {"TRACE_INIT",		TRACE_INIT},
1554    {"TRACE_ALL",		TRACE_ALL},
1555    {"VERBOSE_AML_DISASSEMBLE",	VERBOSE_AML_DISASSEMBLE},
1556    {"VERBOSE_INFO",		VERBOSE_INFO},
1557    {"VERBOSE_TABLES",		VERBOSE_TABLES},
1558    {"VERBOSE_EVENTS",		VERBOSE_EVENTS},
1559    {"VERBOSE_ALL",		VERBOSE_ALL},
1560    {NULL, 0}
1561};
1562
1563static void
1564acpi_parse_debug(char *cp, struct debugtag *tag, UINT32 *flag)
1565{
1566    char	*ep;
1567    int		i, l;
1568    int		set;
1569
1570    while (*cp) {
1571	if (isspace(*cp)) {
1572	    cp++;
1573	    continue;
1574	}
1575	ep = cp;
1576	while (*ep && !isspace(*ep))
1577	    ep++;
1578	if (*cp == '!') {
1579	    set = 0;
1580	    cp++;
1581	    if (cp == ep)
1582		continue;
1583	} else {
1584	    set = 1;
1585	}
1586	l = ep - cp;
1587	for (i = 0; tag[i].name != NULL; i++) {
1588	    if (!strncmp(cp, tag[i].name, l)) {
1589		if (set) {
1590		    *flag |= tag[i].value;
1591		} else {
1592		    *flag &= ~tag[i].value;
1593		}
1594		printf("ACPI_DEBUG: set '%s'\n", tag[i].name);
1595	    }
1596	}
1597	cp = ep;
1598    }
1599}
1600
1601static void
1602acpi_set_debugging(void *junk)
1603{
1604    char	*cp;
1605
1606    AcpiDbgLayer = 0;
1607    AcpiDbgLevel = 0;
1608    if ((cp = getenv("debug.acpi.layer")) != NULL)
1609	acpi_parse_debug(cp, &dbg_layer[0], &AcpiDbgLayer);
1610    if ((cp = getenv("debug.acpi.level")) != NULL)
1611	acpi_parse_debug(cp, &dbg_level[0], &AcpiDbgLevel);
1612
1613    printf("ACPI debug layer 0x%x  debug level 0x%x\n", AcpiDbgLayer, AcpiDbgLevel);
1614}
1615SYSINIT(acpi_debugging, SI_SUB_TUNABLES, SI_ORDER_ANY, acpi_set_debugging, NULL);
1616#endif
1617