xref: /freebsd/sys/dev/acpica/acpi.c (revision 879d6c230682d852ebe9c91ed469c0c14b04cbd3)
115e32d5dSMike Smith /*-
215e32d5dSMike Smith  * Copyright (c) 2000 Takanori Watanabe <takawata@jp.freebsd.org>
315e32d5dSMike Smith  * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
4cb9b0d80SMike Smith  * Copyright (c) 2000, 2001 Michael Smith
515e32d5dSMike Smith  * Copyright (c) 2000 BSDi
615e32d5dSMike Smith  * All rights reserved.
715e32d5dSMike Smith  *
815e32d5dSMike Smith  * Redistribution and use in source and binary forms, with or without
915e32d5dSMike Smith  * modification, are permitted provided that the following conditions
1015e32d5dSMike Smith  * are met:
1115e32d5dSMike Smith  * 1. Redistributions of source code must retain the above copyright
1215e32d5dSMike Smith  *    notice, this list of conditions and the following disclaimer.
1315e32d5dSMike Smith  * 2. Redistributions in binary form must reproduce the above copyright
1415e32d5dSMike Smith  *    notice, this list of conditions and the following disclaimer in the
1515e32d5dSMike Smith  *    documentation and/or other materials provided with the distribution.
1615e32d5dSMike Smith  *
1715e32d5dSMike Smith  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1815e32d5dSMike Smith  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1915e32d5dSMike Smith  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2015e32d5dSMike Smith  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2115e32d5dSMike Smith  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2215e32d5dSMike Smith  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2315e32d5dSMike Smith  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2415e32d5dSMike Smith  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2515e32d5dSMike Smith  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2615e32d5dSMike Smith  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2715e32d5dSMike Smith  * SUCH DAMAGE.
2815e32d5dSMike Smith  *
2915e32d5dSMike Smith  *	$FreeBSD$
3015e32d5dSMike Smith  */
3115e32d5dSMike Smith 
3215e32d5dSMike Smith #include "opt_acpi.h"
3315e32d5dSMike Smith #include <sys/param.h>
3415e32d5dSMike Smith #include <sys/kernel.h>
35fb919e4dSMark Murray #include <sys/proc.h>
36a89fcf28STakanori Watanabe #include <sys/fcntl.h>
3715e32d5dSMike Smith #include <sys/malloc.h>
3815e32d5dSMike Smith #include <sys/bus.h>
3915e32d5dSMike Smith #include <sys/conf.h>
4015e32d5dSMike Smith #include <sys/ioccom.h>
4115e32d5dSMike Smith #include <sys/reboot.h>
4215e32d5dSMike Smith #include <sys/sysctl.h>
4315e32d5dSMike Smith #include <sys/ctype.h>
441611ea87SMitsuru IWASAKI #include <sys/linker.h>
45f9390180SMitsuru IWASAKI #include <sys/power.h>
4654f6bca0SNate Lawson #include <sys/sbuf.h>
47eeb3a05fSNate Lawson #include <sys/smp.h>
4815e32d5dSMike Smith 
4915e32d5dSMike Smith #include <machine/clock.h>
5015e32d5dSMike Smith #include <machine/resource.h>
51dc750869SNate Lawson #include <machine/bus.h>
52dc750869SNate Lawson #include <sys/rman.h>
53bc0f2195SMike Smith #include <isa/isavar.h>
54bc0f2195SMike Smith 
5515e32d5dSMike Smith #include "acpi.h"
5615e32d5dSMike Smith #include <dev/acpica/acpivar.h>
5715e32d5dSMike Smith #include <dev/acpica/acpiio.h>
589b937d48SNate Lawson #include <contrib/dev/acpica/acnamesp.h>
5915e32d5dSMike Smith 
6015e32d5dSMike Smith MALLOC_DEFINE(M_ACPIDEV, "acpidev", "ACPI devices");
6115e32d5dSMike Smith 
62be2b1797SNate Lawson /* Hooks for the ACPI CA debugging infrastructure */
63cb9b0d80SMike Smith #define _COMPONENT	ACPI_BUS
64b53f2771SMike Smith ACPI_MODULE_NAME("ACPI")
650ae55423SMike Smith 
6615e32d5dSMike Smith static d_open_t		acpiopen;
6715e32d5dSMike Smith static d_close_t	acpiclose;
6815e32d5dSMike Smith static d_ioctl_t	acpiioctl;
6915e32d5dSMike Smith 
7015e32d5dSMike Smith static struct cdevsw acpi_cdevsw = {
71dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
72dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
737ac40f5fSPoul-Henning Kamp 	.d_open =	acpiopen,
747ac40f5fSPoul-Henning Kamp 	.d_close =	acpiclose,
757ac40f5fSPoul-Henning Kamp 	.d_ioctl =	acpiioctl,
767ac40f5fSPoul-Henning Kamp 	.d_name =	"acpi",
7715e32d5dSMike Smith };
7815e32d5dSMike Smith 
791d073b1dSJohn Baldwin static const char* sleep_state_names[] = {
80b8670bedSMitsuru IWASAKI     "S0", "S1", "S2", "S3", "S4", "S5", "NONE"};
811d073b1dSJohn Baldwin 
822a4ac806SMike Smith /* this has to be static, as the softc is gone when we need it */
832a4ac806SMike Smith static int acpi_off_state = ACPI_STATE_S5;
842a4ac806SMike Smith 
85fc0ea94aSJohn Baldwin #if __FreeBSD_version >= 500000
86cb9b0d80SMike Smith struct mtx	acpi_mutex;
87fc0ea94aSJohn Baldwin #endif
88cb9b0d80SMike Smith 
893184cf5aSNate Lawson struct acpi_quirks {
903184cf5aSNate Lawson     char	*OemId;
913184cf5aSNate Lawson     uint32_t	OemRevision;
923184cf5aSNate Lawson     char	*value;
933184cf5aSNate Lawson };
943184cf5aSNate Lawson 
953184cf5aSNate Lawson #define ACPI_OEM_REV_ANY	0
963184cf5aSNate Lawson 
973184cf5aSNate Lawson static struct acpi_quirks acpi_quirks_table[] = {
983184cf5aSNate Lawson #ifdef notyet
993184cf5aSNate Lawson     /* Bad PCI routing table.  Used on some SuperMicro boards. */
1003184cf5aSNate Lawson     { "PTLTD ", 0x06040000, "pci_link" },
1013184cf5aSNate Lawson #endif
1023184cf5aSNate Lawson 
1033184cf5aSNate Lawson     { NULL, 0, NULL }
1043184cf5aSNate Lawson };
1053184cf5aSNate Lawson 
1066d63101aSMike Smith static int	acpi_modevent(struct module *mod, int event, void *junk);
10715e32d5dSMike Smith static void	acpi_identify(driver_t *driver, device_t parent);
10815e32d5dSMike Smith static int	acpi_probe(device_t dev);
10915e32d5dSMike Smith static int	acpi_attach(device_t dev);
1103184cf5aSNate Lawson static void	acpi_quirks_set(void);
111be2b1797SNate Lawson static device_t	acpi_add_child(device_t bus, int order, const char *name,
112be2b1797SNate Lawson 			int unit);
11315e32d5dSMike Smith static int	acpi_print_child(device_t bus, device_t child);
114be2b1797SNate Lawson static int	acpi_read_ivar(device_t dev, device_t child, int index,
115be2b1797SNate Lawson 			uintptr_t *result);
116be2b1797SNate Lawson static int	acpi_write_ivar(device_t dev, device_t child, int index,
117be2b1797SNate Lawson 			uintptr_t value);
118be2b1797SNate Lawson static int	acpi_set_resource(device_t dev, device_t child, int type,
119be2b1797SNate Lawson 			int rid, u_long start, u_long count);
120be2b1797SNate Lawson static int	acpi_get_resource(device_t dev, device_t child, int type,
121be2b1797SNate Lawson 			int rid, u_long *startp, u_long *countp);
122be2b1797SNate Lawson static struct resource *acpi_alloc_resource(device_t bus, device_t child,
123be2b1797SNate Lawson 			int type, int *rid, u_long start, u_long end,
124be2b1797SNate Lawson 			u_long count, u_int flags);
125be2b1797SNate Lawson static int	acpi_release_resource(device_t bus, device_t child, int type,
126be2b1797SNate Lawson 			int rid, struct resource *r);
1271e4925e8SNate Lawson static uint32_t	acpi_isa_get_logicalid(device_t dev);
1281e4925e8SNate Lawson static int	acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count);
129be2b1797SNate Lawson static int	acpi_isa_pnp_probe(device_t bus, device_t child,
130be2b1797SNate Lawson 			struct isa_pnp_id *ids);
13115e32d5dSMike Smith static void	acpi_probe_children(device_t bus);
132be2b1797SNate Lawson static ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level,
133be2b1797SNate Lawson 			void *context, void **status);
13415e32d5dSMike Smith static void	acpi_shutdown_pre_sync(void *arg, int howto);
13515e32d5dSMike Smith static void	acpi_shutdown_final(void *arg, int howto);
136eeb3a05fSNate Lawson static void	acpi_shutdown_poweroff(void *arg);
13713d4f7baSMitsuru IWASAKI static void	acpi_enable_fixed_events(struct acpi_softc *sc);
13815e32d5dSMike Smith static void	acpi_system_eventhandler_sleep(void *arg, int state);
13915e32d5dSMike Smith static void	acpi_system_eventhandler_wakeup(void *arg, int state);
140d75de536SMitsuru IWASAKI static int	acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS);
1411d073b1dSJohn Baldwin static int	acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS);
142f9390180SMitsuru IWASAKI static int	acpi_pm_func(u_long cmd, void *arg, ...);
143879d6c23STakanori Watanabe static int	acpi_child_location_str_method(device_t acdev, device_t child,
144879d6c23STakanori Watanabe 					       char *buf, size_t buflen);
145879d6c23STakanori Watanabe static int	acpi_child_pnpinfo_str_method(device_t acdev, device_t child,
146879d6c23STakanori Watanabe 					      char *buf, size_t buflen);
147879d6c23STakanori Watanabe 
148879d6c23STakanori Watanabe int
149879d6c23STakanori Watanabe acpi_child_location_str_method(device_t cbdev, device_t child, char *buf,
150879d6c23STakanori Watanabe     size_t buflen)
151879d6c23STakanori Watanabe {
152879d6c23STakanori Watanabe 	struct acpi_device *dinfo= device_get_ivars(child);
153879d6c23STakanori Watanabe 
154879d6c23STakanori Watanabe 	dinfo = device_get_ivars(child);
155879d6c23STakanori Watanabe 	if(dinfo->ad_handle)
156879d6c23STakanori Watanabe 		snprintf(buf, buflen, "path=%s", acpi_name(dinfo->ad_handle));
157879d6c23STakanori Watanabe 	else
158879d6c23STakanori Watanabe 		snprintf(buf, buflen, "magic=unknown");
159879d6c23STakanori Watanabe 	return (0);
160879d6c23STakanori Watanabe }
161879d6c23STakanori Watanabe 
162879d6c23STakanori Watanabe int
163879d6c23STakanori Watanabe acpi_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf,
164879d6c23STakanori Watanabe     size_t buflen)
165879d6c23STakanori Watanabe {
166879d6c23STakanori Watanabe 	struct acpi_device *dinfo = device_get_ivars(child);
167879d6c23STakanori Watanabe 	ACPI_DEVICE_INFO adinfo;
168879d6c23STakanori Watanabe 	ACPI_BUFFER adbuf = {sizeof(adinfo), &adinfo};
169879d6c23STakanori Watanabe 	char * end;
170879d6c23STakanori Watanabe 	int error;
171879d6c23STakanori Watanabe 
172879d6c23STakanori Watanabe 	dinfo = device_get_ivars(child);
173879d6c23STakanori Watanabe 	error = AcpiGetObjectInfo(dinfo->ad_handle, &adbuf);
174879d6c23STakanori Watanabe 
175879d6c23STakanori Watanabe 	if(error)
176879d6c23STakanori Watanabe 		snprintf(buf, buflen, "Unknown");
177879d6c23STakanori Watanabe 	else
178879d6c23STakanori Watanabe 		snprintf(buf, buflen, "_HID=%s _UID=%u",
179879d6c23STakanori Watanabe 			 (adinfo.Valid & ACPI_VALID_HID)?
180879d6c23STakanori Watanabe 			 adinfo.HardwareId.Value : "UNKNOWN",
181879d6c23STakanori Watanabe 			 (unsigned int)((adinfo.Valid & ACPI_VALID_UID)?
182879d6c23STakanori Watanabe 			strtoul(adinfo.UniqueId.Value, &end, 10):0 ));
183879d6c23STakanori Watanabe 
184879d6c23STakanori Watanabe 	return (0);
185879d6c23STakanori Watanabe }
186879d6c23STakanori Watanabe 
187f9390180SMitsuru IWASAKI 
18815e32d5dSMike Smith static device_method_t acpi_methods[] = {
18915e32d5dSMike Smith     /* Device interface */
19015e32d5dSMike Smith     DEVMETHOD(device_identify,		acpi_identify),
19115e32d5dSMike Smith     DEVMETHOD(device_probe,		acpi_probe),
19215e32d5dSMike Smith     DEVMETHOD(device_attach,		acpi_attach),
19356a70eadSNate Lawson     DEVMETHOD(device_detach,		bus_generic_detach),
19415e32d5dSMike Smith     DEVMETHOD(device_shutdown,		bus_generic_shutdown),
19515e32d5dSMike Smith     DEVMETHOD(device_suspend,		bus_generic_suspend),
19615e32d5dSMike Smith     DEVMETHOD(device_resume,		bus_generic_resume),
19715e32d5dSMike Smith 
19815e32d5dSMike Smith     /* Bus interface */
19915e32d5dSMike Smith     DEVMETHOD(bus_add_child,		acpi_add_child),
20015e32d5dSMike Smith     DEVMETHOD(bus_print_child,		acpi_print_child),
20115e32d5dSMike Smith     DEVMETHOD(bus_read_ivar,		acpi_read_ivar),
20215e32d5dSMike Smith     DEVMETHOD(bus_write_ivar,		acpi_write_ivar),
20315e32d5dSMike Smith     DEVMETHOD(bus_set_resource,		acpi_set_resource),
20415e32d5dSMike Smith     DEVMETHOD(bus_get_resource,		acpi_get_resource),
20515e32d5dSMike Smith     DEVMETHOD(bus_alloc_resource,	acpi_alloc_resource),
20615e32d5dSMike Smith     DEVMETHOD(bus_release_resource,	acpi_release_resource),
207879d6c23STakanori Watanabe     DEVMETHOD(bus_child_pnpinfo_str,    acpi_child_pnpinfo_str_method),
208879d6c23STakanori Watanabe     DEVMETHOD(bus_child_location_str,    acpi_child_location_str_method),
20915e32d5dSMike Smith     DEVMETHOD(bus_driver_added,		bus_generic_driver_added),
21015e32d5dSMike Smith     DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
21115e32d5dSMike Smith     DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
21215e32d5dSMike Smith     DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
21315e32d5dSMike Smith     DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
21415e32d5dSMike Smith 
215bc0f2195SMike Smith     /* ISA emulation */
216bc0f2195SMike Smith     DEVMETHOD(isa_pnp_probe,		acpi_isa_pnp_probe),
217bc0f2195SMike Smith 
21815e32d5dSMike Smith     {0, 0}
21915e32d5dSMike Smith };
22015e32d5dSMike Smith 
22115e32d5dSMike Smith static driver_t acpi_driver = {
22215e32d5dSMike Smith     "acpi",
22315e32d5dSMike Smith     acpi_methods,
22415e32d5dSMike Smith     sizeof(struct acpi_softc),
22515e32d5dSMike Smith };
22615e32d5dSMike Smith 
2273273b005SMike Smith static devclass_t acpi_devclass;
2286d63101aSMike Smith DRIVER_MODULE(acpi, nexus, acpi_driver, acpi_devclass, acpi_modevent, 0);
229dde24897SMike Smith MODULE_VERSION(acpi, 100);
23015e32d5dSMike Smith 
2311d7b121cSNate Lawson SYSCTL_NODE(_debug, OID_AUTO, acpi, CTLFLAG_RW, NULL, "ACPI debugging");
2321d7b121cSNate Lawson static char acpi_ca_version[12];
2331d7b121cSNate Lawson SYSCTL_STRING(_debug_acpi, OID_AUTO, acpi_ca_version, CTLFLAG_RD,
2341d7b121cSNate Lawson 	      acpi_ca_version, 0, "Version of Intel ACPI-CA");
23515e32d5dSMike Smith 
23615e32d5dSMike Smith /*
237413081d7SNate Lawson  * Allow override of whether methods execute in parallel or not.
238413081d7SNate Lawson  * Default to serial behavior as this fixes some AE_ALREADY_EXISTS errors
239413081d7SNate Lawson  * and matches the MS interpreter.
240413081d7SNate Lawson  */
241413081d7SNate Lawson static int acpi_serialize_methods = 1;
242413081d7SNate Lawson TUNABLE_INT("hw.acpi.serialize_methods", &acpi_serialize_methods);
243413081d7SNate Lawson 
244413081d7SNate Lawson /* Allow override of whether to support the _OSI method. */
245413081d7SNate Lawson static int acpi_osi_method;
246413081d7SNate Lawson TUNABLE_INT("hw.acpi.osi_method", &acpi_osi_method);
247413081d7SNate Lawson 
248413081d7SNate Lawson /*
2496d63101aSMike Smith  * ACPI can only be loaded as a module by the loader; activating it after
2506d63101aSMike Smith  * system bootstrap time is not useful, and can be fatal to the system.
251be2b1797SNate Lawson  * It also cannot be unloaded, since the entire system bus heirarchy hangs
252be2b1797SNate Lawson  * off it.
2536d63101aSMike Smith  */
2546d63101aSMike Smith static int
2556d63101aSMike Smith acpi_modevent(struct module *mod, int event, void *junk)
2566d63101aSMike Smith {
2576d63101aSMike Smith     switch(event) {
2586d63101aSMike Smith     case MOD_LOAD:
25987b45ed5SMitsuru IWASAKI 	if (!cold) {
26087b45ed5SMitsuru IWASAKI 	    printf("The ACPI driver cannot be loaded after boot.\n");
2616d63101aSMike Smith 	    return (EPERM);
26287b45ed5SMitsuru IWASAKI 	}
2636d63101aSMike Smith 	break;
2646d63101aSMike Smith     case MOD_UNLOAD:
265f9390180SMitsuru IWASAKI 	if (!cold && power_pm_get_type() == POWER_PM_TYPE_ACPI)
2666d63101aSMike Smith 	    return (EBUSY);
267f9390180SMitsuru IWASAKI 	break;
2686d63101aSMike Smith     default:
2696d63101aSMike Smith 	break;
2706d63101aSMike Smith     }
2716d63101aSMike Smith     return (0);
2726d63101aSMike Smith }
2736d63101aSMike Smith 
2746d63101aSMike Smith /*
275bbc2815cSJohn Baldwin  * Perform early initialization.
27615e32d5dSMike Smith  */
277bbc2815cSJohn Baldwin ACPI_STATUS
278bbc2815cSJohn Baldwin acpi_Startup(void)
27915e32d5dSMike Smith {
280d62ab2f4SMitsuru IWASAKI #ifdef ACPI_DEBUGGER
281d786139cSMaxime Henrion     char *debugpoint;
28215e32d5dSMike Smith #endif
283bbc2815cSJohn Baldwin     static int error, started = 0;
28415e32d5dSMike Smith 
2851b8c233dSPeter Pentchev     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
2861b8c233dSPeter Pentchev 
287bbc2815cSJohn Baldwin     if (started)
288bbc2815cSJohn Baldwin 	return_VALUE (error);
289bbc2815cSJohn Baldwin     started = 1;
29015e32d5dSMike Smith 
291fc0ea94aSJohn Baldwin #if __FreeBSD_version >= 500000
292be2b1797SNate Lawson     /* Initialise the ACPI mutex */
2936008862bSJohn Baldwin     mtx_init(&acpi_mutex, "ACPI global lock", NULL, MTX_DEF);
294fc0ea94aSJohn Baldwin #endif
295cb9b0d80SMike Smith 
296413081d7SNate Lawson     /*
297413081d7SNate Lawson      * Set the globals from our tunables.  This is needed because ACPI-CA
298413081d7SNate Lawson      * uses UINT8 for some values and we have no tunable_uint8.
299413081d7SNate Lawson      */
300413081d7SNate Lawson     AcpiGbl_AllMethodsSerialized = acpi_serialize_methods;
301413081d7SNate Lawson     AcpiGbl_CreateOsiMethod = acpi_osi_method;
302413081d7SNate Lawson 
303be2b1797SNate Lawson     /* Start up the ACPI CA subsystem. */
304d62ab2f4SMitsuru IWASAKI #ifdef ACPI_DEBUGGER
305d786139cSMaxime Henrion     debugpoint = getenv("debug.acpi.debugger");
306d786139cSMaxime Henrion     if (debugpoint) {
307d786139cSMaxime Henrion 	if (!strcmp(debugpoint, "init"))
30815e32d5dSMike Smith 	    acpi_EnterDebugger();
309d786139cSMaxime Henrion 	freeenv(debugpoint);
310d786139cSMaxime Henrion     }
31115e32d5dSMike Smith #endif
312b53f2771SMike Smith     if (ACPI_FAILURE(error = AcpiInitializeSubsystem())) {
313bfae45aaSMike Smith 	printf("ACPI: initialisation failed: %s\n", AcpiFormatException(error));
314bbc2815cSJohn Baldwin 	return_VALUE (error);
31515e32d5dSMike Smith     }
316d62ab2f4SMitsuru IWASAKI #ifdef ACPI_DEBUGGER
317d786139cSMaxime Henrion     debugpoint = getenv("debug.acpi.debugger");
318d786139cSMaxime Henrion     if (debugpoint) {
319d786139cSMaxime Henrion 	if (!strcmp(debugpoint, "tables"))
32015e32d5dSMike Smith 	    acpi_EnterDebugger();
321d786139cSMaxime Henrion 	freeenv(debugpoint);
322d786139cSMaxime Henrion     }
32315e32d5dSMike Smith #endif
3241611ea87SMitsuru IWASAKI 
325b53f2771SMike Smith     if (ACPI_FAILURE(error = AcpiLoadTables())) {
326bfae45aaSMike Smith 	printf("ACPI: table load failed: %s\n", AcpiFormatException(error));
327bbc2815cSJohn Baldwin 	return_VALUE(error);
32815e32d5dSMike Smith     }
3293184cf5aSNate Lawson 
3303184cf5aSNate Lawson     /* Set up any quirks we have for this XSDT. */
3313184cf5aSNate Lawson     acpi_quirks_set();
3324e376d58SNate Lawson     if (acpi_disabled("acpi"))
3334e376d58SNate Lawson 	return_VALUE (AE_ERROR);
3343184cf5aSNate Lawson 
335bbc2815cSJohn Baldwin     return_VALUE (AE_OK);
336bbc2815cSJohn Baldwin }
337bbc2815cSJohn Baldwin 
338bbc2815cSJohn Baldwin /*
339bbc2815cSJohn Baldwin  * Detect ACPI, perform early initialisation
340bbc2815cSJohn Baldwin  */
341bbc2815cSJohn Baldwin static void
342bbc2815cSJohn Baldwin acpi_identify(driver_t *driver, device_t parent)
343bbc2815cSJohn Baldwin {
344bbc2815cSJohn Baldwin     device_t	child;
345bbc2815cSJohn Baldwin 
346bbc2815cSJohn Baldwin     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
347bbc2815cSJohn Baldwin 
348bbc2815cSJohn Baldwin     if (!cold)
349bbc2815cSJohn Baldwin 	return_VOID;
350bbc2815cSJohn Baldwin 
351bbc2815cSJohn Baldwin     /* Check that we haven't been disabled with a hint. */
352bbc2815cSJohn Baldwin     if (resource_disabled("acpi", 0))
353bbc2815cSJohn Baldwin 	return_VOID;
354bbc2815cSJohn Baldwin 
355bbc2815cSJohn Baldwin     /* Make sure we're not being doubly invoked. */
356bbc2815cSJohn Baldwin     if (device_find_child(parent, "acpi", 0) != NULL)
357bbc2815cSJohn Baldwin 	return_VOID;
358bbc2815cSJohn Baldwin 
359bbc2815cSJohn Baldwin     /* Initialize ACPI-CA. */
360bbc2815cSJohn Baldwin     if (ACPI_FAILURE(acpi_Startup()))
361bbc2815cSJohn Baldwin 	return_VOID;
36215e32d5dSMike Smith 
3634e376d58SNate Lawson     snprintf(acpi_ca_version, sizeof(acpi_ca_version), "%#x", ACPI_CA_VERSION);
3644e376d58SNate Lawson 
365be2b1797SNate Lawson     /* Attach the actual ACPI device. */
36615e32d5dSMike Smith     if ((child = BUS_ADD_CHILD(parent, 0, "acpi", 0)) == NULL) {
36715e32d5dSMike Smith 	device_printf(parent, "ACPI: could not attach\n");
3680ae55423SMike Smith 	return_VOID;
36915e32d5dSMike Smith     }
37015e32d5dSMike Smith }
37115e32d5dSMike Smith 
37215e32d5dSMike Smith /*
37315e32d5dSMike Smith  * Fetch some descriptive data from ACPI to put in our attach message
37415e32d5dSMike Smith  */
37515e32d5dSMike Smith static int
37615e32d5dSMike Smith acpi_probe(device_t dev)
37715e32d5dSMike Smith {
37815e32d5dSMike Smith     ACPI_TABLE_HEADER	th;
37915e32d5dSMike Smith     char		buf[20];
38015e32d5dSMike Smith     int			error;
3812ccd1cacSNate Lawson     struct sbuf		sb;
3822ccd1cacSNate Lawson     ACPI_STATUS		status;
383fc0ea94aSJohn Baldwin     ACPI_LOCK_DECL;
38415e32d5dSMike Smith 
385b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
386f9390180SMitsuru IWASAKI 
387f9390180SMitsuru IWASAKI     if (power_pm_get_type() != POWER_PM_TYPE_NONE &&
388f9390180SMitsuru IWASAKI 	power_pm_get_type() != POWER_PM_TYPE_ACPI) {
389be2b1797SNate Lawson 
390f9390180SMitsuru IWASAKI 	device_printf(dev, "Other PM system enabled.\n");
391f9390180SMitsuru IWASAKI 	return_VALUE(ENXIO);
392f9390180SMitsuru IWASAKI     }
393f9390180SMitsuru IWASAKI 
394cb9b0d80SMike Smith     ACPI_LOCK;
3950ae55423SMike Smith 
396b53f2771SMike Smith     if (ACPI_FAILURE(status = AcpiGetTableHeader(ACPI_TABLE_XSDT, 1, &th))) {
397be2b1797SNate Lawson 	device_printf(dev, "couldn't get XSDT header: %s\n",
398be2b1797SNate Lawson 		      AcpiFormatException(status));
399cb9b0d80SMike Smith 	error = ENXIO;
400cb9b0d80SMike Smith     } else {
4012ccd1cacSNate Lawson 	sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
4022ccd1cacSNate Lawson 	sbuf_bcat(&sb, th.OemId, 6);
4032ccd1cacSNate Lawson 	sbuf_trim(&sb);
4042ccd1cacSNate Lawson 	sbuf_putc(&sb, ' ');
4052ccd1cacSNate Lawson 	sbuf_bcat(&sb, th.OemTableId, 8);
4062ccd1cacSNate Lawson 	sbuf_trim(&sb);
4072ccd1cacSNate Lawson 	sbuf_finish(&sb);
4082ccd1cacSNate Lawson 	device_set_desc_copy(dev, sbuf_data(&sb));
4092ccd1cacSNate Lawson 	sbuf_delete(&sb);
410cb9b0d80SMike Smith 	error = 0;
411cb9b0d80SMike Smith     }
412cb9b0d80SMike Smith     ACPI_UNLOCK;
413cb9b0d80SMike Smith     return_VALUE(error);
41415e32d5dSMike Smith }
41515e32d5dSMike Smith 
41615e32d5dSMike Smith static int
41715e32d5dSMike Smith acpi_attach(device_t dev)
41815e32d5dSMike Smith {
41915e32d5dSMike Smith     struct acpi_softc	*sc;
420cb9b0d80SMike Smith     ACPI_STATUS		status;
42115e32d5dSMike Smith     int			error;
42232d18aa5SMike Smith     UINT32		flags;
423498d464fSMitsuru IWASAKI     char		*env;
424d62ab2f4SMitsuru IWASAKI #ifdef ACPI_DEBUGGER
425d786139cSMaxime Henrion     char		*debugpoint;
42615e32d5dSMike Smith #endif
427fc0ea94aSJohn Baldwin     ACPI_LOCK_DECL;
42815e32d5dSMike Smith 
429b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
430cb9b0d80SMike Smith     ACPI_LOCK;
43115e32d5dSMike Smith     sc = device_get_softc(dev);
43215e32d5dSMike Smith     bzero(sc, sizeof(*sc));
43315e32d5dSMike Smith     sc->acpi_dev = dev;
43415e32d5dSMike Smith 
435d62ab2f4SMitsuru IWASAKI #ifdef ACPI_DEBUGGER
436d786139cSMaxime Henrion     debugpoint = getenv("debug.acpi.debugger");
437d786139cSMaxime Henrion     if (debugpoint) {
438d786139cSMaxime Henrion 	if (!strcmp(debugpoint, "spaces"))
43915e32d5dSMike Smith 	    acpi_EnterDebugger();
440d786139cSMaxime Henrion 	freeenv(debugpoint);
441d786139cSMaxime Henrion     }
44215e32d5dSMike Smith #endif
44315e32d5dSMike Smith 
444be2b1797SNate Lawson     /* Install the default address space handlers. */
445cb9b0d80SMike Smith     error = ENXIO;
446be2b1797SNate Lawson     status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
447be2b1797SNate Lawson 		ACPI_ADR_SPACE_SYSTEM_MEMORY, ACPI_DEFAULT_HANDLER, NULL, NULL);
448be2b1797SNate Lawson     if (ACPI_FAILURE(status)) {
449be2b1797SNate Lawson 	device_printf(dev, "Could not initialise SystemMemory handler: %s\n",
450be2b1797SNate Lawson 		      AcpiFormatException(status));
451cb9b0d80SMike Smith 	goto out;
45215e32d5dSMike Smith     }
453be2b1797SNate Lawson     status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
454be2b1797SNate Lawson 		ACPI_ADR_SPACE_SYSTEM_IO, ACPI_DEFAULT_HANDLER, NULL, NULL);
455be2b1797SNate Lawson     if (ACPI_FAILURE(status)) {
456be2b1797SNate Lawson 	device_printf(dev, "Could not initialise SystemIO handler: %s\n",
457be2b1797SNate Lawson 		      AcpiFormatException(status));
458cb9b0d80SMike Smith 	goto out;
45915e32d5dSMike Smith     }
460be2b1797SNate Lawson     status = AcpiInstallAddressSpaceHandler(ACPI_ROOT_OBJECT,
461be2b1797SNate Lawson 		ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
462be2b1797SNate Lawson     if (ACPI_FAILURE(status)) {
463be2b1797SNate Lawson 	device_printf(dev, "could not initialise PciConfig handler: %s\n",
464be2b1797SNate Lawson 		      AcpiFormatException(status));
465cb9b0d80SMike Smith 	goto out;
46615e32d5dSMike Smith     }
46715e32d5dSMike Smith 
46815e32d5dSMike Smith     /*
46915e32d5dSMike Smith      * Bring ACPI fully online.
47015e32d5dSMike Smith      *
471be2b1797SNate Lawson      * Note that some systems (specifically, those with namespace evaluation
472be2b1797SNate Lawson      * issues that require the avoidance of parts of the namespace) must
473be2b1797SNate Lawson      * avoid running _INI and _STA on everything, as well as dodging the final
474be2b1797SNate Lawson      * object init pass.
47515e32d5dSMike Smith      *
47632d18aa5SMike Smith      * For these devices, we set ACPI_NO_DEVICE_INIT and ACPI_NO_OBJECT_INIT).
47732d18aa5SMike Smith      *
478be2b1797SNate Lawson      * XXX We should arrange for the object init pass after we have attached
479be2b1797SNate Lawson      *     all our child devices, but on many systems it works here.
48015e32d5dSMike Smith      */
481d62ab2f4SMitsuru IWASAKI #ifdef ACPI_DEBUGGER
482d786139cSMaxime Henrion     debugpoint = getenv("debug.acpi.debugger");
483d786139cSMaxime Henrion     if (debugpoint) {
484d786139cSMaxime Henrion 	if (!strcmp(debugpoint, "enable"))
48515e32d5dSMike Smith 	    acpi_EnterDebugger();
486d786139cSMaxime Henrion 	freeenv(debugpoint);
487d786139cSMaxime Henrion     }
48815e32d5dSMike Smith #endif
48932d18aa5SMike Smith     flags = 0;
490d786139cSMaxime Henrion     if (testenv("debug.acpi.avoid"))
49132d18aa5SMike Smith 	flags = ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT;
492b53f2771SMike Smith     if (ACPI_FAILURE(status = AcpiEnableSubsystem(flags))) {
493be2b1797SNate Lawson 	device_printf(dev, "Could not enable ACPI: %s\n",
494be2b1797SNate Lawson 		      AcpiFormatException(status));
495cb9b0d80SMike Smith 	goto out;
49615e32d5dSMike Smith     }
49715e32d5dSMike Smith 
498f8335e3aSNate Lawson     /*
499f8335e3aSNate Lawson      * Call the ECDT probe function to provide EC functionality before
500f8335e3aSNate Lawson      * the namespace has been evaluated.
501f8335e3aSNate Lawson      */
502f8335e3aSNate Lawson     acpi_ec_ecdt_probe(dev);
503f8335e3aSNate Lawson 
504b69ed3f4SMitsuru IWASAKI     if (ACPI_FAILURE(status = AcpiInitializeObjects(flags))) {
505be2b1797SNate Lawson 	device_printf(dev, "Could not initialize ACPI objects: %s\n",
506be2b1797SNate Lawson 		      AcpiFormatException(status));
507b69ed3f4SMitsuru IWASAKI 	goto out;
508b69ed3f4SMitsuru IWASAKI     }
509b69ed3f4SMitsuru IWASAKI 
51015e32d5dSMike Smith     /*
5111d073b1dSJohn Baldwin      * Setup our sysctl tree.
5121d073b1dSJohn Baldwin      *
5131d073b1dSJohn Baldwin      * XXX: This doesn't check to make sure that none of these fail.
5141d073b1dSJohn Baldwin      */
5151d073b1dSJohn Baldwin     sysctl_ctx_init(&sc->acpi_sysctl_ctx);
5161d073b1dSJohn Baldwin     sc->acpi_sysctl_tree = SYSCTL_ADD_NODE(&sc->acpi_sysctl_ctx,
5171d073b1dSJohn Baldwin 			       SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
5181d073b1dSJohn Baldwin 			       device_get_name(dev), CTLFLAG_RD, 0, "");
5191d073b1dSJohn Baldwin     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
520d75de536SMitsuru IWASAKI 	OID_AUTO, "supported_sleep_state", CTLTYPE_STRING | CTLFLAG_RD,
521d75de536SMitsuru IWASAKI 	0, 0, acpi_supported_sleep_state_sysctl, "A", "");
522d75de536SMitsuru IWASAKI     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
5231d073b1dSJohn Baldwin 	OID_AUTO, "power_button_state", CTLTYPE_STRING | CTLFLAG_RW,
5241d073b1dSJohn Baldwin 	&sc->acpi_power_button_sx, 0, acpi_sleep_state_sysctl, "A", "");
5251d073b1dSJohn Baldwin     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
5261d073b1dSJohn Baldwin 	OID_AUTO, "sleep_button_state", CTLTYPE_STRING | CTLFLAG_RW,
5271d073b1dSJohn Baldwin 	&sc->acpi_sleep_button_sx, 0, acpi_sleep_state_sysctl, "A", "");
5281d073b1dSJohn Baldwin     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
5291d073b1dSJohn Baldwin 	OID_AUTO, "lid_switch_state", CTLTYPE_STRING | CTLFLAG_RW,
5301d073b1dSJohn Baldwin 	&sc->acpi_lid_switch_sx, 0, acpi_sleep_state_sysctl, "A", "");
531f86214b6SMitsuru IWASAKI     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
532f86214b6SMitsuru IWASAKI 	OID_AUTO, "standby_state", CTLTYPE_STRING | CTLFLAG_RW,
533f86214b6SMitsuru IWASAKI 	&sc->acpi_standby_sx, 0, acpi_sleep_state_sysctl, "A", "");
534f86214b6SMitsuru IWASAKI     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
535f86214b6SMitsuru IWASAKI 	OID_AUTO, "suspend_state", CTLTYPE_STRING | CTLFLAG_RW,
536f86214b6SMitsuru IWASAKI 	&sc->acpi_suspend_sx, 0, acpi_sleep_state_sysctl, "A", "");
5372d644607SMitsuru IWASAKI     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
538ff01efb5SMitsuru IWASAKI 	OID_AUTO, "sleep_delay", CTLFLAG_RD | CTLFLAG_RW,
539ff01efb5SMitsuru IWASAKI 	&sc->acpi_sleep_delay, 0, "sleep delay");
540ff01efb5SMitsuru IWASAKI     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
5411611ea87SMitsuru IWASAKI 	OID_AUTO, "s4bios", CTLFLAG_RD | CTLFLAG_RW,
5421611ea87SMitsuru IWASAKI 	&sc->acpi_s4bios, 0, "S4BIOS mode");
5431611ea87SMitsuru IWASAKI     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
5442d644607SMitsuru IWASAKI 	OID_AUTO, "verbose", CTLFLAG_RD | CTLFLAG_RW,
5452d644607SMitsuru IWASAKI 	&sc->acpi_verbose, 0, "verbose mode");
546c6a78e98STakanori Watanabe     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
547c6a78e98STakanori Watanabe 	OID_AUTO, "disable_on_poweroff", CTLFLAG_RD | CTLFLAG_RW,
548c6a78e98STakanori Watanabe 	&sc->acpi_disable_on_poweroff, 0, "ACPI subsystem disable on poweroff");
549bf0c18ecSNate Lawson 
550bf0c18ecSNate Lawson     /*
551bf0c18ecSNate Lawson      * Default to 5 seconds before sleeping to give some machines time to
552bf0c18ecSNate Lawson      * stabilize.
553bf0c18ecSNate Lawson      */
554bf0c18ecSNate Lawson     sc->acpi_sleep_delay = 5;
555c6a78e98STakanori Watanabe     sc->acpi_disable_on_poweroff = 1;
5562d644607SMitsuru IWASAKI     if (bootverbose)
5572d644607SMitsuru IWASAKI 	sc->acpi_verbose = 1;
558498d464fSMitsuru IWASAKI     if ((env = getenv("hw.acpi.verbose")) && strcmp(env, "0")) {
559498d464fSMitsuru IWASAKI 	sc->acpi_verbose = 1;
560498d464fSMitsuru IWASAKI 	freeenv(env);
561498d464fSMitsuru IWASAKI     }
5621d073b1dSJohn Baldwin 
5632d610c46SNate Lawson     /* Only enable S4BIOS by default if the FACS says it is available. */
5642d610c46SNate Lawson     if (AcpiGbl_FACS->S4Bios_f != 0)
5652d610c46SNate Lawson 	    sc->acpi_s4bios = 1;
5662d610c46SNate Lawson 
5671d073b1dSJohn Baldwin     /*
56815e32d5dSMike Smith      * Dispatch the default sleep state to devices.
56915e32d5dSMike Smith      * TBD: should be configured from userland policy manager.
57015e32d5dSMike Smith      */
57115e32d5dSMike Smith     sc->acpi_power_button_sx = ACPI_POWER_BUTTON_DEFAULT_SX;
57215e32d5dSMike Smith     sc->acpi_sleep_button_sx = ACPI_SLEEP_BUTTON_DEFAULT_SX;
57315e32d5dSMike Smith     sc->acpi_lid_switch_sx = ACPI_LID_SWITCH_DEFAULT_SX;
574f86214b6SMitsuru IWASAKI     sc->acpi_standby_sx = ACPI_STATE_S1;
575f86214b6SMitsuru IWASAKI     sc->acpi_suspend_sx = ACPI_STATE_S3;
57615e32d5dSMike Smith 
57713d4f7baSMitsuru IWASAKI     acpi_enable_fixed_events(sc);
57815e32d5dSMike Smith 
57915e32d5dSMike Smith     /*
58015e32d5dSMike Smith      * Scan the namespace and attach/initialise children.
58115e32d5dSMike Smith      */
582d62ab2f4SMitsuru IWASAKI #ifdef ACPI_DEBUGGER
583d786139cSMaxime Henrion     debugpoint = getenv("debug.acpi.debugger");
584d786139cSMaxime Henrion     if (debugpoint) {
585d786139cSMaxime Henrion 	if (!strcmp(debugpoint, "probe"))
58615e32d5dSMike Smith 	    acpi_EnterDebugger();
587d786139cSMaxime Henrion 	freeenv(debugpoint);
588d786139cSMaxime Henrion     }
58915e32d5dSMike Smith #endif
59015e32d5dSMike Smith 
591be2b1797SNate Lawson     /* Register our shutdown handlers */
592be2b1797SNate Lawson     EVENTHANDLER_REGISTER(shutdown_pre_sync, acpi_shutdown_pre_sync, sc,
593be2b1797SNate Lawson 	SHUTDOWN_PRI_LAST);
594be2b1797SNate Lawson     EVENTHANDLER_REGISTER(shutdown_final, acpi_shutdown_final, sc,
595be2b1797SNate Lawson 	SHUTDOWN_PRI_LAST);
59615e32d5dSMike Smith 
59715e32d5dSMike Smith     /*
59815e32d5dSMike Smith      * Register our acpi event handlers.
59915e32d5dSMike Smith      * XXX should be configurable eg. via userland policy manager.
60015e32d5dSMike Smith      */
601be2b1797SNate Lawson     EVENTHANDLER_REGISTER(acpi_sleep_event, acpi_system_eventhandler_sleep,
602be2b1797SNate Lawson 	sc, ACPI_EVENT_PRI_LAST);
603be2b1797SNate Lawson     EVENTHANDLER_REGISTER(acpi_wakeup_event, acpi_system_eventhandler_wakeup,
604be2b1797SNate Lawson 	sc, ACPI_EVENT_PRI_LAST);
60515e32d5dSMike Smith 
606be2b1797SNate Lawson     /* Flag our initial states. */
60715e32d5dSMike Smith     sc->acpi_enabled = 1;
60815e32d5dSMike Smith     sc->acpi_sstate = ACPI_STATE_S0;
609ece50487SMitsuru IWASAKI     sc->acpi_sleep_disabled = 0;
61015e32d5dSMike Smith 
611be2b1797SNate Lawson     /* Create the control device */
612a89fcf28STakanori Watanabe     sc->acpi_dev_t = make_dev(&acpi_cdevsw, 0, UID_ROOT, GID_WHEEL, 0644,
6132a4689e8SRobert Watson 			      "acpi");
61415e32d5dSMike Smith     sc->acpi_dev_t->si_drv1 = sc;
61515e32d5dSMike Smith 
616d62ab2f4SMitsuru IWASAKI #ifdef ACPI_DEBUGGER
617d786139cSMaxime Henrion     debugpoint = getenv("debug.acpi.debugger");
618d786139cSMaxime Henrion     if (debugpoint) {
619be2b1797SNate Lawson 	if (strcmp(debugpoint, "running") == 0)
62015e32d5dSMike Smith 	    acpi_EnterDebugger();
621d786139cSMaxime Henrion 	freeenv(debugpoint);
622d786139cSMaxime Henrion     }
62315e32d5dSMike Smith #endif
624f86214b6SMitsuru IWASAKI 
62591da7c40SMitsuru IWASAKI #ifdef ACPI_USE_THREADS
626be2b1797SNate Lawson     if ((error = acpi_task_thread_init()))
627c573e654SMitsuru IWASAKI 	goto out;
628c573e654SMitsuru IWASAKI #endif
629c573e654SMitsuru IWASAKI 
630be2b1797SNate Lawson     if ((error = acpi_machdep_init(dev)))
631f86214b6SMitsuru IWASAKI 	goto out;
632f86214b6SMitsuru IWASAKI 
633f9390180SMitsuru IWASAKI     /* Register ACPI again to pass the correct argument of pm_func. */
634f9390180SMitsuru IWASAKI     power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, sc);
635f9390180SMitsuru IWASAKI 
636eeb6dba2SJohn Baldwin     if (!acpi_disabled("bus"))
637eeb6dba2SJohn Baldwin 	acpi_probe_children(dev);
638eeb6dba2SJohn Baldwin 
639cb9b0d80SMike Smith     error = 0;
640cb9b0d80SMike Smith 
641cb9b0d80SMike Smith  out:
642cb9b0d80SMike Smith     ACPI_UNLOCK;
643cb9b0d80SMike Smith     return_VALUE (error);
64415e32d5dSMike Smith }
64515e32d5dSMike Smith 
6463184cf5aSNate Lawson static void
6473184cf5aSNate Lawson acpi_quirks_set()
6483184cf5aSNate Lawson {
6493184cf5aSNate Lawson     XSDT_DESCRIPTOR *xsdt;
6503184cf5aSNate Lawson     struct acpi_quirks *quirk;
6513184cf5aSNate Lawson     char *env, *tmp;
6523184cf5aSNate Lawson     int len;
6533184cf5aSNate Lawson 
6544e376d58SNate Lawson     /*
6554e376d58SNate Lawson      * If the user loaded a custom table or disabled "quirks", leave
6564e376d58SNate Lawson      * the settings alone.
6574e376d58SNate Lawson      */
6583184cf5aSNate Lawson     len = 0;
6594e376d58SNate Lawson     if ((env = getenv("acpi_dsdt_load")) != NULL) {
6604e376d58SNate Lawson 	/* XXX No strcasecmp but this is good enough. */
6614e376d58SNate Lawson 	if (*env == 'Y' || *env == 'y')
6624e376d58SNate Lawson 	    goto out;
6634e376d58SNate Lawson 	freeenv(env);
6644e376d58SNate Lawson     }
6653184cf5aSNate Lawson     if ((env = getenv("debug.acpi.disabled")) != NULL) {
6664e376d58SNate Lawson 	if (strstr("quirks", env) != NULL)
6673184cf5aSNate Lawson 	    goto out;
6683184cf5aSNate Lawson 	len = strlen(env);
6693184cf5aSNate Lawson     }
6703184cf5aSNate Lawson 
6713184cf5aSNate Lawson     /*
6723184cf5aSNate Lawson      * Search through our quirk table and concatenate the disabled
6733184cf5aSNate Lawson      * values with whatever we find.
6743184cf5aSNate Lawson      */
6753184cf5aSNate Lawson     xsdt = AcpiGbl_XSDT;
6763184cf5aSNate Lawson     for (quirk = acpi_quirks_table; quirk->OemId; quirk++) {
6773184cf5aSNate Lawson 	if (!strncmp(xsdt->OemId, quirk->OemId, strlen(quirk->OemId)) &&
6783184cf5aSNate Lawson 	    (xsdt->OemRevision == quirk->OemRevision ||
6793184cf5aSNate Lawson 	    quirk->OemRevision == ACPI_OEM_REV_ANY)) {
6803184cf5aSNate Lawson 		len += strlen(quirk->value) + 2;
6813184cf5aSNate Lawson 		if ((tmp = malloc(len, M_TEMP, M_NOWAIT)) == NULL)
6823184cf5aSNate Lawson 		    goto out;
6833184cf5aSNate Lawson 		sprintf(tmp, "%s %s", env ? env : "", quirk->value);
6843184cf5aSNate Lawson 		setenv("debug.acpi.disabled", tmp);
6853184cf5aSNate Lawson 		free(tmp, M_TEMP);
6863184cf5aSNate Lawson 		break;
6873184cf5aSNate Lawson 	}
6883184cf5aSNate Lawson     }
6893184cf5aSNate Lawson 
6903184cf5aSNate Lawson out:
6913184cf5aSNate Lawson     if (env)
6923184cf5aSNate Lawson 	freeenv(env);
6933184cf5aSNate Lawson }
6943184cf5aSNate Lawson 
69515e32d5dSMike Smith /*
69615e32d5dSMike Smith  * Handle a new device being added
69715e32d5dSMike Smith  */
69815e32d5dSMike Smith static device_t
69915e32d5dSMike Smith acpi_add_child(device_t bus, int order, const char *name, int unit)
70015e32d5dSMike Smith {
70115e32d5dSMike Smith     struct acpi_device	*ad;
70215e32d5dSMike Smith     device_t		child;
70315e32d5dSMike Smith 
704be2b1797SNate Lawson     if ((ad = malloc(sizeof(*ad), M_ACPIDEV, M_NOWAIT | M_ZERO)) == NULL)
70515e32d5dSMike Smith 	return (NULL);
70615e32d5dSMike Smith 
70715e32d5dSMike Smith     resource_list_init(&ad->ad_rl);
70815e32d5dSMike Smith 
70915e32d5dSMike Smith     child = device_add_child_ordered(bus, order, name, unit);
71015e32d5dSMike Smith     if (child != NULL)
71115e32d5dSMike Smith 	device_set_ivars(child, ad);
71215e32d5dSMike Smith     return (child);
71315e32d5dSMike Smith }
71415e32d5dSMike Smith 
71515e32d5dSMike Smith static int
71615e32d5dSMike Smith acpi_print_child(device_t bus, device_t child)
71715e32d5dSMike Smith {
71815e32d5dSMike Smith     struct acpi_device	 *adev = device_get_ivars(child);
71915e32d5dSMike Smith     struct resource_list *rl = &adev->ad_rl;
72015e32d5dSMike Smith     int retval = 0;
72115e32d5dSMike Smith 
72215e32d5dSMike Smith     retval += bus_print_child_header(bus, child);
7239ed79ecaSJohn Baldwin     retval += resource_list_print_type(rl, "port",  SYS_RES_IOPORT, "%#lx");
7249ed79ecaSJohn Baldwin     retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
7259ed79ecaSJohn Baldwin     retval += resource_list_print_type(rl, "irq",   SYS_RES_IRQ,    "%ld");
7269ed79ecaSJohn Baldwin     retval += resource_list_print_type(rl, "drq",   SYS_RES_DRQ,    "%ld");
72715e32d5dSMike Smith     retval += bus_print_child_footer(bus, child);
72815e32d5dSMike Smith 
72915e32d5dSMike Smith     return (retval);
73015e32d5dSMike Smith }
73115e32d5dSMike Smith 
73215e32d5dSMike Smith /*
73315e32d5dSMike Smith  * Handle per-device ivars
73415e32d5dSMike Smith  */
73515e32d5dSMike Smith static int
73615e32d5dSMike Smith acpi_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
73715e32d5dSMike Smith {
73815e32d5dSMike Smith     struct acpi_device	*ad;
73915e32d5dSMike Smith 
74015e32d5dSMike Smith     if ((ad = device_get_ivars(child)) == NULL) {
74115e32d5dSMike Smith 	printf("device has no ivars\n");
74215e32d5dSMike Smith 	return (ENOENT);
74315e32d5dSMike Smith     }
74415e32d5dSMike Smith 
745be2b1797SNate Lawson     /* ACPI and ISA compatibility ivars */
74615e32d5dSMike Smith     switch(index) {
74715e32d5dSMike Smith     case ACPI_IVAR_HANDLE:
74815e32d5dSMike Smith 	*(ACPI_HANDLE *)result = ad->ad_handle;
74915e32d5dSMike Smith 	break;
75015e32d5dSMike Smith     case ACPI_IVAR_MAGIC:
75115e32d5dSMike Smith 	*(int *)result = ad->ad_magic;
75215e32d5dSMike Smith 	break;
75315e32d5dSMike Smith     case ACPI_IVAR_PRIVATE:
75415e32d5dSMike Smith 	*(void **)result = ad->ad_private;
75515e32d5dSMike Smith 	break;
75632d18aa5SMike Smith     case ISA_IVAR_VENDORID:
75732d18aa5SMike Smith     case ISA_IVAR_SERIAL:
75832d18aa5SMike Smith     case ISA_IVAR_COMPATID:
75932d18aa5SMike Smith 	*(int *)result = -1;
76032d18aa5SMike Smith 	break;
76132d18aa5SMike Smith     case ISA_IVAR_LOGICALID:
76232d18aa5SMike Smith 	*(int *)result = acpi_isa_get_logicalid(child);
76332d18aa5SMike Smith 	break;
76415e32d5dSMike Smith     default:
76515e32d5dSMike Smith 	return (ENOENT);
76615e32d5dSMike Smith     }
767be2b1797SNate Lawson 
76815e32d5dSMike Smith     return (0);
76915e32d5dSMike Smith }
77015e32d5dSMike Smith 
77115e32d5dSMike Smith static int
77215e32d5dSMike Smith acpi_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
77315e32d5dSMike Smith {
77415e32d5dSMike Smith     struct acpi_device	*ad;
77515e32d5dSMike Smith 
77615e32d5dSMike Smith     if ((ad = device_get_ivars(child)) == NULL) {
77715e32d5dSMike Smith 	printf("device has no ivars\n");
77815e32d5dSMike Smith 	return (ENOENT);
77915e32d5dSMike Smith     }
78015e32d5dSMike Smith 
78115e32d5dSMike Smith     switch(index) {
78215e32d5dSMike Smith     case ACPI_IVAR_HANDLE:
78315e32d5dSMike Smith 	ad->ad_handle = (ACPI_HANDLE)value;
78415e32d5dSMike Smith 	break;
78515e32d5dSMike Smith     case ACPI_IVAR_MAGIC:
78615e32d5dSMike Smith 	ad->ad_magic = (int)value;
78715e32d5dSMike Smith 	break;
78815e32d5dSMike Smith     case ACPI_IVAR_PRIVATE:
78915e32d5dSMike Smith 	ad->ad_private = (void *)value;
79015e32d5dSMike Smith 	break;
79115e32d5dSMike Smith     default:
7922ab060eeSWarner Losh 	panic("bad ivar write request (%d)", index);
79315e32d5dSMike Smith 	return (ENOENT);
79415e32d5dSMike Smith     }
795be2b1797SNate Lawson 
79615e32d5dSMike Smith     return (0);
79715e32d5dSMike Smith }
79815e32d5dSMike Smith 
799be2b1797SNate Lawson ACPI_HANDLE
800be2b1797SNate Lawson acpi_get_handle(device_t dev)
801be2b1797SNate Lawson {
802be2b1797SNate Lawson     uintptr_t up;
803be2b1797SNate Lawson     ACPI_HANDLE	h;
804be2b1797SNate Lawson 
805be2b1797SNate Lawson     if (BUS_READ_IVAR(device_get_parent(dev), dev, ACPI_IVAR_HANDLE, &up))
806be2b1797SNate Lawson 	return(NULL);
807be2b1797SNate Lawson     h = (ACPI_HANDLE)up;
808be2b1797SNate Lawson     return (h);
809be2b1797SNate Lawson }
810be2b1797SNate Lawson 
811be2b1797SNate Lawson int
812be2b1797SNate Lawson acpi_set_handle(device_t dev, ACPI_HANDLE h)
813be2b1797SNate Lawson {
814be2b1797SNate Lawson     uintptr_t up;
815be2b1797SNate Lawson 
816be2b1797SNate Lawson     up = (uintptr_t)h;
817be2b1797SNate Lawson     return (BUS_WRITE_IVAR(device_get_parent(dev), dev, ACPI_IVAR_HANDLE, up));
818be2b1797SNate Lawson }
819be2b1797SNate Lawson 
820be2b1797SNate Lawson int
821be2b1797SNate Lawson acpi_get_magic(device_t dev)
822be2b1797SNate Lawson {
823be2b1797SNate Lawson     uintptr_t up;
824be2b1797SNate Lawson     int	m;
825be2b1797SNate Lawson 
826be2b1797SNate Lawson     if (BUS_READ_IVAR(device_get_parent(dev), dev, ACPI_IVAR_MAGIC, &up))
827be2b1797SNate Lawson 	return(0);
828be2b1797SNate Lawson     m = (int)up;
829be2b1797SNate Lawson     return (m);
830be2b1797SNate Lawson }
831be2b1797SNate Lawson 
832be2b1797SNate Lawson int
833be2b1797SNate Lawson acpi_set_magic(device_t dev, int m)
834be2b1797SNate Lawson {
835be2b1797SNate Lawson     uintptr_t up;
836be2b1797SNate Lawson 
837be2b1797SNate Lawson     up = (uintptr_t)m;
838be2b1797SNate Lawson     return (BUS_WRITE_IVAR(device_get_parent(dev), dev, ACPI_IVAR_MAGIC, up));
839be2b1797SNate Lawson }
840be2b1797SNate Lawson 
841be2b1797SNate Lawson void *
842be2b1797SNate Lawson acpi_get_private(device_t dev)
843be2b1797SNate Lawson {
844be2b1797SNate Lawson     uintptr_t up;
845be2b1797SNate Lawson     void *p;
846be2b1797SNate Lawson 
847be2b1797SNate Lawson     if (BUS_READ_IVAR(device_get_parent(dev), dev, ACPI_IVAR_PRIVATE, &up))
848be2b1797SNate Lawson 	return (NULL);
849be2b1797SNate Lawson     p = (void *)up;
850be2b1797SNate Lawson     return (p);
851be2b1797SNate Lawson }
852be2b1797SNate Lawson 
853be2b1797SNate Lawson int
854be2b1797SNate Lawson acpi_set_private(device_t dev, void *p)
855be2b1797SNate Lawson {
856be2b1797SNate Lawson     uintptr_t up;
857be2b1797SNate Lawson 
858be2b1797SNate Lawson     up = (uintptr_t)p;
859be2b1797SNate Lawson     return (BUS_WRITE_IVAR(device_get_parent(dev), dev, ACPI_IVAR_PRIVATE, up));
860be2b1797SNate Lawson }
861be2b1797SNate Lawson 
862be2b1797SNate Lawson ACPI_OBJECT_TYPE
863be2b1797SNate Lawson acpi_get_type(device_t dev)
864be2b1797SNate Lawson {
865be2b1797SNate Lawson     ACPI_HANDLE		h;
866be2b1797SNate Lawson     ACPI_OBJECT_TYPE	t;
867be2b1797SNate Lawson 
868be2b1797SNate Lawson     if ((h = acpi_get_handle(dev)) == NULL)
869be2b1797SNate Lawson 	return (ACPI_TYPE_NOT_FOUND);
870be2b1797SNate Lawson     if (AcpiGetType(h, &t) != AE_OK)
871be2b1797SNate Lawson 	return (ACPI_TYPE_NOT_FOUND);
872be2b1797SNate Lawson     return (t);
873be2b1797SNate Lawson }
874be2b1797SNate Lawson 
87515e32d5dSMike Smith /*
87615e32d5dSMike Smith  * Handle child resource allocation/removal
87715e32d5dSMike Smith  */
87815e32d5dSMike Smith static int
879be2b1797SNate Lawson acpi_set_resource(device_t dev, device_t child, int type, int rid,
880be2b1797SNate Lawson 		  u_long start, u_long count)
88115e32d5dSMike Smith {
88215e32d5dSMike Smith     struct acpi_device		*ad = device_get_ivars(child);
88315e32d5dSMike Smith     struct resource_list	*rl = &ad->ad_rl;
88415e32d5dSMike Smith 
88515e32d5dSMike Smith     resource_list_add(rl, type, rid, start, start + count -1, count);
88615e32d5dSMike Smith 
88715e32d5dSMike Smith     return(0);
88815e32d5dSMike Smith }
88915e32d5dSMike Smith 
89015e32d5dSMike Smith static int
891be2b1797SNate Lawson acpi_get_resource(device_t dev, device_t child, int type, int rid,
892be2b1797SNate Lawson 		  u_long *startp, u_long *countp)
89315e32d5dSMike Smith {
89415e32d5dSMike Smith     struct acpi_device		*ad = device_get_ivars(child);
89515e32d5dSMike Smith     struct resource_list	*rl = &ad->ad_rl;
89615e32d5dSMike Smith     struct resource_list_entry	*rle;
89715e32d5dSMike Smith 
89815e32d5dSMike Smith     rle = resource_list_find(rl, type, rid);
89915e32d5dSMike Smith     if (!rle)
90015e32d5dSMike Smith 	return(ENOENT);
90115e32d5dSMike Smith 
90215e32d5dSMike Smith     if (startp)
90315e32d5dSMike Smith 	*startp = rle->start;
90415e32d5dSMike Smith     if (countp)
90515e32d5dSMike Smith 	*countp = rle->count;
90615e32d5dSMike Smith 
90715e32d5dSMike Smith     return (0);
90815e32d5dSMike Smith }
90915e32d5dSMike Smith 
91015e32d5dSMike Smith static struct resource *
91115e32d5dSMike Smith acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
91215e32d5dSMike Smith 		    u_long start, u_long end, u_long count, u_int flags)
91315e32d5dSMike Smith {
91415e32d5dSMike Smith     struct acpi_device *ad = device_get_ivars(child);
91515e32d5dSMike Smith     struct resource_list *rl = &ad->ad_rl;
91615e32d5dSMike Smith 
917be2b1797SNate Lawson     return (resource_list_alloc(rl, bus, child, type, rid, start, end, count,
918be2b1797SNate Lawson 	    flags));
91915e32d5dSMike Smith }
92015e32d5dSMike Smith 
92115e32d5dSMike Smith static int
92215e32d5dSMike Smith acpi_release_resource(device_t bus, device_t child, int type, int rid, struct resource *r)
92315e32d5dSMike Smith {
92415e32d5dSMike Smith     struct acpi_device *ad = device_get_ivars(child);
92515e32d5dSMike Smith     struct resource_list *rl = &ad->ad_rl;
92615e32d5dSMike Smith 
92715e32d5dSMike Smith     return (resource_list_release(rl, bus, child, type, rid, r));
92815e32d5dSMike Smith }
92915e32d5dSMike Smith 
930dc750869SNate Lawson /* Allocate an IO port or memory resource, given its GAS. */
931dc750869SNate Lawson struct resource *
932dc750869SNate Lawson acpi_bus_alloc_gas(device_t dev, int *rid, ACPI_GENERIC_ADDRESS *gas)
933dc750869SNate Lawson {
934dc750869SNate Lawson     int type;
935dc750869SNate Lawson 
936dc750869SNate Lawson     if (gas == NULL || !ACPI_VALID_ADDRESS(gas->Address) ||
937dc750869SNate Lawson 	gas->RegisterBitWidth < 8)
938dc750869SNate Lawson 	return (NULL);
939dc750869SNate Lawson 
940dc750869SNate Lawson     switch (gas->AddressSpaceId) {
941dc750869SNate Lawson     case ACPI_ADR_SPACE_SYSTEM_MEMORY:
942dc750869SNate Lawson 	type = SYS_RES_MEMORY;
943dc750869SNate Lawson 	break;
944dc750869SNate Lawson     case ACPI_ADR_SPACE_SYSTEM_IO:
945dc750869SNate Lawson 	type = SYS_RES_IOPORT;
946dc750869SNate Lawson 	break;
947dc750869SNate Lawson     default:
948dc750869SNate Lawson 	return (NULL);
949dc750869SNate Lawson     }
950dc750869SNate Lawson 
951dc750869SNate Lawson     bus_set_resource(dev, type, *rid, gas->Address, gas->RegisterBitWidth / 8);
9525f96beb9SNate Lawson     return (bus_alloc_resource_any(dev, type, rid, RF_ACTIVE));
953dc750869SNate Lawson }
954dc750869SNate Lawson 
95515e32d5dSMike Smith /*
956bc0f2195SMike Smith  * Handle ISA-like devices probing for a PnP ID to match.
957bc0f2195SMike Smith  */
958bc0f2195SMike Smith #define PNP_EISAID(s)				\
959bc0f2195SMike Smith 	((((s[0] - '@') & 0x1f) << 2)		\
960bc0f2195SMike Smith 	 | (((s[1] - '@') & 0x18) >> 3)		\
961bc0f2195SMike Smith 	 | (((s[1] - '@') & 0x07) << 13)	\
962bc0f2195SMike Smith 	 | (((s[2] - '@') & 0x1f) << 8)		\
963bc0f2195SMike Smith 	 | (PNP_HEXTONUM(s[4]) << 16)		\
964bc0f2195SMike Smith 	 | (PNP_HEXTONUM(s[3]) << 20)		\
965bc0f2195SMike Smith 	 | (PNP_HEXTONUM(s[6]) << 24)		\
966bc0f2195SMike Smith 	 | (PNP_HEXTONUM(s[5]) << 28))
967bc0f2195SMike Smith 
9681e4925e8SNate Lawson static uint32_t
96932d18aa5SMike Smith acpi_isa_get_logicalid(device_t dev)
970bc0f2195SMike Smith {
9711e4925e8SNate Lawson     ACPI_DEVICE_INFO	*devinfo;
9721e4925e8SNate Lawson     ACPI_BUFFER		buf;
973bc0f2195SMike Smith     ACPI_HANDLE		h;
974bc0f2195SMike Smith     ACPI_STATUS		error;
975bc0f2195SMike Smith     u_int32_t		pnpid;
976fc0ea94aSJohn Baldwin     ACPI_LOCK_DECL;
97732d18aa5SMike Smith 
978b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
97932d18aa5SMike Smith 
98032d18aa5SMike Smith     pnpid = 0;
981bd189fe7SNate Lawson     buf.Pointer = NULL;
982bd189fe7SNate Lawson     buf.Length = ACPI_ALLOCATE_BUFFER;
983bd189fe7SNate Lawson 
98432d18aa5SMike Smith     ACPI_LOCK;
98532d18aa5SMike Smith 
9866fca9360SNate Lawson     /* Fetch and validate the HID. */
98732d18aa5SMike Smith     if ((h = acpi_get_handle(dev)) == NULL)
988bd189fe7SNate Lawson 	goto out;
9896fca9360SNate Lawson     error = AcpiGetObjectInfo(h, &buf);
9906fca9360SNate Lawson     if (ACPI_FAILURE(error))
991bd189fe7SNate Lawson 	goto out;
9921e4925e8SNate Lawson     devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
99332d18aa5SMike Smith 
9941e4925e8SNate Lawson     if ((devinfo->Valid & ACPI_VALID_HID) != 0)
9951e4925e8SNate Lawson 	pnpid = PNP_EISAID(devinfo->HardwareId.Value);
996be2b1797SNate Lawson 
997bd189fe7SNate Lawson out:
998bd189fe7SNate Lawson     if (buf.Pointer != NULL)
9991e4925e8SNate Lawson 	AcpiOsFree(buf.Pointer);
100032d18aa5SMike Smith     ACPI_UNLOCK;
100132d18aa5SMike Smith     return_VALUE (pnpid);
100232d18aa5SMike Smith }
100332d18aa5SMike Smith 
10041e4925e8SNate Lawson static int
10051e4925e8SNate Lawson acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count)
1006b2566207STakanori Watanabe {
10071e4925e8SNate Lawson     ACPI_DEVICE_INFO	*devinfo;
10081e4925e8SNate Lawson     ACPI_BUFFER		buf;
1009b2566207STakanori Watanabe     ACPI_HANDLE		h;
1010b2566207STakanori Watanabe     ACPI_STATUS		error;
10111e4925e8SNate Lawson     uint32_t		*pnpid;
10121e4925e8SNate Lawson     int			valid, i;
1013b2566207STakanori Watanabe     ACPI_LOCK_DECL;
1014b2566207STakanori Watanabe 
1015b2566207STakanori Watanabe     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1016b2566207STakanori Watanabe 
10171e4925e8SNate Lawson     pnpid = cids;
10181e4925e8SNate Lawson     valid = 0;
1019bd189fe7SNate Lawson     buf.Pointer = NULL;
1020bd189fe7SNate Lawson     buf.Length = ACPI_ALLOCATE_BUFFER;
1021bd189fe7SNate Lawson 
1022b2566207STakanori Watanabe     ACPI_LOCK;
1023b2566207STakanori Watanabe 
10241e4925e8SNate Lawson     /* Fetch and validate the CID */
1025b2566207STakanori Watanabe     if ((h = acpi_get_handle(dev)) == NULL)
1026bd189fe7SNate Lawson 	goto out;
10271e4925e8SNate Lawson     error = AcpiGetObjectInfo(h, &buf);
10281e4925e8SNate Lawson     if (ACPI_FAILURE(error))
1029bd189fe7SNate Lawson 	goto out;
10301e4925e8SNate Lawson     devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
10311e4925e8SNate Lawson     if ((devinfo->Valid & ACPI_VALID_CID) == 0)
1032b2566207STakanori Watanabe 	goto out;
1033b2566207STakanori Watanabe 
10341e4925e8SNate Lawson     if (devinfo->CompatibilityId.Count < count)
10351e4925e8SNate Lawson 	count = devinfo->CompatibilityId.Count;
10361e4925e8SNate Lawson     for (i = 0; i < count; i++) {
10371e4925e8SNate Lawson 	if (strncmp(devinfo->CompatibilityId.Id[i].Value, "PNP", 3) != 0)
10381e4925e8SNate Lawson 	    continue;
10391e4925e8SNate Lawson 	*pnpid++ = PNP_EISAID(devinfo->CompatibilityId.Id[i].Value);
10401e4925e8SNate Lawson 	valid++;
1041b2566207STakanori Watanabe     }
1042b2566207STakanori Watanabe 
10431e4925e8SNate Lawson out:
1044bd189fe7SNate Lawson     if (buf.Pointer != NULL)
10451e4925e8SNate Lawson 	AcpiOsFree(buf.Pointer);
10461e4925e8SNate Lawson     ACPI_UNLOCK;
10471e4925e8SNate Lawson     return_VALUE (valid);
10481e4925e8SNate Lawson }
1049b2566207STakanori Watanabe 
105032d18aa5SMike Smith static int
105132d18aa5SMike Smith acpi_isa_pnp_probe(device_t bus, device_t child, struct isa_pnp_id *ids)
105232d18aa5SMike Smith {
10531e4925e8SNate Lawson     int			result, cid_count, i;
10541e4925e8SNate Lawson     uint32_t		lid, cids[8];
1055bc0f2195SMike Smith 
1056b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1057bc0f2195SMike Smith 
1058bc0f2195SMike Smith     /*
1059bc0f2195SMike Smith      * ISA-style drivers attached to ACPI may persist and
1060bc0f2195SMike Smith      * probe manually if we return ENOENT.  We never want
1061bc0f2195SMike Smith      * that to happen, so don't ever return it.
1062bc0f2195SMike Smith      */
1063bc0f2195SMike Smith     result = ENXIO;
1064bc0f2195SMike Smith 
1065be2b1797SNate Lawson     /* Scan the supplied IDs for a match */
1066b2566207STakanori Watanabe     lid = acpi_isa_get_logicalid(child);
10671e4925e8SNate Lawson     cid_count = acpi_isa_get_compatid(child, cids, 8);
1068bc0f2195SMike Smith     while (ids && ids->ip_id) {
10691e4925e8SNate Lawson 	if (lid == ids->ip_id) {
1070bc0f2195SMike Smith 	    result = 0;
1071bc0f2195SMike Smith 	    goto out;
1072bc0f2195SMike Smith 	}
10731e4925e8SNate Lawson 	for (i = 0; i < cid_count; i++) {
10741e4925e8SNate Lawson 	    if (cids[i] == ids->ip_id) {
10751e4925e8SNate Lawson 		result = 0;
10761e4925e8SNate Lawson 		goto out;
10771e4925e8SNate Lawson 	    }
10781e4925e8SNate Lawson 	}
1079bc0f2195SMike Smith 	ids++;
1080bc0f2195SMike Smith     }
1081be2b1797SNate Lawson 
1082bc0f2195SMike Smith  out:
1083bc0f2195SMike Smith     return_VALUE (result);
1084bc0f2195SMike Smith }
1085bc0f2195SMike Smith 
1086bc0f2195SMike Smith /*
108715e32d5dSMike Smith  * Scan relevant portions of the ACPI namespace and attach child devices.
108815e32d5dSMike Smith  *
1089be2b1797SNate Lawson  * Note that we only expect to find devices in the \_PR_, \_TZ_, \_SI_ and
1090be2b1797SNate Lawson  * \_SB_ scopes, and \_PR_ and \_TZ_ become obsolete in the ACPI 2.0 spec.
109115e32d5dSMike Smith  */
109215e32d5dSMike Smith static void
109315e32d5dSMike Smith acpi_probe_children(device_t bus)
109415e32d5dSMike Smith {
109515e32d5dSMike Smith     ACPI_HANDLE	parent;
1096be2b1797SNate Lawson     ACPI_STATUS	status;
10977d3bcec9SMike Smith     static char	*scopes[] = {"\\_PR_", "\\_TZ_", "\\_SI", "\\_SB_", NULL};
109815e32d5dSMike Smith     int		i;
109915e32d5dSMike Smith 
1100b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1101cb9b0d80SMike Smith     ACPI_ASSERTLOCK;
11020ae55423SMike Smith 
1103be2b1797SNate Lawson     /* Create any static children by calling device identify methods. */
11044c1cdee6SMike Smith     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "device identify routines\n"));
110515e32d5dSMike Smith     bus_generic_probe(bus);
110615e32d5dSMike Smith 
110715e32d5dSMike Smith     /*
110815e32d5dSMike Smith      * Scan the namespace and insert placeholders for all the devices that
110915e32d5dSMike Smith      * we find.
111015e32d5dSMike Smith      *
111115e32d5dSMike Smith      * Note that we use AcpiWalkNamespace rather than AcpiGetDevices because
1112be2b1797SNate Lawson      * we want to create nodes for all devices, not just those that are
1113be2b1797SNate Lawson      * currently present. (This assumes that we don't want to create/remove
1114be2b1797SNate Lawson      * devices as they appear, which might be smarter.)
111515e32d5dSMike Smith      */
11164c1cdee6SMike Smith     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "namespace scan\n"));
1117be2b1797SNate Lawson     for (i = 0; scopes[i] != NULL; i++) {
1118be2b1797SNate Lawson 	status = AcpiGetHandle(ACPI_ROOT_OBJECT, scopes[i], &parent);
1119be2b1797SNate Lawson 	if (ACPI_SUCCESS(status)) {
1120be2b1797SNate Lawson 	    AcpiWalkNamespace(ACPI_TYPE_ANY, parent, 100, acpi_probe_child,
1121be2b1797SNate Lawson 			      bus, NULL);
1122be2b1797SNate Lawson 	}
1123be2b1797SNate Lawson     }
112415e32d5dSMike Smith 
112515e32d5dSMike Smith     /*
112615e32d5dSMike Smith      * Scan all of the child devices we have created and let them probe/attach.
112715e32d5dSMike Smith      */
11284c1cdee6SMike Smith     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "first bus_generic_attach\n"));
112915e32d5dSMike Smith     bus_generic_attach(bus);
113015e32d5dSMike Smith 
113115e32d5dSMike Smith     /*
113215e32d5dSMike Smith      * Some of these children may have attached others as part of their attach
113315e32d5dSMike Smith      * process (eg. the root PCI bus driver), so rescan.
113415e32d5dSMike Smith      */
11354c1cdee6SMike Smith     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "second bus_generic_attach\n"));
113615e32d5dSMike Smith     bus_generic_attach(bus);
11370ae55423SMike Smith 
1138bc0f2195SMike Smith     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "done attaching children\n"));
11390ae55423SMike Smith     return_VOID;
114015e32d5dSMike Smith }
114115e32d5dSMike Smith 
114215e32d5dSMike Smith /*
114315e32d5dSMike Smith  * Evaluate a child device and determine whether we might attach a device to
114415e32d5dSMike Smith  * it.
114515e32d5dSMike Smith  */
114615e32d5dSMike Smith static ACPI_STATUS
114715e32d5dSMike Smith acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
114815e32d5dSMike Smith {
114915e32d5dSMike Smith     ACPI_OBJECT_TYPE	type;
115015e32d5dSMike Smith     device_t		child, bus = (device_t)context;
115115e32d5dSMike Smith 
1152b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
11530ae55423SMike Smith 
1154be2b1797SNate Lawson     /* Skip this device if we think we'll have trouble with it. */
11550ae55423SMike Smith     if (acpi_avoid(handle))
11560ae55423SMike Smith 	return_ACPI_STATUS (AE_OK);
11570ae55423SMike Smith 
1158b53f2771SMike Smith     if (ACPI_SUCCESS(AcpiGetType(handle, &type))) {
115915e32d5dSMike Smith 	switch(type) {
116015e32d5dSMike Smith 	case ACPI_TYPE_DEVICE:
116115e32d5dSMike Smith 	case ACPI_TYPE_PROCESSOR:
116215e32d5dSMike Smith 	case ACPI_TYPE_THERMAL:
116315e32d5dSMike Smith 	case ACPI_TYPE_POWER:
11640ae55423SMike Smith 	    if (acpi_disabled("children"))
11650ae55423SMike Smith 		break;
1166be2b1797SNate Lawson 
116715e32d5dSMike Smith 	    /*
116815e32d5dSMike Smith 	     * Create a placeholder device for this node.  Sort the placeholder
116915e32d5dSMike Smith 	     * so that the probe/attach passes will run breadth-first.
117015e32d5dSMike Smith 	     */
1171be2b1797SNate Lawson 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "scanning '%s'\n",
1172be2b1797SNate Lawson 			     acpi_name(handle)));
117315e32d5dSMike Smith 	    child = BUS_ADD_CHILD(bus, level * 10, NULL, -1);
1174bc0f2195SMike Smith 	    if (child == NULL)
1175bc0f2195SMike Smith 		break;
117615e32d5dSMike Smith 	    acpi_set_handle(child, handle);
1177bc0f2195SMike Smith 
1178bc0f2195SMike Smith 	    /*
1179b519f9d6SMike Smith 	     * Check that the device is present.  If it's not present,
1180b519f9d6SMike Smith 	     * leave it disabled (so that we have a device_t attached to
1181b519f9d6SMike Smith 	     * the handle, but we don't probe it).
1182b519f9d6SMike Smith 	     */
1183be2b1797SNate Lawson 	    if (type == ACPI_TYPE_DEVICE && !acpi_DeviceIsPresent(child)) {
1184b519f9d6SMike Smith 		device_disable(child);
1185b519f9d6SMike Smith 		break;
1186b519f9d6SMike Smith 	    }
1187b519f9d6SMike Smith 
1188b519f9d6SMike Smith 	    /*
1189bc0f2195SMike Smith 	     * Get the device's resource settings and attach them.
1190bc0f2195SMike Smith 	     * Note that if the device has _PRS but no _CRS, we need
1191bc0f2195SMike Smith 	     * to decide when it's appropriate to try to configure the
1192bc0f2195SMike Smith 	     * device.  Ignore the return value here; it's OK for the
1193bc0f2195SMike Smith 	     * device not to have any resources.
1194bc0f2195SMike Smith 	     */
1195bc0f2195SMike Smith 	    acpi_parse_resources(child, handle, &acpi_res_parse_set);
1196bc0f2195SMike Smith 
1197be2b1797SNate Lawson 	    /* If we're debugging, probe/attach now rather than later */
1198b53f2771SMike Smith 	    ACPI_DEBUG_EXEC(device_probe_and_attach(child));
11990ae55423SMike Smith 	    break;
120015e32d5dSMike Smith 	}
120115e32d5dSMike Smith     }
1202be2b1797SNate Lawson 
12030ae55423SMike Smith     return_ACPI_STATUS (AE_OK);
120415e32d5dSMike Smith }
120515e32d5dSMike Smith 
120615e32d5dSMike Smith static void
120715e32d5dSMike Smith acpi_shutdown_pre_sync(void *arg, int howto)
120815e32d5dSMike Smith {
1209c6a78e98STakanori Watanabe     struct acpi_softc *sc = arg;
1210c6a78e98STakanori Watanabe 
1211cb9b0d80SMike Smith     ACPI_ASSERTLOCK;
1212cb9b0d80SMike Smith 
121315e32d5dSMike Smith     /*
12140ae55423SMike Smith      * Disable all ACPI events before soft off, otherwise the system
121515e32d5dSMike Smith      * will be turned on again on some laptops.
121615e32d5dSMike Smith      *
121715e32d5dSMike Smith      * XXX this should probably be restricted to masking some events just
121815e32d5dSMike Smith      *     before powering down, since we may still need ACPI during the
121915e32d5dSMike Smith      *     shutdown process.
122015e32d5dSMike Smith      */
1221c6a78e98STakanori Watanabe     if (sc->acpi_disable_on_poweroff)
1222c6a78e98STakanori Watanabe 	acpi_Disable(sc);
122315e32d5dSMike Smith }
122415e32d5dSMike Smith 
122515e32d5dSMike Smith static void
122615e32d5dSMike Smith acpi_shutdown_final(void *arg, int howto)
122715e32d5dSMike Smith {
1228eeb3a05fSNate Lawson 
1229eeb3a05fSNate Lawson     ACPI_ASSERTLOCK;
1230eeb3a05fSNate Lawson 
1231eeb3a05fSNate Lawson     /*
1232eeb3a05fSNate Lawson      * If powering off, run the actual shutdown code on each processor.
1233eeb3a05fSNate Lawson      * It will only perform the shutdown on the BSP.  Some chipsets do
1234eeb3a05fSNate Lawson      * not power off the system correctly if called from an AP.
1235eeb3a05fSNate Lawson      */
1236eeb3a05fSNate Lawson     if ((howto & RB_POWEROFF) != 0) {
1237eeb3a05fSNate Lawson 	printf("Powering system off using ACPI\n");
1238eeb3a05fSNate Lawson 	smp_rendezvous(NULL, acpi_shutdown_poweroff, NULL, NULL);
1239eeb3a05fSNate Lawson     } else {
1240eeb3a05fSNate Lawson 	printf("Shutting down ACPI\n");
1241eeb3a05fSNate Lawson 	AcpiTerminate();
1242eeb3a05fSNate Lawson     }
1243eeb3a05fSNate Lawson }
1244eeb3a05fSNate Lawson 
1245eeb3a05fSNate Lawson static void
1246eeb3a05fSNate Lawson acpi_shutdown_poweroff(void *arg)
1247eeb3a05fSNate Lawson {
124815e32d5dSMike Smith     ACPI_STATUS	status;
124915e32d5dSMike Smith 
1250cb9b0d80SMike Smith     ACPI_ASSERTLOCK;
1251cb9b0d80SMike Smith 
1252eeb3a05fSNate Lawson     /* Only attempt to power off if this is the BSP (cpuid 0). */
1253eeb3a05fSNate Lawson     if (PCPU_GET(cpuid) != 0)
1254eeb3a05fSNate Lawson 	return;
1255eeb3a05fSNate Lawson 
1256be2b1797SNate Lawson     status = AcpiEnterSleepStatePrep(acpi_off_state);
1257be2b1797SNate Lawson     if (ACPI_FAILURE(status)) {
1258b9c780d6SMitsuru IWASAKI 	printf("AcpiEnterSleepStatePrep failed - %s\n",
1259b9c780d6SMitsuru IWASAKI 	       AcpiFormatException(status));
1260b9c780d6SMitsuru IWASAKI 	return;
1261b9c780d6SMitsuru IWASAKI     }
126255398047SNate Lawson     ACPI_DISABLE_IRQS();
1263be2b1797SNate Lawson     status = AcpiEnterSleepState(acpi_off_state);
1264be2b1797SNate Lawson     if (ACPI_FAILURE(status)) {
1265bfae45aaSMike Smith 	printf("ACPI power-off failed - %s\n", AcpiFormatException(status));
126615e32d5dSMike Smith     } else {
126715e32d5dSMike Smith 	DELAY(1000000);
126815e32d5dSMike Smith 	printf("ACPI power-off failed - timeout\n");
126915e32d5dSMike Smith     }
127015e32d5dSMike Smith }
127115e32d5dSMike Smith 
127213d4f7baSMitsuru IWASAKI static void
127313d4f7baSMitsuru IWASAKI acpi_enable_fixed_events(struct acpi_softc *sc)
127413d4f7baSMitsuru IWASAKI {
127513d4f7baSMitsuru IWASAKI     static int	first_time = 1;
127613d4f7baSMitsuru IWASAKI 
1277cb9b0d80SMike Smith     ACPI_ASSERTLOCK;
1278cb9b0d80SMike Smith 
127913d4f7baSMitsuru IWASAKI     /* Enable and clear fixed events and install handlers. */
1280be2b1797SNate Lawson     if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->PwrButton == 0) {
128159ddeb18SNate Lawson 	AcpiClearEvent(ACPI_EVENT_POWER_BUTTON);
128213d4f7baSMitsuru IWASAKI 	AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
128333febf93SNate Lawson 				     acpi_event_power_button_sleep, sc);
1284be2b1797SNate Lawson 	if (first_time)
12856c0e8467SNate Lawson 	    device_printf(sc->acpi_dev, "Power Button (fixed)\n");
128613d4f7baSMitsuru IWASAKI     }
1287be2b1797SNate Lawson     if (AcpiGbl_FADT != NULL && AcpiGbl_FADT->SleepButton == 0) {
128859ddeb18SNate Lawson 	AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON);
128913d4f7baSMitsuru IWASAKI 	AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON,
129033febf93SNate Lawson 				     acpi_event_sleep_button_sleep, sc);
1291be2b1797SNate Lawson 	if (first_time)
12926c0e8467SNate Lawson 	    device_printf(sc->acpi_dev, "Sleep Button (fixed)\n");
129313d4f7baSMitsuru IWASAKI     }
129413d4f7baSMitsuru IWASAKI 
129513d4f7baSMitsuru IWASAKI     first_time = 0;
129613d4f7baSMitsuru IWASAKI }
129713d4f7baSMitsuru IWASAKI 
129815e32d5dSMike Smith /*
1299c5ba0be4SMike Smith  * Returns true if the device is actually present and should
1300c5ba0be4SMike Smith  * be attached to.  This requires the present, enabled, UI-visible
1301c5ba0be4SMike Smith  * and diagnostics-passed bits to be set.
1302c5ba0be4SMike Smith  */
1303c5ba0be4SMike Smith BOOLEAN
1304c5ba0be4SMike Smith acpi_DeviceIsPresent(device_t dev)
1305c5ba0be4SMike Smith {
13061e4925e8SNate Lawson     ACPI_DEVICE_INFO	*devinfo;
1307c5ba0be4SMike Smith     ACPI_HANDLE		h;
13081e4925e8SNate Lawson     ACPI_BUFFER		buf;
1309c5ba0be4SMike Smith     ACPI_STATUS		error;
13101e4925e8SNate Lawson     int			ret;
1311c5ba0be4SMike Smith 
1312cb9b0d80SMike Smith     ACPI_ASSERTLOCK;
1313cb9b0d80SMike Smith 
13141e4925e8SNate Lawson     ret = FALSE;
1315c5ba0be4SMike Smith     if ((h = acpi_get_handle(dev)) == NULL)
1316c5ba0be4SMike Smith 	return (FALSE);
13171e4925e8SNate Lawson     buf.Pointer = NULL;
13181e4925e8SNate Lawson     buf.Length = ACPI_ALLOCATE_BUFFER;
13196fca9360SNate Lawson     error = AcpiGetObjectInfo(h, &buf);
13206fca9360SNate Lawson     if (ACPI_FAILURE(error))
1321c5ba0be4SMike Smith 	return (FALSE);
13221e4925e8SNate Lawson     devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
1323be2b1797SNate Lawson 
1324be2b1797SNate Lawson     /* If no _STA method, must be present */
13251e4925e8SNate Lawson     if ((devinfo->Valid & ACPI_VALID_STA) == 0)
13261e4925e8SNate Lawson 	ret = TRUE;
1327be2b1797SNate Lawson 
1328be2b1797SNate Lawson     /* Return true for 'present' and 'functioning' */
13291e4925e8SNate Lawson     if ((devinfo->CurrentStatus & 0x9) == 0x9)
13301e4925e8SNate Lawson 	ret = TRUE;
1331be2b1797SNate Lawson 
13321e4925e8SNate Lawson     AcpiOsFree(buf.Pointer);
13331e4925e8SNate Lawson     return (ret);
1334c5ba0be4SMike Smith }
1335c5ba0be4SMike Smith 
1336c5ba0be4SMike Smith /*
1337b53f2771SMike Smith  * Returns true if the battery is actually present and inserted.
1338b53f2771SMike Smith  */
1339b53f2771SMike Smith BOOLEAN
1340b53f2771SMike Smith acpi_BatteryIsPresent(device_t dev)
1341b53f2771SMike Smith {
13421e4925e8SNate Lawson     ACPI_DEVICE_INFO	*devinfo;
1343b53f2771SMike Smith     ACPI_HANDLE		h;
13441e4925e8SNate Lawson     ACPI_BUFFER		buf;
1345b53f2771SMike Smith     ACPI_STATUS		error;
13461e4925e8SNate Lawson     int			ret;
1347b53f2771SMike Smith 
1348b53f2771SMike Smith     ACPI_ASSERTLOCK;
1349b53f2771SMike Smith 
13501e4925e8SNate Lawson     ret = FALSE;
1351b53f2771SMike Smith     if ((h = acpi_get_handle(dev)) == NULL)
1352b53f2771SMike Smith 	return (FALSE);
13531e4925e8SNate Lawson     buf.Pointer = NULL;
13541e4925e8SNate Lawson     buf.Length = ACPI_ALLOCATE_BUFFER;
13556fca9360SNate Lawson     error = AcpiGetObjectInfo(h, &buf);
13566fca9360SNate Lawson     if (ACPI_FAILURE(error))
1357b53f2771SMike Smith 	return (FALSE);
13581e4925e8SNate Lawson     devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
1359be2b1797SNate Lawson 
1360be2b1797SNate Lawson     /* If no _STA method, must be present */
13611e4925e8SNate Lawson     if ((devinfo->Valid & ACPI_VALID_STA) == 0)
13621e4925e8SNate Lawson 	ret = TRUE;
1363be2b1797SNate Lawson 
1364be2b1797SNate Lawson     /* Return true for 'present' and 'functioning' */
13651e4925e8SNate Lawson     if ((devinfo->CurrentStatus & 0x19) == 0x19)
13661e4925e8SNate Lawson 	ret = TRUE;
1367be2b1797SNate Lawson 
13681e4925e8SNate Lawson     AcpiOsFree(buf.Pointer);
13691e4925e8SNate Lawson     return (ret);
1370b53f2771SMike Smith }
1371b53f2771SMike Smith 
1372b53f2771SMike Smith /*
137315e32d5dSMike Smith  * Match a HID string against a device
137415e32d5dSMike Smith  */
137515e32d5dSMike Smith BOOLEAN
137615e32d5dSMike Smith acpi_MatchHid(device_t dev, char *hid)
137715e32d5dSMike Smith {
13781e4925e8SNate Lawson     ACPI_DEVICE_INFO	*devinfo;
137915e32d5dSMike Smith     ACPI_HANDLE		h;
13801e4925e8SNate Lawson     ACPI_BUFFER		buf;
138115e32d5dSMike Smith     ACPI_STATUS		error;
13821e4925e8SNate Lawson     int			ret, i;
138315e32d5dSMike Smith 
1384cb9b0d80SMike Smith     ACPI_ASSERTLOCK;
1385cb9b0d80SMike Smith 
13861e4925e8SNate Lawson     ret = FALSE;
13874d332989SMike Smith     if (hid == NULL)
138815e32d5dSMike Smith 	return (FALSE);
138915e32d5dSMike Smith     if ((h = acpi_get_handle(dev)) == NULL)
139015e32d5dSMike Smith 	return (FALSE);
13911e4925e8SNate Lawson     buf.Pointer = NULL;
13921e4925e8SNate Lawson     buf.Length = ACPI_ALLOCATE_BUFFER;
13936fca9360SNate Lawson     error = AcpiGetObjectInfo(h, &buf);
13946fca9360SNate Lawson     if (ACPI_FAILURE(error))
139515e32d5dSMike Smith 	return (FALSE);
13961e4925e8SNate Lawson     devinfo = (ACPI_DEVICE_INFO *)buf.Pointer;
1397be2b1797SNate Lawson 
1398c59c9a8eSJohn Baldwin     if ((devinfo->Valid & ACPI_VALID_HID) != 0 &&
1399c59c9a8eSJohn Baldwin 	strcmp(hid, devinfo->HardwareId.Value) == 0)
14001e4925e8SNate Lawson 	    ret = TRUE;
1401c59c9a8eSJohn Baldwin     else if ((devinfo->Valid & ACPI_VALID_CID) != 0) {
14021e4925e8SNate Lawson 	for (i = 0; i < devinfo->CompatibilityId.Count; i++) {
14031e4925e8SNate Lawson 	    if (strcmp(hid, devinfo->CompatibilityId.Id[i].Value) == 0) {
14041e4925e8SNate Lawson 		ret = TRUE;
14051e4925e8SNate Lawson 		break;
14061e4925e8SNate Lawson 	    }
14071e4925e8SNate Lawson 	}
14081e4925e8SNate Lawson     }
1409be2b1797SNate Lawson 
14101e4925e8SNate Lawson     AcpiOsFree(buf.Pointer);
14111e4925e8SNate Lawson     return (ret);
141215e32d5dSMike Smith }
141315e32d5dSMike Smith 
141415e32d5dSMike Smith /*
1415c5ba0be4SMike Smith  * Return the handle of a named object within our scope, ie. that of (parent)
1416c5ba0be4SMike Smith  * or one if its parents.
1417c5ba0be4SMike Smith  */
1418c5ba0be4SMike Smith ACPI_STATUS
1419c5ba0be4SMike Smith acpi_GetHandleInScope(ACPI_HANDLE parent, char *path, ACPI_HANDLE *result)
1420c5ba0be4SMike Smith {
1421c5ba0be4SMike Smith     ACPI_HANDLE		r;
1422c5ba0be4SMike Smith     ACPI_STATUS		status;
1423c5ba0be4SMike Smith 
1424cb9b0d80SMike Smith     ACPI_ASSERTLOCK;
1425cb9b0d80SMike Smith 
1426be2b1797SNate Lawson     /* Walk back up the tree to the root */
1427c5ba0be4SMike Smith     for (;;) {
1428be2b1797SNate Lawson 	status = AcpiGetHandle(parent, path, &r);
1429be2b1797SNate Lawson 	if (ACPI_SUCCESS(status)) {
1430c5ba0be4SMike Smith 	    *result = r;
1431c5ba0be4SMike Smith 	    return (AE_OK);
1432c5ba0be4SMike Smith 	}
1433c5ba0be4SMike Smith 	if (status != AE_NOT_FOUND)
1434c5ba0be4SMike Smith 	    return (AE_OK);
1435b53f2771SMike Smith 	if (ACPI_FAILURE(AcpiGetParent(parent, &r)))
1436c5ba0be4SMike Smith 	    return (AE_NOT_FOUND);
1437c5ba0be4SMike Smith 	parent = r;
1438c5ba0be4SMike Smith     }
1439c5ba0be4SMike Smith }
1440c5ba0be4SMike Smith 
1441c5ba0be4SMike Smith /*
1442c5ba0be4SMike Smith  * Allocate a buffer with a preset data size.
1443c5ba0be4SMike Smith  */
1444c5ba0be4SMike Smith ACPI_BUFFER *
1445c5ba0be4SMike Smith acpi_AllocBuffer(int size)
1446c5ba0be4SMike Smith {
1447c5ba0be4SMike Smith     ACPI_BUFFER	*buf;
1448c5ba0be4SMike Smith 
1449c5ba0be4SMike Smith     if ((buf = malloc(size + sizeof(*buf), M_ACPIDEV, M_NOWAIT)) == NULL)
1450c5ba0be4SMike Smith 	return (NULL);
1451c5ba0be4SMike Smith     buf->Length = size;
1452c5ba0be4SMike Smith     buf->Pointer = (void *)(buf + 1);
1453c5ba0be4SMike Smith     return (buf);
1454c5ba0be4SMike Smith }
1455c5ba0be4SMike Smith 
1456c310653eSNate Lawson ACPI_STATUS
1457cc58e4eeSNate Lawson acpi_SetInteger(ACPI_HANDLE handle, char *path, UINT32 number)
1458c310653eSNate Lawson {
1459c310653eSNate Lawson     ACPI_OBJECT arg1;
1460c310653eSNate Lawson     ACPI_OBJECT_LIST args;
1461c310653eSNate Lawson 
1462c310653eSNate Lawson     ACPI_ASSERTLOCK;
1463c310653eSNate Lawson 
1464c310653eSNate Lawson     arg1.Type = ACPI_TYPE_INTEGER;
1465c310653eSNate Lawson     arg1.Integer.Value = number;
1466c310653eSNate Lawson     args.Count = 1;
1467c310653eSNate Lawson     args.Pointer = &arg1;
1468c310653eSNate Lawson 
1469c310653eSNate Lawson     return (AcpiEvaluateObject(handle, path, &args, NULL));
1470c310653eSNate Lawson }
1471c310653eSNate Lawson 
1472c5ba0be4SMike Smith /*
1473c5ba0be4SMike Smith  * Evaluate a path that should return an integer.
1474c5ba0be4SMike Smith  */
1475c5ba0be4SMike Smith ACPI_STATUS
1476cc58e4eeSNate Lawson acpi_GetInteger(ACPI_HANDLE handle, char *path, UINT32 *number)
1477c5ba0be4SMike Smith {
1478be2b1797SNate Lawson     ACPI_STATUS	status;
1479c5ba0be4SMike Smith     ACPI_BUFFER	buf;
1480c573e654SMitsuru IWASAKI     ACPI_OBJECT	param;
1481c5ba0be4SMike Smith 
1482cb9b0d80SMike Smith     ACPI_ASSERTLOCK;
1483cb9b0d80SMike Smith 
1484c5ba0be4SMike Smith     if (handle == NULL)
1485c5ba0be4SMike Smith 	handle = ACPI_ROOT_OBJECT;
14860c7da7acSJohn Baldwin 
14870c7da7acSJohn Baldwin     /*
14880c7da7acSJohn Baldwin      * Assume that what we've been pointed at is an Integer object, or
14890c7da7acSJohn Baldwin      * a method that will return an Integer.
14900c7da7acSJohn Baldwin      */
1491c5ba0be4SMike Smith     buf.Pointer = &param;
1492c5ba0be4SMike Smith     buf.Length = sizeof(param);
1493be2b1797SNate Lawson     status = AcpiEvaluateObject(handle, path, NULL, &buf);
1494be2b1797SNate Lawson     if (ACPI_SUCCESS(status)) {
1495be2b1797SNate Lawson 	if (param.Type == ACPI_TYPE_INTEGER)
1496c5ba0be4SMike Smith 	    *number = param.Integer.Value;
1497be2b1797SNate Lawson 	else
1498be2b1797SNate Lawson 	    status = AE_TYPE;
1499c5ba0be4SMike Smith     }
15000c7da7acSJohn Baldwin 
15010c7da7acSJohn Baldwin     /*
15020c7da7acSJohn Baldwin      * In some applications, a method that's expected to return an Integer
15030c7da7acSJohn Baldwin      * may instead return a Buffer (probably to simplify some internal
15040c7da7acSJohn Baldwin      * arithmetic).  We'll try to fetch whatever it is, and if it's a Buffer,
15050c7da7acSJohn Baldwin      * convert it into an Integer as best we can.
15060c7da7acSJohn Baldwin      *
15070c7da7acSJohn Baldwin      * This is a hack.
15080c7da7acSJohn Baldwin      */
1509be2b1797SNate Lawson     if (status == AE_BUFFER_OVERFLOW) {
1510b53f2771SMike Smith 	if ((buf.Pointer = AcpiOsAllocate(buf.Length)) == NULL) {
1511be2b1797SNate Lawson 	    status = AE_NO_MEMORY;
15120c7da7acSJohn Baldwin 	} else {
1513be2b1797SNate Lawson 	    status = AcpiEvaluateObject(handle, path, NULL, &buf);
1514be2b1797SNate Lawson 	    if (ACPI_SUCCESS(status))
1515be2b1797SNate Lawson 		status = acpi_ConvertBufferToInteger(&buf, number);
15160c7da7acSJohn Baldwin 	    AcpiOsFree(buf.Pointer);
15170c7da7acSJohn Baldwin 	}
1518f97739daSNate Lawson     }
1519be2b1797SNate Lawson     return (status);
1520c5ba0be4SMike Smith }
1521c5ba0be4SMike Smith 
1522c573e654SMitsuru IWASAKI ACPI_STATUS
1523cc58e4eeSNate Lawson acpi_ConvertBufferToInteger(ACPI_BUFFER *bufp, UINT32 *number)
1524c573e654SMitsuru IWASAKI {
1525c573e654SMitsuru IWASAKI     ACPI_OBJECT	*p;
1526dba55fa2SNate Lawson     UINT8	*val;
1527c573e654SMitsuru IWASAKI     int		i;
1528c573e654SMitsuru IWASAKI 
1529c573e654SMitsuru IWASAKI     p = (ACPI_OBJECT *)bufp->Pointer;
1530c573e654SMitsuru IWASAKI     if (p->Type == ACPI_TYPE_INTEGER) {
1531c573e654SMitsuru IWASAKI 	*number = p->Integer.Value;
1532c573e654SMitsuru IWASAKI 	return (AE_OK);
1533c573e654SMitsuru IWASAKI     }
1534c573e654SMitsuru IWASAKI     if (p->Type != ACPI_TYPE_BUFFER)
1535c573e654SMitsuru IWASAKI 	return (AE_TYPE);
1536c573e654SMitsuru IWASAKI     if (p->Buffer.Length > sizeof(int))
1537c573e654SMitsuru IWASAKI 	return (AE_BAD_DATA);
1538be2b1797SNate Lawson 
1539c573e654SMitsuru IWASAKI     *number = 0;
1540dba55fa2SNate Lawson     val = p->Buffer.Pointer;
1541c573e654SMitsuru IWASAKI     for (i = 0; i < p->Buffer.Length; i++)
1542dba55fa2SNate Lawson 	*number += val[i] << (i * 8);
1543c573e654SMitsuru IWASAKI     return (AE_OK);
1544c573e654SMitsuru IWASAKI }
1545c573e654SMitsuru IWASAKI 
1546c5ba0be4SMike Smith /*
1547c5ba0be4SMike Smith  * Iterate over the elements of an a package object, calling the supplied
1548c5ba0be4SMike Smith  * function for each element.
1549c5ba0be4SMike Smith  *
1550c5ba0be4SMike Smith  * XXX possible enhancement might be to abort traversal on error.
1551c5ba0be4SMike Smith  */
1552c5ba0be4SMike Smith ACPI_STATUS
1553be2b1797SNate Lawson acpi_ForeachPackageObject(ACPI_OBJECT *pkg,
1554be2b1797SNate Lawson 	void (*func)(ACPI_OBJECT *comp, void *arg), void *arg)
1555c5ba0be4SMike Smith {
1556c5ba0be4SMike Smith     ACPI_OBJECT	*comp;
1557c5ba0be4SMike Smith     int		i;
1558c5ba0be4SMike Smith 
1559be2b1797SNate Lawson     if (pkg == NULL || pkg->Type != ACPI_TYPE_PACKAGE)
1560c5ba0be4SMike Smith 	return (AE_BAD_PARAMETER);
1561c5ba0be4SMike Smith 
1562be2b1797SNate Lawson     /* Iterate over components */
1563be2b1797SNate Lawson     i = 0;
1564be2b1797SNate Lawson     comp = pkg->Package.Elements;
1565be2b1797SNate Lawson     for (; i < pkg->Package.Count; i++, comp++)
1566c5ba0be4SMike Smith 	func(comp, arg);
1567c5ba0be4SMike Smith 
1568c5ba0be4SMike Smith     return (AE_OK);
1569c5ba0be4SMike Smith }
1570c5ba0be4SMike Smith 
15716f69255bSMike Smith /*
15726f69255bSMike Smith  * Find the (index)th resource object in a set.
15736f69255bSMike Smith  */
15746f69255bSMike Smith ACPI_STATUS
15756d63101aSMike Smith acpi_FindIndexedResource(ACPI_BUFFER *buf, int index, ACPI_RESOURCE **resp)
15766f69255bSMike Smith {
15776d63101aSMike Smith     ACPI_RESOURCE	*rp;
15786f69255bSMike Smith     int			i;
15796f69255bSMike Smith 
15806d63101aSMike Smith     rp = (ACPI_RESOURCE *)buf->Pointer;
15816f69255bSMike Smith     i = index;
15826d63101aSMike Smith     while (i-- > 0) {
1583be2b1797SNate Lawson 	/* Range check */
15846d63101aSMike Smith 	if (rp > (ACPI_RESOURCE *)((u_int8_t *)buf->Pointer + buf->Length))
15856f69255bSMike Smith 	    return (AE_BAD_PARAMETER);
1586be2b1797SNate Lawson 
1587be2b1797SNate Lawson 	/* Check for terminator */
1588be2b1797SNate Lawson 	if (rp->Id == ACPI_RSTYPE_END_TAG || rp->Length == 0)
15896d63101aSMike Smith 	    return (AE_NOT_FOUND);
1590abcbc5bcSNate Lawson 	rp = ACPI_NEXT_RESOURCE(rp);
15916f69255bSMike Smith     }
15926f69255bSMike Smith     if (resp != NULL)
15936d63101aSMike Smith 	*resp = rp;
1594be2b1797SNate Lawson 
15956d63101aSMike Smith     return (AE_OK);
15966d63101aSMike Smith }
15976d63101aSMike Smith 
15986d63101aSMike Smith /*
15996d63101aSMike Smith  * Append an ACPI_RESOURCE to an ACPI_BUFFER.
16006d63101aSMike Smith  *
16016d63101aSMike Smith  * Given a pointer to an ACPI_RESOURCE structure, expand the ACPI_BUFFER
16026d63101aSMike Smith  * provided to contain it.  If the ACPI_BUFFER is empty, allocate a sensible
16036d63101aSMike Smith  * backing block.  If the ACPI_RESOURCE is NULL, return an empty set of
16046d63101aSMike Smith  * resources.
16056d63101aSMike Smith  */
16066d63101aSMike Smith #define ACPI_INITIAL_RESOURCE_BUFFER_SIZE	512
16076d63101aSMike Smith 
16086d63101aSMike Smith ACPI_STATUS
16096d63101aSMike Smith acpi_AppendBufferResource(ACPI_BUFFER *buf, ACPI_RESOURCE *res)
16106d63101aSMike Smith {
16116d63101aSMike Smith     ACPI_RESOURCE	*rp;
16126d63101aSMike Smith     void		*newp;
16136d63101aSMike Smith 
1614be2b1797SNate Lawson     /* Initialise the buffer if necessary. */
16156d63101aSMike Smith     if (buf->Pointer == NULL) {
16166d63101aSMike Smith 	buf->Length = ACPI_INITIAL_RESOURCE_BUFFER_SIZE;
16176d63101aSMike Smith 	if ((buf->Pointer = AcpiOsAllocate(buf->Length)) == NULL)
16186d63101aSMike Smith 	    return (AE_NO_MEMORY);
16196d63101aSMike Smith 	rp = (ACPI_RESOURCE *)buf->Pointer;
16206d63101aSMike Smith 	rp->Id = ACPI_RSTYPE_END_TAG;
16216d63101aSMike Smith 	rp->Length = 0;
16226d63101aSMike Smith     }
16236d63101aSMike Smith     if (res == NULL)
16246d63101aSMike Smith 	return (AE_OK);
16256d63101aSMike Smith 
16266d63101aSMike Smith     /*
16276d63101aSMike Smith      * Scan the current buffer looking for the terminator.
16286d63101aSMike Smith      * This will either find the terminator or hit the end
16296d63101aSMike Smith      * of the buffer and return an error.
16306d63101aSMike Smith      */
16316d63101aSMike Smith     rp = (ACPI_RESOURCE *)buf->Pointer;
16326d63101aSMike Smith     for (;;) {
1633be2b1797SNate Lawson 	/* Range check, don't go outside the buffer */
16346d63101aSMike Smith 	if (rp >= (ACPI_RESOURCE *)((u_int8_t *)buf->Pointer + buf->Length))
16356d63101aSMike Smith 	    return (AE_BAD_PARAMETER);
1636be2b1797SNate Lawson 	if (rp->Id == ACPI_RSTYPE_END_TAG || rp->Length == 0)
16376d63101aSMike Smith 	    break;
1638abcbc5bcSNate Lawson 	rp = ACPI_NEXT_RESOURCE(rp);
16396d63101aSMike Smith     }
16406d63101aSMike Smith 
16416d63101aSMike Smith     /*
16426d63101aSMike Smith      * Check the size of the buffer and expand if required.
16436d63101aSMike Smith      *
16446d63101aSMike Smith      * Required size is:
16456d63101aSMike Smith      *	size of existing resources before terminator +
16466d63101aSMike Smith      *	size of new resource and header +
16476d63101aSMike Smith      * 	size of terminator.
16486d63101aSMike Smith      *
16496d63101aSMike Smith      * Note that this loop should really only run once, unless
16506d63101aSMike Smith      * for some reason we are stuffing a *really* huge resource.
16516d63101aSMike Smith      */
16526d63101aSMike Smith     while ((((u_int8_t *)rp - (u_int8_t *)buf->Pointer) +
16536d63101aSMike Smith 	    res->Length + ACPI_RESOURCE_LENGTH_NO_DATA +
16546d63101aSMike Smith 	    ACPI_RESOURCE_LENGTH) >= buf->Length) {
16556d63101aSMike Smith 	if ((newp = AcpiOsAllocate(buf->Length * 2)) == NULL)
16566d63101aSMike Smith 	    return (AE_NO_MEMORY);
16576d63101aSMike Smith 	bcopy(buf->Pointer, newp, buf->Length);
1658a692219dSMike Smith 	rp = (ACPI_RESOURCE *)((u_int8_t *)newp +
1659a692219dSMike Smith 			       ((u_int8_t *)rp - (u_int8_t *)buf->Pointer));
16606d63101aSMike Smith 	AcpiOsFree(buf->Pointer);
16616d63101aSMike Smith 	buf->Pointer = newp;
16626d63101aSMike Smith 	buf->Length += buf->Length;
16636d63101aSMike Smith     }
16646d63101aSMike Smith 
1665be2b1797SNate Lawson     /* Insert the new resource. */
16666d63101aSMike Smith     bcopy(res, rp, res->Length + ACPI_RESOURCE_LENGTH_NO_DATA);
16676d63101aSMike Smith 
1668be2b1797SNate Lawson     /* And add the terminator. */
1669abcbc5bcSNate Lawson     rp = ACPI_NEXT_RESOURCE(rp);
16706d63101aSMike Smith     rp->Id = ACPI_RSTYPE_END_TAG;
16716d63101aSMike Smith     rp->Length = 0;
16726d63101aSMike Smith 
16736f69255bSMike Smith     return (AE_OK);
16746f69255bSMike Smith }
1675c5ba0be4SMike Smith 
1676da14ac9fSJohn Baldwin /*
1677da14ac9fSJohn Baldwin  * Set interrupt model.
1678da14ac9fSJohn Baldwin  */
1679da14ac9fSJohn Baldwin ACPI_STATUS
1680da14ac9fSJohn Baldwin acpi_SetIntrModel(int model)
1681da14ac9fSJohn Baldwin {
1682da14ac9fSJohn Baldwin 
1683c310653eSNate Lawson     return (acpi_SetInteger(ACPI_ROOT_OBJECT, "_PIC", model));
1684da14ac9fSJohn Baldwin }
1685da14ac9fSJohn Baldwin 
1686ece50487SMitsuru IWASAKI #define ACPI_MINIMUM_AWAKETIME	5
1687ece50487SMitsuru IWASAKI 
1688ece50487SMitsuru IWASAKI static void
1689ece50487SMitsuru IWASAKI acpi_sleep_enable(void *arg)
1690ece50487SMitsuru IWASAKI {
1691ece50487SMitsuru IWASAKI     ((struct acpi_softc *)arg)->acpi_sleep_disabled = 0;
1692ece50487SMitsuru IWASAKI }
1693c30382dfSMitsuru IWASAKI 
169415e32d5dSMike Smith /*
169515e32d5dSMike Smith  * Set the system sleep state
169615e32d5dSMike Smith  *
1697be2b1797SNate Lawson  * Currently we support S1-S5 but S4 is only S4BIOS
169815e32d5dSMike Smith  */
169915e32d5dSMike Smith ACPI_STATUS
170015e32d5dSMike Smith acpi_SetSleepState(struct acpi_softc *sc, int state)
170115e32d5dSMike Smith {
170215e32d5dSMike Smith     ACPI_STATUS	status = AE_OK;
170356d8cb57SMitsuru IWASAKI     UINT8	TypeA;
170456d8cb57SMitsuru IWASAKI     UINT8	TypeB;
170515e32d5dSMike Smith 
1706b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
1707cb9b0d80SMike Smith     ACPI_ASSERTLOCK;
17080ae55423SMike Smith 
170998175614SNate Lawson     /* Avoid reentry if already attempting to suspend. */
17106397624dSMitsuru IWASAKI     if (sc->acpi_sstate != ACPI_STATE_S0)
171198175614SNate Lawson 	return_ACPI_STATUS (AE_BAD_PARAMETER);
17126397624dSMitsuru IWASAKI 
171398175614SNate Lawson     /* We recently woke up so don't suspend again for a while. */
1714ece50487SMitsuru IWASAKI     if (sc->acpi_sleep_disabled)
1715ece50487SMitsuru IWASAKI 	return_ACPI_STATUS (AE_OK);
1716ece50487SMitsuru IWASAKI 
171715e32d5dSMike Smith     switch (state) {
171815e32d5dSMike Smith     case ACPI_STATE_S1:
17196161544cSTakanori Watanabe     case ACPI_STATE_S2:
17206161544cSTakanori Watanabe     case ACPI_STATE_S3:
17216161544cSTakanori Watanabe     case ACPI_STATE_S4:
1722be2b1797SNate Lawson 	status = AcpiGetSleepTypeData((UINT8)state, &TypeA, &TypeB);
172398175614SNate Lawson 	if (status == AE_NOT_FOUND) {
172498175614SNate Lawson 	    device_printf(sc->acpi_dev,
172598175614SNate Lawson 			  "Sleep state S%d not supported by BIOS\n", state);
172698175614SNate Lawson 	    break;
172798175614SNate Lawson 	} else if (ACPI_FAILURE(status)) {
1728be2b1797SNate Lawson 	    device_printf(sc->acpi_dev, "AcpiGetSleepTypeData failed - %s\n",
1729be2b1797SNate Lawson 			  AcpiFormatException(status));
173056d8cb57SMitsuru IWASAKI 	    break;
173156d8cb57SMitsuru IWASAKI 	}
173256d8cb57SMitsuru IWASAKI 
1733a1fccb47SMitsuru IWASAKI 	sc->acpi_sstate = state;
1734a1fccb47SMitsuru IWASAKI 	sc->acpi_sleep_disabled = 1;
1735a1fccb47SMitsuru IWASAKI 
1736be2b1797SNate Lawson 	/* Inform all devices that we are going to sleep. */
173715e32d5dSMike Smith 	if (DEVICE_SUSPEND(root_bus) != 0) {
173815e32d5dSMike Smith 	    /*
173915e32d5dSMike Smith 	     * Re-wake the system.
174015e32d5dSMike Smith 	     *
174115e32d5dSMike Smith 	     * XXX note that a better two-pass approach with a 'veto' pass
174215e32d5dSMike Smith 	     *     followed by a "real thing" pass would be better, but the
174315e32d5dSMike Smith 	     *     current bus interface does not provide for this.
174415e32d5dSMike Smith 	     */
174515e32d5dSMike Smith 	    DEVICE_RESUME(root_bus);
17460ae55423SMike Smith 	    return_ACPI_STATUS (AE_ERROR);
174715e32d5dSMike Smith 	}
1748b9c780d6SMitsuru IWASAKI 
1749be2b1797SNate Lawson 	status = AcpiEnterSleepStatePrep(state);
1750be2b1797SNate Lawson 	if (ACPI_FAILURE(status)) {
1751b9c780d6SMitsuru IWASAKI 	    device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n",
1752b9c780d6SMitsuru IWASAKI 			  AcpiFormatException(status));
1753b9c780d6SMitsuru IWASAKI 	    break;
1754b9c780d6SMitsuru IWASAKI 	}
1755b9c780d6SMitsuru IWASAKI 
1756be2b1797SNate Lawson 	if (sc->acpi_sleep_delay > 0)
1757ff01efb5SMitsuru IWASAKI 	    DELAY(sc->acpi_sleep_delay * 1000000);
1758ff01efb5SMitsuru IWASAKI 
17596161544cSTakanori Watanabe 	if (state != ACPI_STATE_S1) {
17606161544cSTakanori Watanabe 	    acpi_sleep_machdep(sc, state);
17616161544cSTakanori Watanabe 
1762be2b1797SNate Lawson 	    /* AcpiEnterSleepState() may be incomplete, unlock if locked. */
176359ddeb18SNate Lawson 	    if (AcpiGbl_MutexInfo[ACPI_MTX_HARDWARE].OwnerId !=
176459ddeb18SNate Lawson 		ACPI_MUTEX_NOT_ACQUIRED) {
176559ddeb18SNate Lawson 
17666161544cSTakanori Watanabe 		AcpiUtReleaseMutex(ACPI_MTX_HARDWARE);
1767a1fccb47SMitsuru IWASAKI 	    }
17686161544cSTakanori Watanabe 
17696161544cSTakanori Watanabe 	    /* Re-enable ACPI hardware on wakeup from sleep state 4. */
1770be2b1797SNate Lawson 	    if (state == ACPI_STATE_S4)
1771964679ceSMitsuru IWASAKI 		AcpiEnable();
17726161544cSTakanori Watanabe 	} else {
1773be2b1797SNate Lawson 	    status = AcpiEnterSleepState((UINT8)state);
1774be2b1797SNate Lawson 	    if (ACPI_FAILURE(status)) {
1775be2b1797SNate Lawson 		device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n",
1776be2b1797SNate Lawson 			      AcpiFormatException(status));
1777c30382dfSMitsuru IWASAKI 		break;
177815e32d5dSMike Smith 	    }
17796161544cSTakanori Watanabe 	}
1780ff741befSTakanori Watanabe 	AcpiLeaveSleepState((UINT8)state);
178115e32d5dSMike Smith 	DEVICE_RESUME(root_bus);
178215e32d5dSMike Smith 	sc->acpi_sstate = ACPI_STATE_S0;
178313d4f7baSMitsuru IWASAKI 	acpi_enable_fixed_events(sc);
178415e32d5dSMike Smith 	break;
178515e32d5dSMike Smith     case ACPI_STATE_S5:
178615e32d5dSMike Smith 	/*
178715e32d5dSMike Smith 	 * Shut down cleanly and power off.  This will call us back through the
178815e32d5dSMike Smith 	 * shutdown handlers.
178915e32d5dSMike Smith 	 */
179015e32d5dSMike Smith 	shutdown_nice(RB_POWEROFF);
179115e32d5dSMike Smith 	break;
179298175614SNate Lawson     case ACPI_STATE_S0:
179315e32d5dSMike Smith     default:
179415e32d5dSMike Smith 	status = AE_BAD_PARAMETER;
179515e32d5dSMike Smith 	break;
179615e32d5dSMike Smith     }
1797ece50487SMitsuru IWASAKI 
179898175614SNate Lawson     /* Disable a second sleep request for a short period */
1799ece50487SMitsuru IWASAKI     if (sc->acpi_sleep_disabled)
1800ece50487SMitsuru IWASAKI 	timeout(acpi_sleep_enable, (caddr_t)sc, hz * ACPI_MINIMUM_AWAKETIME);
1801ece50487SMitsuru IWASAKI 
18020ae55423SMike Smith     return_ACPI_STATUS (status);
180315e32d5dSMike Smith }
180415e32d5dSMike Smith 
180515e32d5dSMike Smith /*
180615e32d5dSMike Smith  * Enable/Disable ACPI
180715e32d5dSMike Smith  */
180815e32d5dSMike Smith ACPI_STATUS
180915e32d5dSMike Smith acpi_Enable(struct acpi_softc *sc)
181015e32d5dSMike Smith {
181115e32d5dSMike Smith     ACPI_STATUS	status;
181215e32d5dSMike Smith     u_int32_t	flags;
181315e32d5dSMike Smith 
1814b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1815cb9b0d80SMike Smith     ACPI_ASSERTLOCK;
18160ae55423SMike Smith 
181715e32d5dSMike Smith     flags = ACPI_NO_ADDRESS_SPACE_INIT | ACPI_NO_HARDWARE_INIT |
181815e32d5dSMike Smith 	    ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT;
1819be2b1797SNate Lawson     if (!sc->acpi_enabled)
182015e32d5dSMike Smith 	status = AcpiEnableSubsystem(flags);
1821be2b1797SNate Lawson     else
182215e32d5dSMike Smith 	status = AE_OK;
1823be2b1797SNate Lawson 
182415e32d5dSMike Smith     if (status == AE_OK)
182515e32d5dSMike Smith 	sc->acpi_enabled = 1;
1826be2b1797SNate Lawson 
18270ae55423SMike Smith     return_ACPI_STATUS (status);
182815e32d5dSMike Smith }
182915e32d5dSMike Smith 
183015e32d5dSMike Smith ACPI_STATUS
183115e32d5dSMike Smith acpi_Disable(struct acpi_softc *sc)
183215e32d5dSMike Smith {
183315e32d5dSMike Smith     ACPI_STATUS	status;
183415e32d5dSMike Smith 
1835b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1836cb9b0d80SMike Smith     ACPI_ASSERTLOCK;
18370ae55423SMike Smith 
1838be2b1797SNate Lawson     if (sc->acpi_enabled)
183915e32d5dSMike Smith 	status = AcpiDisable();
1840be2b1797SNate Lawson     else
184115e32d5dSMike Smith 	status = AE_OK;
1842be2b1797SNate Lawson 
184315e32d5dSMike Smith     if (status == AE_OK)
184415e32d5dSMike Smith 	sc->acpi_enabled = 0;
1845be2b1797SNate Lawson 
18460ae55423SMike Smith     return_ACPI_STATUS (status);
184715e32d5dSMike Smith }
184815e32d5dSMike Smith 
184915e32d5dSMike Smith /*
185015e32d5dSMike Smith  * ACPI Event Handlers
185115e32d5dSMike Smith  */
185215e32d5dSMike Smith 
185315e32d5dSMike Smith /* System Event Handlers (registered by EVENTHANDLER_REGISTER) */
185415e32d5dSMike Smith 
185515e32d5dSMike Smith static void
185615e32d5dSMike Smith acpi_system_eventhandler_sleep(void *arg, int state)
185715e32d5dSMike Smith {
1858fc0ea94aSJohn Baldwin     ACPI_LOCK_DECL;
1859b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
186015e32d5dSMike Smith 
1861cb9b0d80SMike Smith     ACPI_LOCK;
1862a5d1879bSMitsuru IWASAKI     if (state >= ACPI_STATE_S0 && state <= ACPI_S_STATES_MAX)
186315e32d5dSMike Smith 	acpi_SetSleepState((struct acpi_softc *)arg, state);
1864cb9b0d80SMike Smith     ACPI_UNLOCK;
18650ae55423SMike Smith     return_VOID;
186615e32d5dSMike Smith }
186715e32d5dSMike Smith 
186815e32d5dSMike Smith static void
186915e32d5dSMike Smith acpi_system_eventhandler_wakeup(void *arg, int state)
187015e32d5dSMike Smith {
1871fc0ea94aSJohn Baldwin     ACPI_LOCK_DECL;
1872b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
18730ae55423SMike Smith 
187415e32d5dSMike Smith     /* Well, what to do? :-) */
18750ae55423SMike Smith 
1876cb9b0d80SMike Smith     ACPI_LOCK;
1877cb9b0d80SMike Smith     ACPI_UNLOCK;
1878cb9b0d80SMike Smith 
18790ae55423SMike Smith     return_VOID;
188015e32d5dSMike Smith }
188115e32d5dSMike Smith 
188215e32d5dSMike Smith /*
188315e32d5dSMike Smith  * ACPICA Event Handlers (FixedEvent, also called from button notify handler)
188415e32d5dSMike Smith  */
188515e32d5dSMike Smith UINT32
188633febf93SNate Lawson acpi_event_power_button_sleep(void *context)
188715e32d5dSMike Smith {
188815e32d5dSMike Smith     struct acpi_softc	*sc = (struct acpi_softc *)context;
188915e32d5dSMike Smith 
1890b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
18910ae55423SMike Smith 
189215e32d5dSMike Smith     EVENTHANDLER_INVOKE(acpi_sleep_event, sc->acpi_power_button_sx);
18930ae55423SMike Smith 
1894b53f2771SMike Smith     return_VALUE (ACPI_INTERRUPT_HANDLED);
189515e32d5dSMike Smith }
189615e32d5dSMike Smith 
189715e32d5dSMike Smith UINT32
189833febf93SNate Lawson acpi_event_power_button_wake(void *context)
189915e32d5dSMike Smith {
190015e32d5dSMike Smith     struct acpi_softc	*sc = (struct acpi_softc *)context;
190115e32d5dSMike Smith 
1902b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
19030ae55423SMike Smith 
190415e32d5dSMike Smith     EVENTHANDLER_INVOKE(acpi_wakeup_event, sc->acpi_power_button_sx);
19050ae55423SMike Smith 
1906b53f2771SMike Smith     return_VALUE (ACPI_INTERRUPT_HANDLED);
190715e32d5dSMike Smith }
190815e32d5dSMike Smith 
190915e32d5dSMike Smith UINT32
191033febf93SNate Lawson acpi_event_sleep_button_sleep(void *context)
191115e32d5dSMike Smith {
191215e32d5dSMike Smith     struct acpi_softc	*sc = (struct acpi_softc *)context;
191315e32d5dSMike Smith 
1914b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
19150ae55423SMike Smith 
191615e32d5dSMike Smith     EVENTHANDLER_INVOKE(acpi_sleep_event, sc->acpi_sleep_button_sx);
19170ae55423SMike Smith 
1918b53f2771SMike Smith     return_VALUE (ACPI_INTERRUPT_HANDLED);
191915e32d5dSMike Smith }
192015e32d5dSMike Smith 
192115e32d5dSMike Smith UINT32
192233febf93SNate Lawson acpi_event_sleep_button_wake(void *context)
192315e32d5dSMike Smith {
192415e32d5dSMike Smith     struct acpi_softc	*sc = (struct acpi_softc *)context;
192515e32d5dSMike Smith 
1926b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
19270ae55423SMike Smith 
192815e32d5dSMike Smith     EVENTHANDLER_INVOKE(acpi_wakeup_event, sc->acpi_sleep_button_sx);
19290ae55423SMike Smith 
1930b53f2771SMike Smith     return_VALUE (ACPI_INTERRUPT_HANDLED);
193115e32d5dSMike Smith }
193215e32d5dSMike Smith 
193315e32d5dSMike Smith /*
193415e32d5dSMike Smith  * XXX This is kinda ugly, and should not be here.
193515e32d5dSMike Smith  */
193615e32d5dSMike Smith struct acpi_staticbuf {
193715e32d5dSMike Smith     ACPI_BUFFER	buffer;
193815e32d5dSMike Smith     char	data[512];
193915e32d5dSMike Smith };
194015e32d5dSMike Smith 
194115e32d5dSMike Smith char *
194215e32d5dSMike Smith acpi_name(ACPI_HANDLE handle)
194315e32d5dSMike Smith {
194415e32d5dSMike Smith     static struct acpi_staticbuf	buf;
194515e32d5dSMike Smith 
1946cb9b0d80SMike Smith     ACPI_ASSERTLOCK;
1947cb9b0d80SMike Smith 
194815e32d5dSMike Smith     buf.buffer.Length = 512;
194915e32d5dSMike Smith     buf.buffer.Pointer = &buf.data[0];
195015e32d5dSMike Smith 
1951b53f2771SMike Smith     if (ACPI_SUCCESS(AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf.buffer)))
195215e32d5dSMike Smith 	return (buf.buffer.Pointer);
1953be2b1797SNate Lawson 
195415e32d5dSMike Smith     return ("(unknown path)");
195515e32d5dSMike Smith }
195615e32d5dSMike Smith 
195715e32d5dSMike Smith /*
195815e32d5dSMike Smith  * Debugging/bug-avoidance.  Avoid trying to fetch info on various
195915e32d5dSMike Smith  * parts of the namespace.
196015e32d5dSMike Smith  */
196115e32d5dSMike Smith int
196215e32d5dSMike Smith acpi_avoid(ACPI_HANDLE handle)
196315e32d5dSMike Smith {
19643c600cfbSJohn Baldwin     char	*cp, *env, *np;
196515e32d5dSMike Smith     int		len;
196615e32d5dSMike Smith 
196715e32d5dSMike Smith     np = acpi_name(handle);
196815e32d5dSMike Smith     if (*np == '\\')
196915e32d5dSMike Smith 	np++;
19703c600cfbSJohn Baldwin     if ((env = getenv("debug.acpi.avoid")) == NULL)
197115e32d5dSMike Smith 	return (0);
197215e32d5dSMike Smith 
1973be2b1797SNate Lawson     /* Scan the avoid list checking for a match */
19743c600cfbSJohn Baldwin     cp = env;
197515e32d5dSMike Smith     for (;;) {
197615e32d5dSMike Smith 	while ((*cp != 0) && isspace(*cp))
197715e32d5dSMike Smith 	    cp++;
197815e32d5dSMike Smith 	if (*cp == 0)
197915e32d5dSMike Smith 	    break;
198015e32d5dSMike Smith 	len = 0;
198115e32d5dSMike Smith 	while ((cp[len] != 0) && !isspace(cp[len]))
198215e32d5dSMike Smith 	    len++;
1983d786139cSMaxime Henrion 	if (!strncmp(cp, np, len)) {
19843c600cfbSJohn Baldwin 	    freeenv(env);
19850ae55423SMike Smith 	    return(1);
1986d786139cSMaxime Henrion 	}
19870ae55423SMike Smith 	cp += len;
19880ae55423SMike Smith     }
19893c600cfbSJohn Baldwin     freeenv(env);
1990be2b1797SNate Lawson 
19910ae55423SMike Smith     return (0);
19920ae55423SMike Smith }
19930ae55423SMike Smith 
19940ae55423SMike Smith /*
19950ae55423SMike Smith  * Debugging/bug-avoidance.  Disable ACPI subsystem components.
19960ae55423SMike Smith  */
19970ae55423SMike Smith int
19980ae55423SMike Smith acpi_disabled(char *subsys)
19990ae55423SMike Smith {
200078689b15SMaxime Henrion     char	*cp, *env;
20010ae55423SMike Smith     int		len;
20020ae55423SMike Smith 
20033184cf5aSNate Lawson     if ((env = getenv("debug.acpi.disabled")) == NULL)
20040ae55423SMike Smith 	return (0);
20053184cf5aSNate Lawson     if (strcmp(env, "all") == 0) {
200678689b15SMaxime Henrion 	freeenv(env);
20070ae55423SMike Smith 	return (1);
2008d786139cSMaxime Henrion     }
20090ae55423SMike Smith 
20103184cf5aSNate Lawson     /* Scan the disable list, checking for a match. */
201178689b15SMaxime Henrion     cp = env;
20120ae55423SMike Smith     for (;;) {
20133184cf5aSNate Lawson 	while (*cp != '\0' && isspace(*cp))
20140ae55423SMike Smith 	    cp++;
20153184cf5aSNate Lawson 	if (*cp == '\0')
20160ae55423SMike Smith 	    break;
20170ae55423SMike Smith 	len = 0;
20183184cf5aSNate Lawson 	while (cp[len] != '\0' && !isspace(cp[len]))
20190ae55423SMike Smith 	    len++;
20203184cf5aSNate Lawson 	if (strncmp(cp, subsys, len) == 0) {
202178689b15SMaxime Henrion 	    freeenv(env);
202215e32d5dSMike Smith 	    return (1);
2023d786139cSMaxime Henrion 	}
202415e32d5dSMike Smith 	cp += len;
202515e32d5dSMike Smith     }
202678689b15SMaxime Henrion     freeenv(env);
2027be2b1797SNate Lawson 
202815e32d5dSMike Smith     return (0);
202915e32d5dSMike Smith }
203015e32d5dSMike Smith 
203115e32d5dSMike Smith /*
2032a1fccb47SMitsuru IWASAKI  * Device wake capability enable/disable.
2033a1fccb47SMitsuru IWASAKI  */
2034a1fccb47SMitsuru IWASAKI void
2035a1fccb47SMitsuru IWASAKI acpi_device_enable_wake_capability(ACPI_HANDLE h, int enable)
2036a1fccb47SMitsuru IWASAKI {
2037a1fccb47SMitsuru IWASAKI     /*
2038a1fccb47SMitsuru IWASAKI      * TBD: All Power Resources referenced by elements 2 through N
2039a1fccb47SMitsuru IWASAKI      *      of the _PRW object are put into the ON state.
2040a1fccb47SMitsuru IWASAKI      */
2041a1fccb47SMitsuru IWASAKI 
2042c310653eSNate Lawson     (void)acpi_SetInteger(h, "_PSW", enable);
2043a1fccb47SMitsuru IWASAKI }
2044a1fccb47SMitsuru IWASAKI 
2045a1fccb47SMitsuru IWASAKI void
2046a1fccb47SMitsuru IWASAKI acpi_device_enable_wake_event(ACPI_HANDLE h)
2047a1fccb47SMitsuru IWASAKI {
2048a1fccb47SMitsuru IWASAKI     struct acpi_softc		*sc;
2049a1fccb47SMitsuru IWASAKI     ACPI_STATUS			status;
2050a1fccb47SMitsuru IWASAKI     ACPI_BUFFER			prw_buffer;
2051a1fccb47SMitsuru IWASAKI     ACPI_OBJECT			*res;
2052a1fccb47SMitsuru IWASAKI 
2053a1fccb47SMitsuru IWASAKI     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
2054a1fccb47SMitsuru IWASAKI 
2055be2b1797SNate Lawson     sc = devclass_get_softc(acpi_devclass, 0);
2056be2b1797SNate Lawson     if (sc == NULL)
2057a1fccb47SMitsuru IWASAKI 	return;
2058a1fccb47SMitsuru IWASAKI 
2059a1fccb47SMitsuru IWASAKI     /*
2060a1fccb47SMitsuru IWASAKI      * _PRW object is only required for devices that have the ability
2061a1fccb47SMitsuru IWASAKI      * to wake the system from a system sleeping state.
2062a1fccb47SMitsuru IWASAKI      */
2063a1fccb47SMitsuru IWASAKI     prw_buffer.Length = ACPI_ALLOCATE_BUFFER;
2064a1fccb47SMitsuru IWASAKI     status = AcpiEvaluateObject(h, "_PRW", NULL, &prw_buffer);
2065be2b1797SNate Lawson     if (ACPI_FAILURE(status))
2066a1fccb47SMitsuru IWASAKI 	return;
2067a1fccb47SMitsuru IWASAKI 
2068a1fccb47SMitsuru IWASAKI     res = (ACPI_OBJECT *)prw_buffer.Pointer;
2069be2b1797SNate Lawson     if (res == NULL)
2070a1fccb47SMitsuru IWASAKI 	return;
2071a1fccb47SMitsuru IWASAKI 
2072a1fccb47SMitsuru IWASAKI     if ((res->Type != ACPI_TYPE_PACKAGE) || (res->Package.Count < 2)) {
2073a1fccb47SMitsuru IWASAKI 	goto out;
2074a1fccb47SMitsuru IWASAKI     }
2075a1fccb47SMitsuru IWASAKI 
2076a1fccb47SMitsuru IWASAKI     /*
2077a1fccb47SMitsuru IWASAKI      * The element 1 of the _PRW object:
2078a1fccb47SMitsuru IWASAKI      * The lowest power system sleeping state that can be entered
2079a1fccb47SMitsuru IWASAKI      * while still providing wake functionality.
2080a1fccb47SMitsuru IWASAKI      * The sleeping state being entered must be greater or equal to
2081a1fccb47SMitsuru IWASAKI      * the power state declared in element 1 of the _PRW object.
2082a1fccb47SMitsuru IWASAKI      */
2083be2b1797SNate Lawson     if (res->Package.Elements[1].Type != ACPI_TYPE_INTEGER)
2084a1fccb47SMitsuru IWASAKI 	goto out;
2085a1fccb47SMitsuru IWASAKI 
2086be2b1797SNate Lawson     if (sc->acpi_sstate > res->Package.Elements[1].Integer.Value)
2087a1fccb47SMitsuru IWASAKI 	goto out;
2088a1fccb47SMitsuru IWASAKI 
2089a1fccb47SMitsuru IWASAKI     /*
2090a1fccb47SMitsuru IWASAKI      * The element 0 of the _PRW object:
2091a1fccb47SMitsuru IWASAKI      */
2092a1fccb47SMitsuru IWASAKI     switch(res->Package.Elements[0].Type) {
2093a1fccb47SMitsuru IWASAKI     case ACPI_TYPE_INTEGER:
2094a1fccb47SMitsuru IWASAKI 	/*
2095a1fccb47SMitsuru IWASAKI 	 * If the data type of this package element is numeric, then this
2096a1fccb47SMitsuru IWASAKI 	 * _PRW package element is the bit index in the GPEx_EN, in the
2097a1fccb47SMitsuru IWASAKI 	 * GPE blocks described in the FADT, of the enable bit that is
2098a1fccb47SMitsuru IWASAKI 	 * enabled for the wake event.
2099a1fccb47SMitsuru IWASAKI 	 */
2100a1fccb47SMitsuru IWASAKI 
21016fca9360SNate Lawson 	status = AcpiEnableGpe(NULL, res->Package.Elements[0].Integer.Value,
21026fca9360SNate Lawson 			       ACPI_EVENT_WAKE_ENABLE);
2103a1fccb47SMitsuru IWASAKI 	if (ACPI_FAILURE(status))
2104a1fccb47SMitsuru IWASAKI 	    printf("%s: EnableEvent Failed\n", __func__);
2105a1fccb47SMitsuru IWASAKI 	break;
2106a1fccb47SMitsuru IWASAKI     case ACPI_TYPE_PACKAGE:
2107a1fccb47SMitsuru IWASAKI 	/*
2108be2b1797SNate Lawson 	 * XXX TBD
2109be2b1797SNate Lawson 	 *
2110a1fccb47SMitsuru IWASAKI 	 * If the data type of this package element is a package, then this
2111a1fccb47SMitsuru IWASAKI 	 * _PRW package element is itself a package containing two
2112a1fccb47SMitsuru IWASAKI 	 * elements. The first is an object reference to the GPE Block
2113a1fccb47SMitsuru IWASAKI 	 * device that contains the GPE that will be triggered by the wake
2114a1fccb47SMitsuru IWASAKI 	 * event. The second element is numeric and it contains the bit
2115a1fccb47SMitsuru IWASAKI 	 * index in the GPEx_EN, in the GPE Block referenced by the
2116a1fccb47SMitsuru IWASAKI 	 * first element in the package, of the enable bit that is enabled for
2117a1fccb47SMitsuru IWASAKI 	 * the wake event.
2118a1fccb47SMitsuru IWASAKI 	 * For example, if this field is a package then it is of the form:
2119a1fccb47SMitsuru IWASAKI 	 * Package() {\_SB.PCI0.ISA.GPE, 2}
2120a1fccb47SMitsuru IWASAKI 	 */
2121a1fccb47SMitsuru IWASAKI 	break;
2122a1fccb47SMitsuru IWASAKI     default:
2123a1fccb47SMitsuru IWASAKI 	break;
2124a1fccb47SMitsuru IWASAKI     }
2125a1fccb47SMitsuru IWASAKI 
2126a1fccb47SMitsuru IWASAKI out:
2127a1fccb47SMitsuru IWASAKI     if (prw_buffer.Pointer != NULL)
2128a1fccb47SMitsuru IWASAKI 	AcpiOsFree(prw_buffer.Pointer);
2129a1fccb47SMitsuru IWASAKI }
2130a1fccb47SMitsuru IWASAKI 
2131a1fccb47SMitsuru IWASAKI /*
213215e32d5dSMike Smith  * Control interface.
213315e32d5dSMike Smith  *
21340ae55423SMike Smith  * We multiplex ioctls for all participating ACPI devices here.  Individual
2135be2b1797SNate Lawson  * drivers wanting to be accessible via /dev/acpi should use the
2136be2b1797SNate Lawson  * register/deregister interface to make their handlers visible.
213715e32d5dSMike Smith  */
21380ae55423SMike Smith struct acpi_ioctl_hook
21390ae55423SMike Smith {
21400ae55423SMike Smith     TAILQ_ENTRY(acpi_ioctl_hook) link;
21410ae55423SMike Smith     u_long			 cmd;
2142be2b1797SNate Lawson     acpi_ioctl_fn		 fn;
21430ae55423SMike Smith     void			 *arg;
21440ae55423SMike Smith };
21450ae55423SMike Smith 
21460ae55423SMike Smith static TAILQ_HEAD(,acpi_ioctl_hook)	acpi_ioctl_hooks;
21470ae55423SMike Smith static int				acpi_ioctl_hooks_initted;
21480ae55423SMike Smith 
21490ae55423SMike Smith /*
21500ae55423SMike Smith  * Register an ioctl handler.
21510ae55423SMike Smith  */
21520ae55423SMike Smith int
2153be2b1797SNate Lawson acpi_register_ioctl(u_long cmd, acpi_ioctl_fn fn, void *arg)
21540ae55423SMike Smith {
21550ae55423SMike Smith     struct acpi_ioctl_hook	*hp;
21560ae55423SMike Smith 
21570ae55423SMike Smith     if ((hp = malloc(sizeof(*hp), M_ACPIDEV, M_NOWAIT)) == NULL)
21580ae55423SMike Smith 	return (ENOMEM);
21590ae55423SMike Smith     hp->cmd = cmd;
21600ae55423SMike Smith     hp->fn = fn;
21610ae55423SMike Smith     hp->arg = arg;
21620ae55423SMike Smith     if (acpi_ioctl_hooks_initted == 0) {
21630ae55423SMike Smith 	TAILQ_INIT(&acpi_ioctl_hooks);
21640ae55423SMike Smith 	acpi_ioctl_hooks_initted = 1;
21650ae55423SMike Smith     }
21660ae55423SMike Smith     TAILQ_INSERT_TAIL(&acpi_ioctl_hooks, hp, link);
21670ae55423SMike Smith     return (0);
21680ae55423SMike Smith }
21690ae55423SMike Smith 
21700ae55423SMike Smith /*
21710ae55423SMike Smith  * Deregister an ioctl handler.
21720ae55423SMike Smith  */
21730ae55423SMike Smith void
2174be2b1797SNate Lawson acpi_deregister_ioctl(u_long cmd, acpi_ioctl_fn fn)
21750ae55423SMike Smith {
21760ae55423SMike Smith     struct acpi_ioctl_hook	*hp;
21770ae55423SMike Smith 
21780ae55423SMike Smith     TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link)
21790ae55423SMike Smith 	if ((hp->cmd == cmd) && (hp->fn == fn))
21800ae55423SMike Smith 	    break;
21810ae55423SMike Smith 
21820ae55423SMike Smith     if (hp != NULL) {
21830ae55423SMike Smith 	TAILQ_REMOVE(&acpi_ioctl_hooks, hp, link);
21840ae55423SMike Smith 	free(hp, M_ACPIDEV);
21850ae55423SMike Smith     }
21860ae55423SMike Smith }
21870ae55423SMike Smith 
218815e32d5dSMike Smith static int
21896b4d1b08SJohn Baldwin acpiopen(dev_t dev, int flag, int fmt, d_thread_t *td)
219015e32d5dSMike Smith {
219115e32d5dSMike Smith     return (0);
219215e32d5dSMike Smith }
219315e32d5dSMike Smith 
219415e32d5dSMike Smith static int
21956b4d1b08SJohn Baldwin acpiclose(dev_t dev, int flag, int fmt, d_thread_t *td)
219615e32d5dSMike Smith {
219715e32d5dSMike Smith     return (0);
219815e32d5dSMike Smith }
219915e32d5dSMike Smith 
220015e32d5dSMike Smith static int
22016b4d1b08SJohn Baldwin acpiioctl(dev_t dev, u_long cmd, caddr_t addr, int flag, d_thread_t *td)
220215e32d5dSMike Smith {
220315e32d5dSMike Smith     struct acpi_softc		*sc;
22040ae55423SMike Smith     struct acpi_ioctl_hook	*hp;
22050ae55423SMike Smith     int				error, xerror, state;
2206fc0ea94aSJohn Baldwin     ACPI_LOCK_DECL;
220715e32d5dSMike Smith 
2208cb9b0d80SMike Smith     ACPI_LOCK;
2209cb9b0d80SMike Smith 
221015e32d5dSMike Smith     error = state = 0;
221115e32d5dSMike Smith     sc = dev->si_drv1;
221215e32d5dSMike Smith 
22130ae55423SMike Smith     /*
22140ae55423SMike Smith      * Scan the list of registered ioctls, looking for handlers.
22150ae55423SMike Smith      */
22160ae55423SMike Smith     if (acpi_ioctl_hooks_initted) {
22170ae55423SMike Smith 	TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link) {
22180ae55423SMike Smith 	    if (hp->cmd == cmd) {
22190ae55423SMike Smith 		xerror = hp->fn(cmd, addr, hp->arg);
22200ae55423SMike Smith 		if (xerror != 0)
22210ae55423SMike Smith 		    error = xerror;
2222917d44c8SMitsuru IWASAKI 		goto out;
22230ae55423SMike Smith 	    }
22240ae55423SMike Smith 	}
22250ae55423SMike Smith     }
22260ae55423SMike Smith 
22270ae55423SMike Smith     /*
2228a89fcf28STakanori Watanabe      * Core ioctls are not permitted for non-writable user.
2229a89fcf28STakanori Watanabe      * Currently, other ioctls just fetch information.
2230a89fcf28STakanori Watanabe      * Not changing system behavior.
2231a89fcf28STakanori Watanabe      */
2232be2b1797SNate Lawson     if((flag & FWRITE) == 0)
2233be2b1797SNate Lawson 	return (EPERM);
2234a89fcf28STakanori Watanabe 
2235be2b1797SNate Lawson     /* Core system ioctls. */
223615e32d5dSMike Smith     switch (cmd) {
223715e32d5dSMike Smith     case ACPIIO_ENABLE:
22380ae55423SMike Smith 	if (ACPI_FAILURE(acpi_Enable(sc)))
223915e32d5dSMike Smith 	    error = ENXIO;
224015e32d5dSMike Smith 	break;
224115e32d5dSMike Smith     case ACPIIO_DISABLE:
22420ae55423SMike Smith 	if (ACPI_FAILURE(acpi_Disable(sc)))
224315e32d5dSMike Smith 	    error = ENXIO;
224415e32d5dSMike Smith 	break;
224515e32d5dSMike Smith     case ACPIIO_SETSLPSTATE:
224615e32d5dSMike Smith 	if (!sc->acpi_enabled) {
224715e32d5dSMike Smith 	    error = ENXIO;
224815e32d5dSMike Smith 	    break;
224915e32d5dSMike Smith 	}
225015e32d5dSMike Smith 	state = *(int *)addr;
22512d610c46SNate Lawson 	if (state >= ACPI_STATE_S0  && state <= ACPI_S_STATES_MAX) {
22522d610c46SNate Lawson 	    if (ACPI_FAILURE(acpi_SetSleepState(sc, state)))
225315e32d5dSMike Smith 		error = EINVAL;
22542d610c46SNate Lawson 	} else {
22552d610c46SNate Lawson 	    error = EINVAL;
22562d610c46SNate Lawson 	}
225715e32d5dSMike Smith 	break;
225815e32d5dSMike Smith     default:
22590ae55423SMike Smith 	if (error == 0)
226015e32d5dSMike Smith 	    error = EINVAL;
226115e32d5dSMike Smith 	break;
226215e32d5dSMike Smith     }
2263917d44c8SMitsuru IWASAKI 
2264917d44c8SMitsuru IWASAKI out:
2265cb9b0d80SMike Smith     ACPI_UNLOCK;
226615e32d5dSMike Smith     return (error);
226715e32d5dSMike Smith }
226815e32d5dSMike Smith 
22691d073b1dSJohn Baldwin static int
2270d75de536SMitsuru IWASAKI acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS)
2271d75de536SMitsuru IWASAKI {
2272d75de536SMitsuru IWASAKI     char sleep_state[4];
2273d75de536SMitsuru IWASAKI     char buf[16];
2274d75de536SMitsuru IWASAKI     int error;
2275d75de536SMitsuru IWASAKI     UINT8 state, TypeA, TypeB;
2276d75de536SMitsuru IWASAKI 
2277d75de536SMitsuru IWASAKI     buf[0] = '\0';
2278d75de536SMitsuru IWASAKI     for (state = ACPI_STATE_S1; state < ACPI_S_STATES_MAX+1; state++) {
2279d75de536SMitsuru IWASAKI 	if (ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB))) {
2280d75de536SMitsuru IWASAKI 	    sprintf(sleep_state, "S%d ", state);
2281d75de536SMitsuru IWASAKI 	    strcat(buf, sleep_state);
2282d75de536SMitsuru IWASAKI 	}
2283d75de536SMitsuru IWASAKI     }
2284d75de536SMitsuru IWASAKI     error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
2285d75de536SMitsuru IWASAKI     return (error);
2286d75de536SMitsuru IWASAKI }
2287d75de536SMitsuru IWASAKI 
2288d75de536SMitsuru IWASAKI static int
22891d073b1dSJohn Baldwin acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS)
22901d073b1dSJohn Baldwin {
22911d073b1dSJohn Baldwin     char sleep_state[10];
22921d073b1dSJohn Baldwin     int error;
22931d073b1dSJohn Baldwin     u_int new_state, old_state;
22941d073b1dSJohn Baldwin 
22951d073b1dSJohn Baldwin     old_state = *(u_int *)oidp->oid_arg1;
2296b8670bedSMitsuru IWASAKI     if (old_state > ACPI_S_STATES_MAX+1) {
22971d073b1dSJohn Baldwin 	strcpy(sleep_state, "unknown");
2298cb9b0d80SMike Smith     } else {
2299b8670bedSMitsuru IWASAKI 	bzero(sleep_state, sizeof(sleep_state));
23001d073b1dSJohn Baldwin 	strncpy(sleep_state, sleep_state_names[old_state],
23011d073b1dSJohn Baldwin 		sizeof(sleep_state_names[old_state]));
2302cb9b0d80SMike Smith     }
23031d073b1dSJohn Baldwin     error = sysctl_handle_string(oidp, sleep_state, sizeof(sleep_state), req);
23041d073b1dSJohn Baldwin     if (error == 0 && req->newptr != NULL) {
2305be2b1797SNate Lawson 	new_state = ACPI_STATE_S0;
2306be2b1797SNate Lawson 	for (; new_state <= ACPI_S_STATES_MAX + 1; new_state++) {
23071d073b1dSJohn Baldwin 	    if (strncmp(sleep_state, sleep_state_names[new_state],
23081d073b1dSJohn Baldwin 			sizeof(sleep_state)) == 0)
23091d073b1dSJohn Baldwin 		break;
2310cb9b0d80SMike Smith 	}
2311931a10c9SMitsuru IWASAKI 	if (new_state <= ACPI_S_STATES_MAX + 1) {
2312be2b1797SNate Lawson 	    if (new_state != old_state)
23131d073b1dSJohn Baldwin 		*(u_int *)oidp->oid_arg1 = new_state;
2314cb9b0d80SMike Smith 	} else {
23151d073b1dSJohn Baldwin 	    error = EINVAL;
23161d073b1dSJohn Baldwin 	}
2317cb9b0d80SMike Smith     }
2318be2b1797SNate Lawson 
23191d073b1dSJohn Baldwin     return (error);
23201d073b1dSJohn Baldwin }
23211d073b1dSJohn Baldwin 
23229b937d48SNate Lawson /* Inform devctl(4) when we receive a Notify. */
23239b937d48SNate Lawson void
23249b937d48SNate Lawson acpi_UserNotify(const char *subsystem, ACPI_HANDLE h, uint8_t notify)
23259b937d48SNate Lawson {
23269b937d48SNate Lawson     char		notify_buf[16];
23279b937d48SNate Lawson     ACPI_BUFFER		handle_buf;
23289b937d48SNate Lawson     ACPI_STATUS		status;
23299b937d48SNate Lawson 
23309b937d48SNate Lawson     if (subsystem == NULL)
23319b937d48SNate Lawson 	return;
23329b937d48SNate Lawson 
23339b937d48SNate Lawson     handle_buf.Pointer = NULL;
23349b937d48SNate Lawson     handle_buf.Length = ACPI_ALLOCATE_BUFFER;
23359b937d48SNate Lawson     status = AcpiNsHandleToPathname(h, &handle_buf);
23369b937d48SNate Lawson     if (ACPI_FAILURE(status))
23379b937d48SNate Lawson 	return;
23389b937d48SNate Lawson     snprintf(notify_buf, sizeof(notify_buf), "notify=0x%02x", notify);
23399b937d48SNate Lawson     devctl_notify("ACPI", subsystem, handle_buf.Pointer, notify_buf);
23409b937d48SNate Lawson     AcpiOsFree(handle_buf.Pointer);
23419b937d48SNate Lawson }
23429b937d48SNate Lawson 
234315e32d5dSMike Smith #ifdef ACPI_DEBUG
23440ae55423SMike Smith /*
23450ae55423SMike Smith  * Support for parsing debug options from the kernel environment.
23460ae55423SMike Smith  *
23470ae55423SMike Smith  * Bits may be set in the AcpiDbgLayer and AcpiDbgLevel debug registers
23480ae55423SMike Smith  * by specifying the names of the bits in the debug.acpi.layer and
23490ae55423SMike Smith  * debug.acpi.level environment variables.  Bits may be unset by
23500ae55423SMike Smith  * prefixing the bit name with !.
23510ae55423SMike Smith  */
235215e32d5dSMike Smith struct debugtag
235315e32d5dSMike Smith {
235415e32d5dSMike Smith     char	*name;
235515e32d5dSMike Smith     UINT32	value;
235615e32d5dSMike Smith };
235715e32d5dSMike Smith 
235815e32d5dSMike Smith static struct debugtag	dbg_layer[] = {
2359c5ba0be4SMike Smith     {"ACPI_UTILITIES",		ACPI_UTILITIES},
2360c5ba0be4SMike Smith     {"ACPI_HARDWARE",		ACPI_HARDWARE},
2361c5ba0be4SMike Smith     {"ACPI_EVENTS",		ACPI_EVENTS},
2362c5ba0be4SMike Smith     {"ACPI_TABLES",		ACPI_TABLES},
2363c5ba0be4SMike Smith     {"ACPI_NAMESPACE",		ACPI_NAMESPACE},
2364c5ba0be4SMike Smith     {"ACPI_PARSER",		ACPI_PARSER},
2365c5ba0be4SMike Smith     {"ACPI_DISPATCHER",		ACPI_DISPATCHER},
2366c5ba0be4SMike Smith     {"ACPI_EXECUTER",		ACPI_EXECUTER},
2367c5ba0be4SMike Smith     {"ACPI_RESOURCES",		ACPI_RESOURCES},
2368d62ab2f4SMitsuru IWASAKI     {"ACPI_CA_DEBUGGER",	ACPI_CA_DEBUGGER},
23694c1cdee6SMike Smith     {"ACPI_OS_SERVICES",	ACPI_OS_SERVICES},
2370d62ab2f4SMitsuru IWASAKI     {"ACPI_CA_DISASSEMBLER",	ACPI_CA_DISASSEMBLER},
2371297835bcSNate Lawson     {"ACPI_ALL_COMPONENTS",	ACPI_ALL_COMPONENTS},
23724c1cdee6SMike Smith 
2373c5ba0be4SMike Smith     {"ACPI_AC_ADAPTER",		ACPI_AC_ADAPTER},
2374c5ba0be4SMike Smith     {"ACPI_BATTERY",		ACPI_BATTERY},
23753184cf5aSNate Lawson     {"ACPI_BUS",		ACPI_BUS},
2376c5ba0be4SMike Smith     {"ACPI_BUTTON",		ACPI_BUTTON},
23773184cf5aSNate Lawson     {"ACPI_EC", 		ACPI_EC},
23783184cf5aSNate Lawson     {"ACPI_FAN",		ACPI_FAN},
23793184cf5aSNate Lawson     {"ACPI_POWERRES",		ACPI_POWERRES},
23804c1cdee6SMike Smith     {"ACPI_PROCESSOR",		ACPI_PROCESSOR},
2381cb9b0d80SMike Smith     {"ACPI_THERMAL",		ACPI_THERMAL},
23823184cf5aSNate Lawson     {"ACPI_TIMER",		ACPI_TIMER},
2383b53f2771SMike Smith     {"ACPI_ALL_DRIVERS",	ACPI_ALL_DRIVERS},
238415e32d5dSMike Smith     {NULL, 0}
238515e32d5dSMike Smith };
238615e32d5dSMike Smith 
238715e32d5dSMike Smith static struct debugtag dbg_level[] = {
23884c1cdee6SMike Smith     {"ACPI_LV_ERROR",		ACPI_LV_ERROR},
23899501b603SJohn Baldwin     {"ACPI_LV_WARN",		ACPI_LV_WARN},
23909501b603SJohn Baldwin     {"ACPI_LV_INIT",		ACPI_LV_INIT},
23914c1cdee6SMike Smith     {"ACPI_LV_DEBUG_OBJECT",	ACPI_LV_DEBUG_OBJECT},
23929501b603SJohn Baldwin     {"ACPI_LV_INFO",		ACPI_LV_INFO},
23934c1cdee6SMike Smith     {"ACPI_LV_ALL_EXCEPTIONS",	ACPI_LV_ALL_EXCEPTIONS},
2394d62ab2f4SMitsuru IWASAKI 
2395d62ab2f4SMitsuru IWASAKI     /* Trace verbosity level 1 [Standard Trace Level] */
2396297835bcSNate Lawson     {"ACPI_LV_INIT_NAMES",	ACPI_LV_INIT_NAMES},
23974c1cdee6SMike Smith     {"ACPI_LV_PARSE",		ACPI_LV_PARSE},
23984c1cdee6SMike Smith     {"ACPI_LV_LOAD",		ACPI_LV_LOAD},
2399d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_DISPATCH",	ACPI_LV_DISPATCH},
24004c1cdee6SMike Smith     {"ACPI_LV_EXEC",		ACPI_LV_EXEC},
24014c1cdee6SMike Smith     {"ACPI_LV_NAMES",		ACPI_LV_NAMES},
24024c1cdee6SMike Smith     {"ACPI_LV_OPREGION",	ACPI_LV_OPREGION},
24034c1cdee6SMike Smith     {"ACPI_LV_BFIELD",		ACPI_LV_BFIELD},
24044c1cdee6SMike Smith     {"ACPI_LV_TABLES",		ACPI_LV_TABLES},
24054c1cdee6SMike Smith     {"ACPI_LV_VALUES",		ACPI_LV_VALUES},
24064c1cdee6SMike Smith     {"ACPI_LV_OBJECTS",		ACPI_LV_OBJECTS},
24074c1cdee6SMike Smith     {"ACPI_LV_RESOURCES",	ACPI_LV_RESOURCES},
24084c1cdee6SMike Smith     {"ACPI_LV_USER_REQUESTS",	ACPI_LV_USER_REQUESTS},
24094c1cdee6SMike Smith     {"ACPI_LV_PACKAGE",		ACPI_LV_PACKAGE},
2410d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_VERBOSITY1",	ACPI_LV_VERBOSITY1},
2411d62ab2f4SMitsuru IWASAKI 
2412d62ab2f4SMitsuru IWASAKI     /* Trace verbosity level 2 [Function tracing and memory allocation] */
2413d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_ALLOCATIONS",	ACPI_LV_ALLOCATIONS},
2414d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_FUNCTIONS",	ACPI_LV_FUNCTIONS},
2415d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_OPTIMIZATIONS",	ACPI_LV_OPTIMIZATIONS},
2416d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_VERBOSITY2",	ACPI_LV_VERBOSITY2},
24174c1cdee6SMike Smith     {"ACPI_LV_ALL",		ACPI_LV_ALL},
2418d62ab2f4SMitsuru IWASAKI 
2419d62ab2f4SMitsuru IWASAKI     /* Trace verbosity level 3 [Threading, I/O, and Interrupts] */
2420d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_MUTEX",		ACPI_LV_MUTEX},
2421d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_THREADS",		ACPI_LV_THREADS},
2422d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_IO",		ACPI_LV_IO},
2423d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_INTERRUPTS",	ACPI_LV_INTERRUPTS},
2424d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_VERBOSITY3",	ACPI_LV_VERBOSITY3},
2425d62ab2f4SMitsuru IWASAKI 
2426d62ab2f4SMitsuru IWASAKI     /* Exceptionally verbose output -- also used in the global "DebugLevel"  */
242798479b04SMitsuru IWASAKI     {"ACPI_LV_AML_DISASSEMBLE",	ACPI_LV_AML_DISASSEMBLE},
242898479b04SMitsuru IWASAKI     {"ACPI_LV_VERBOSE_INFO",	ACPI_LV_VERBOSE_INFO},
242998479b04SMitsuru IWASAKI     {"ACPI_LV_FULL_TABLES",	ACPI_LV_FULL_TABLES},
243098479b04SMitsuru IWASAKI     {"ACPI_LV_EVENTS",		ACPI_LV_EVENTS},
243198479b04SMitsuru IWASAKI     {"ACPI_LV_VERBOSE",		ACPI_LV_VERBOSE},
243215e32d5dSMike Smith     {NULL, 0}
243315e32d5dSMike Smith };
243415e32d5dSMike Smith 
243515e32d5dSMike Smith static void
243615e32d5dSMike Smith acpi_parse_debug(char *cp, struct debugtag *tag, UINT32 *flag)
243715e32d5dSMike Smith {
243815e32d5dSMike Smith     char	*ep;
243915e32d5dSMike Smith     int		i, l;
24400ae55423SMike Smith     int		set;
244115e32d5dSMike Smith 
244215e32d5dSMike Smith     while (*cp) {
244315e32d5dSMike Smith 	if (isspace(*cp)) {
244415e32d5dSMike Smith 	    cp++;
244515e32d5dSMike Smith 	    continue;
244615e32d5dSMike Smith 	}
244715e32d5dSMike Smith 	ep = cp;
244815e32d5dSMike Smith 	while (*ep && !isspace(*ep))
244915e32d5dSMike Smith 	    ep++;
24500ae55423SMike Smith 	if (*cp == '!') {
24510ae55423SMike Smith 	    set = 0;
24520ae55423SMike Smith 	    cp++;
24530ae55423SMike Smith 	    if (cp == ep)
24540ae55423SMike Smith 		continue;
24550ae55423SMike Smith 	} else {
24560ae55423SMike Smith 	    set = 1;
24570ae55423SMike Smith 	}
245815e32d5dSMike Smith 	l = ep - cp;
245915e32d5dSMike Smith 	for (i = 0; tag[i].name != NULL; i++) {
246015e32d5dSMike Smith 	    if (!strncmp(cp, tag[i].name, l)) {
2461be2b1797SNate Lawson 		if (set)
246215e32d5dSMike Smith 		    *flag |= tag[i].value;
2463be2b1797SNate Lawson 		else
24640ae55423SMike Smith 		    *flag &= ~tag[i].value;
246515e32d5dSMike Smith 		printf("ACPI_DEBUG: set '%s'\n", tag[i].name);
246615e32d5dSMike Smith 	    }
246715e32d5dSMike Smith 	}
246815e32d5dSMike Smith 	cp = ep;
246915e32d5dSMike Smith     }
247015e32d5dSMike Smith }
247115e32d5dSMike Smith 
247215e32d5dSMike Smith static void
24732a4ac806SMike Smith acpi_set_debugging(void *junk)
247415e32d5dSMike Smith {
247594aae282SMike Barcroft     char	*cp;
247615e32d5dSMike Smith 
24771d7b121cSNate Lawson     if (cold) {
24780ae55423SMike Smith 	AcpiDbgLayer = 0;
24790ae55423SMike Smith 	AcpiDbgLevel = 0;
24801d7b121cSNate Lawson     }
24811d7b121cSNate Lawson 
248294aae282SMike Barcroft     if ((cp = getenv("debug.acpi.layer")) != NULL) {
248315e32d5dSMike Smith 	acpi_parse_debug(cp, &dbg_layer[0], &AcpiDbgLayer);
248494aae282SMike Barcroft 	freeenv(cp);
248594aae282SMike Barcroft     }
248694aae282SMike Barcroft     if ((cp = getenv("debug.acpi.level")) != NULL) {
248715e32d5dSMike Smith 	acpi_parse_debug(cp, &dbg_level[0], &AcpiDbgLevel);
248894aae282SMike Barcroft 	freeenv(cp);
248994aae282SMike Barcroft     }
24900ae55423SMike Smith 
24911d7b121cSNate Lawson     if (cold) {
24921d7b121cSNate Lawson 	printf("ACPI debug layer 0x%x debug level 0x%x\n",
24931d7b121cSNate Lawson 	       AcpiDbgLayer, AcpiDbgLevel);
24941d7b121cSNate Lawson     }
249515e32d5dSMike Smith }
2496be2b1797SNate Lawson SYSINIT(acpi_debugging, SI_SUB_TUNABLES, SI_ORDER_ANY, acpi_set_debugging,
2497be2b1797SNate Lawson 	NULL);
24981d7b121cSNate Lawson 
24991d7b121cSNate Lawson static int
25001d7b121cSNate Lawson acpi_debug_sysctl(SYSCTL_HANDLER_ARGS)
25011d7b121cSNate Lawson {
250254f6bca0SNate Lawson     int		 error, *dbg;
25031d7b121cSNate Lawson     struct	 debugtag *tag;
250454f6bca0SNate Lawson     struct	 sbuf sb;
25051d7b121cSNate Lawson 
250654f6bca0SNate Lawson     if (sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND) == NULL)
250754f6bca0SNate Lawson 	return (ENOMEM);
25081d7b121cSNate Lawson     if (strcmp(oidp->oid_arg1, "debug.acpi.layer") == 0) {
25091d7b121cSNate Lawson 	tag = &dbg_layer[0];
25101d7b121cSNate Lawson 	dbg = &AcpiDbgLayer;
25111d7b121cSNate Lawson     } else {
25121d7b121cSNate Lawson 	tag = &dbg_level[0];
25131d7b121cSNate Lawson 	dbg = &AcpiDbgLevel;
25141d7b121cSNate Lawson     }
25151d7b121cSNate Lawson 
25161d7b121cSNate Lawson     /* Get old values if this is a get request. */
25171d7b121cSNate Lawson     if (*dbg == 0) {
251854f6bca0SNate Lawson 	sbuf_cpy(&sb, "NONE");
25191d7b121cSNate Lawson     } else if (req->newptr == NULL) {
25201d7b121cSNate Lawson 	for (; tag->name != NULL; tag++) {
252154f6bca0SNate Lawson 	    if ((*dbg & tag->value) == tag->value)
252254f6bca0SNate Lawson 		sbuf_printf(&sb, "%s ", tag->name);
25231d7b121cSNate Lawson 	}
25241d7b121cSNate Lawson     }
252554f6bca0SNate Lawson     sbuf_trim(&sb);
252654f6bca0SNate Lawson     sbuf_finish(&sb);
25271d7b121cSNate Lawson 
252854f6bca0SNate Lawson     error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
252954f6bca0SNate Lawson     sbuf_delete(&sb);
25301d7b121cSNate Lawson 
25311d7b121cSNate Lawson     /* If the user is setting a string, parse it. */
25321d7b121cSNate Lawson     if (error == 0 && req->newptr != NULL) {
25331d7b121cSNate Lawson 	*dbg = 0;
25341d7b121cSNate Lawson 	setenv((char *)oidp->oid_arg1, (char *)req->newptr);
25351d7b121cSNate Lawson 	acpi_set_debugging(NULL);
25361d7b121cSNate Lawson     }
25371d7b121cSNate Lawson 
25381d7b121cSNate Lawson     return (error);
25391d7b121cSNate Lawson }
25401d7b121cSNate Lawson SYSCTL_PROC(_debug_acpi, OID_AUTO, layer, CTLFLAG_RW | CTLTYPE_STRING,
25411d7b121cSNate Lawson 	    "debug.acpi.layer", 0, acpi_debug_sysctl, "A", "");
25421d7b121cSNate Lawson SYSCTL_PROC(_debug_acpi, OID_AUTO, level, CTLFLAG_RW | CTLTYPE_STRING,
25431d7b121cSNate Lawson 	    "debug.acpi.level", 0, acpi_debug_sysctl, "A", "");
254415e32d5dSMike Smith #endif
2545f9390180SMitsuru IWASAKI 
2546f9390180SMitsuru IWASAKI static int
2547f9390180SMitsuru IWASAKI acpi_pm_func(u_long cmd, void *arg, ...)
2548f9390180SMitsuru IWASAKI {
2549f9390180SMitsuru IWASAKI 	int	state, acpi_state;
2550f9390180SMitsuru IWASAKI 	int	error;
2551f9390180SMitsuru IWASAKI 	struct	acpi_softc *sc;
2552f9390180SMitsuru IWASAKI 	va_list	ap;
2553f9390180SMitsuru IWASAKI 
2554f9390180SMitsuru IWASAKI 	error = 0;
2555f9390180SMitsuru IWASAKI 	switch (cmd) {
2556f9390180SMitsuru IWASAKI 	case POWER_CMD_SUSPEND:
2557f9390180SMitsuru IWASAKI 		sc = (struct acpi_softc *)arg;
2558f9390180SMitsuru IWASAKI 		if (sc == NULL) {
2559f9390180SMitsuru IWASAKI 			error = EINVAL;
2560f9390180SMitsuru IWASAKI 			goto out;
2561f9390180SMitsuru IWASAKI 		}
2562f9390180SMitsuru IWASAKI 
2563f9390180SMitsuru IWASAKI 		va_start(ap, arg);
2564f9390180SMitsuru IWASAKI 		state = va_arg(ap, int);
2565f9390180SMitsuru IWASAKI 		va_end(ap);
2566f9390180SMitsuru IWASAKI 
2567f9390180SMitsuru IWASAKI 		switch (state) {
2568f9390180SMitsuru IWASAKI 		case POWER_SLEEP_STATE_STANDBY:
2569f9390180SMitsuru IWASAKI 			acpi_state = sc->acpi_standby_sx;
2570f9390180SMitsuru IWASAKI 			break;
2571f9390180SMitsuru IWASAKI 		case POWER_SLEEP_STATE_SUSPEND:
2572f9390180SMitsuru IWASAKI 			acpi_state = sc->acpi_suspend_sx;
2573f9390180SMitsuru IWASAKI 			break;
2574f9390180SMitsuru IWASAKI 		case POWER_SLEEP_STATE_HIBERNATE:
2575f9390180SMitsuru IWASAKI 			acpi_state = ACPI_STATE_S4;
2576f9390180SMitsuru IWASAKI 			break;
2577f9390180SMitsuru IWASAKI 		default:
2578f9390180SMitsuru IWASAKI 			error = EINVAL;
2579f9390180SMitsuru IWASAKI 			goto out;
2580f9390180SMitsuru IWASAKI 		}
2581f9390180SMitsuru IWASAKI 
2582f9390180SMitsuru IWASAKI 		acpi_SetSleepState(sc, acpi_state);
2583f9390180SMitsuru IWASAKI 		break;
2584f9390180SMitsuru IWASAKI 	default:
2585f9390180SMitsuru IWASAKI 		error = EINVAL;
2586f9390180SMitsuru IWASAKI 		goto out;
2587f9390180SMitsuru IWASAKI 	}
2588f9390180SMitsuru IWASAKI 
2589f9390180SMitsuru IWASAKI out:
2590f9390180SMitsuru IWASAKI 	return (error);
2591f9390180SMitsuru IWASAKI }
2592f9390180SMitsuru IWASAKI 
2593f9390180SMitsuru IWASAKI static void
2594f9390180SMitsuru IWASAKI acpi_pm_register(void *arg)
2595f9390180SMitsuru IWASAKI {
2596be2b1797SNate Lawson     if (!cold || resource_disabled("acpi", 0))
25976c407052SMitsuru IWASAKI 	return;
2598f9390180SMitsuru IWASAKI 
2599f9390180SMitsuru IWASAKI     power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, NULL);
2600f9390180SMitsuru IWASAKI }
2601f9390180SMitsuru IWASAKI 
2602f9390180SMitsuru IWASAKI SYSINIT(power, SI_SUB_KLD, SI_ORDER_ANY, acpi_pm_register, 0);
2603