xref: /freebsd/sys/dev/acpica/acpi.c (revision 3f9a00e3b577dcca57e331842e0baf2dbdf9325f)
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 
30dad97feeSDavid E. O'Brien #include <sys/cdefs.h>
31dad97feeSDavid E. O'Brien __FBSDID("$FreeBSD$");
32dad97feeSDavid E. O'Brien 
3315e32d5dSMike Smith #include "opt_acpi.h"
3462d70a81SJohn Baldwin 
3515e32d5dSMike Smith #include <sys/param.h>
36e2e050c8SConrad Meyer #include <sys/eventhandler.h>
3715e32d5dSMike Smith #include <sys/kernel.h>
38fb919e4dSMark Murray #include <sys/proc.h>
39a89fcf28STakanori Watanabe #include <sys/fcntl.h>
4015e32d5dSMike Smith #include <sys/malloc.h>
41fe12f24bSPoul-Henning Kamp #include <sys/module.h>
4215e32d5dSMike Smith #include <sys/bus.h>
4315e32d5dSMike Smith #include <sys/conf.h>
4415e32d5dSMike Smith #include <sys/ioccom.h>
4515e32d5dSMike Smith #include <sys/reboot.h>
4615e32d5dSMike Smith #include <sys/sysctl.h>
4715e32d5dSMike Smith #include <sys/ctype.h>
481611ea87SMitsuru IWASAKI #include <sys/linker.h>
49f1084587SKonstantin Belousov #include <sys/mount.h>
50f9390180SMitsuru IWASAKI #include <sys/power.h>
5154f6bca0SNate Lawson #include <sys/sbuf.h>
52c66d2b38SJung-uk Kim #include <sys/sched.h>
53eeb3a05fSNate Lawson #include <sys/smp.h>
54c66d2b38SJung-uk Kim #include <sys/timetc.h>
55b91fc6c4SBartlomiej Grzesik #include <sys/uuid.h>
5615e32d5dSMike Smith 
57d320e05cSJohn Baldwin #if defined(__i386__) || defined(__amd64__)
58279be68bSAndriy Gapon #include <machine/clock.h>
59d320e05cSJohn Baldwin #include <machine/pci_cfgreg.h>
60d320e05cSJohn Baldwin #endif
6115e32d5dSMike Smith #include <machine/resource.h>
62dc750869SNate Lawson #include <machine/bus.h>
63dc750869SNate Lawson #include <sys/rman.h>
64bc0f2195SMike Smith #include <isa/isavar.h>
65c796e27bSNate Lawson #include <isa/pnpvar.h>
66bc0f2195SMike Smith 
67129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acpi.h>
68129d3046SJung-uk Kim #include <contrib/dev/acpica/include/accommon.h>
69129d3046SJung-uk Kim #include <contrib/dev/acpica/include/acnamesp.h>
70129d3046SJung-uk Kim 
7115e32d5dSMike Smith #include <dev/acpica/acpivar.h>
7215e32d5dSMike Smith #include <dev/acpica/acpiio.h>
7315e32d5dSMike Smith 
740e68afe5SAndrew Turner #include <dev/pci/pcivar.h>
750e68afe5SAndrew Turner 
762be4e471SJung-uk Kim #include <vm/vm_param.h>
772be4e471SJung-uk Kim 
78d745c852SEd Schouten static MALLOC_DEFINE(M_ACPIDEV, "acpidev", "ACPI devices");
7915e32d5dSMike Smith 
80be2b1797SNate Lawson /* Hooks for the ACPI CA debugging infrastructure */
81cb9b0d80SMike Smith #define _COMPONENT	ACPI_BUS
82b53f2771SMike Smith ACPI_MODULE_NAME("ACPI")
830ae55423SMike Smith 
8415e32d5dSMike Smith static d_open_t		acpiopen;
8515e32d5dSMike Smith static d_close_t	acpiclose;
8615e32d5dSMike Smith static d_ioctl_t	acpiioctl;
8715e32d5dSMike Smith 
8815e32d5dSMike Smith static struct cdevsw acpi_cdevsw = {
89dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
907ac40f5fSPoul-Henning Kamp 	.d_open =	acpiopen,
917ac40f5fSPoul-Henning Kamp 	.d_close =	acpiclose,
927ac40f5fSPoul-Henning Kamp 	.d_ioctl =	acpiioctl,
937ac40f5fSPoul-Henning Kamp 	.d_name =	"acpi",
9415e32d5dSMike Smith };
9515e32d5dSMike Smith 
96ae19af49SJung-uk Kim struct acpi_interface {
97ae19af49SJung-uk Kim 	ACPI_STRING	*data;
98ae19af49SJung-uk Kim 	int		num;
99ae19af49SJung-uk Kim };
100ae19af49SJung-uk Kim 
101dc8ab16eSWarner Losh static char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
102dc8ab16eSWarner Losh static char *pcilink_ids[] = { "PNP0C0F", NULL };
103dc8ab16eSWarner Losh 
104346eda4fSNate Lawson /* Global mutex for locking access to the ACPI subsystem. */
105cb9b0d80SMike Smith struct mtx	acpi_mutex;
106fadf3fb9SJohn Baldwin struct callout	acpi_sleep_timer;
107cb9b0d80SMike Smith 
10889fb5af8SNate Lawson /* Bitmap of device quirks. */
10989fb5af8SNate Lawson int		acpi_quirks;
11089fb5af8SNate Lawson 
111a0e73a12SJung-uk Kim /* Supported sleep states. */
112a0e73a12SJung-uk Kim static BOOLEAN	acpi_sleep_states[ACPI_S_STATE_COUNT];
113a0e73a12SJung-uk Kim 
11464de8019SJohn Baldwin static void	acpi_lookup(void *arg, const char *name, device_t *dev);
1156d63101aSMike Smith static int	acpi_modevent(struct module *mod, int event, void *junk);
11615e32d5dSMike Smith static int	acpi_probe(device_t dev);
11715e32d5dSMike Smith static int	acpi_attach(device_t dev);
11810ce62b9SNate Lawson static int	acpi_suspend(device_t dev);
11910ce62b9SNate Lawson static int	acpi_resume(device_t dev);
120169b539aSNate Lawson static int	acpi_shutdown(device_t dev);
1213d844eddSAndriy Gapon static device_t	acpi_add_child(device_t bus, u_int order, const char *name,
122be2b1797SNate Lawson 			int unit);
12315e32d5dSMike Smith static int	acpi_print_child(device_t bus, device_t child);
12410ce62b9SNate Lawson static void	acpi_probe_nomatch(device_t bus, device_t child);
12510ce62b9SNate Lawson static void	acpi_driver_added(device_t dev, driver_t *driver);
126709749aaSVladimir Kondratyev static void	acpi_child_deleted(device_t dev, device_t child);
127be2b1797SNate Lawson static int	acpi_read_ivar(device_t dev, device_t child, int index,
128be2b1797SNate Lawson 			uintptr_t *result);
129be2b1797SNate Lawson static int	acpi_write_ivar(device_t dev, device_t child, int index,
130be2b1797SNate Lawson 			uintptr_t value);
13191233413SNate Lawson static struct resource_list *acpi_get_rlist(device_t dev, device_t child);
132ea233199SJohn Baldwin static void	acpi_reserve_resources(device_t dev);
133adad4744SNate Lawson static int	acpi_sysres_alloc(device_t dev);
134ea233199SJohn Baldwin static int	acpi_set_resource(device_t dev, device_t child, int type,
1352dd1bdf1SJustin Hibbits 			int rid, rman_res_t start, rman_res_t count);
136be2b1797SNate Lawson static struct resource *acpi_alloc_resource(device_t bus, device_t child,
1372dd1bdf1SJustin Hibbits 			int type, int *rid, rman_res_t start, rman_res_t end,
1382dd1bdf1SJustin Hibbits 			rman_res_t count, u_int flags);
139049dc0d1SJohn Baldwin static int	acpi_adjust_resource(device_t bus, device_t child, int type,
1402dd1bdf1SJustin Hibbits 			struct resource *r, rman_res_t start, rman_res_t end);
141be2b1797SNate Lawson static int	acpi_release_resource(device_t bus, device_t child, int type,
142be2b1797SNate Lawson 			int rid, struct resource *r);
1438b28b622SNate Lawson static void	acpi_delete_resource(device_t bus, device_t child, int type,
1448b28b622SNate Lawson 		    int rid);
1451e4925e8SNate Lawson static uint32_t	acpi_isa_get_logicalid(device_t dev);
1461e4925e8SNate Lawson static int	acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count);
147*3f9a00e3SBartlomiej Grzesik static ssize_t acpi_bus_get_prop(device_t bus, device_t child, const char *propname,
148*3f9a00e3SBartlomiej Grzesik 		    void *propvalue, size_t size);
1495efca36fSTakanori Watanabe static int	acpi_device_id_probe(device_t bus, device_t dev, char **ids, char **match);
150ce619b2eSNate Lawson static ACPI_STATUS acpi_device_eval_obj(device_t bus, device_t dev,
151ce619b2eSNate Lawson 		    ACPI_STRING pathname, ACPI_OBJECT_LIST *parameters,
152ce619b2eSNate Lawson 		    ACPI_BUFFER *ret);
153b91fc6c4SBartlomiej Grzesik static ACPI_STATUS acpi_device_get_prop(device_t bus, device_t dev,
154b91fc6c4SBartlomiej Grzesik 		    ACPI_STRING propname, const ACPI_OBJECT **value);
155df8d2a32SNate Lawson static ACPI_STATUS acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level,
156df8d2a32SNate Lawson 		    void *context, void **retval);
157df8d2a32SNate Lawson static ACPI_STATUS acpi_device_scan_children(device_t bus, device_t dev,
158df8d2a32SNate Lawson 		    int max_depth, acpi_scan_cb_t user_fn, void *arg);
159b91fc6c4SBartlomiej Grzesik static ACPI_STATUS acpi_find_dsd(device_t bus, device_t dev);
160be2b1797SNate Lawson static int	acpi_isa_pnp_probe(device_t bus, device_t child,
161be2b1797SNate Lawson 		    struct isa_pnp_id *ids);
162855e49f3SAlexander Motin static void	acpi_platform_osc(device_t dev);
16315e32d5dSMike Smith static void	acpi_probe_children(device_t bus);
164d227204dSJohn Baldwin static void	acpi_probe_order(ACPI_HANDLE handle, int *order);
165be2b1797SNate Lawson static ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level,
166be2b1797SNate Lawson 		    void *context, void **status);
167a0e73a12SJung-uk Kim static void	acpi_sleep_enable(void *arg);
168a0e73a12SJung-uk Kim static ACPI_STATUS acpi_sleep_disable(struct acpi_softc *sc);
16900a30448SNate Lawson static ACPI_STATUS acpi_EnterSleepState(struct acpi_softc *sc, int state);
17015e32d5dSMike Smith static void	acpi_shutdown_final(void *arg, int howto);
17113d4f7baSMitsuru IWASAKI static void	acpi_enable_fixed_events(struct acpi_softc *sc);
172a0a15716SJung-uk Kim static void	acpi_resync_clock(struct acpi_softc *sc);
173d4b9ff91SNate Lawson static int	acpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate);
174d4b9ff91SNate Lawson static int	acpi_wake_run_prep(ACPI_HANDLE handle, int sstate);
175d4b9ff91SNate Lawson static int	acpi_wake_prep_walk(int sstate);
17688a79fc0SNate Lawson static int	acpi_wake_sysctl_walk(device_t dev);
17788a79fc0SNate Lawson static int	acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS);
17815e32d5dSMike Smith static void	acpi_system_eventhandler_sleep(void *arg, int state);
17915e32d5dSMike Smith static void	acpi_system_eventhandler_wakeup(void *arg, int state);
180a0e73a12SJung-uk Kim static int	acpi_sname2sstate(const char *sname);
181a0e73a12SJung-uk Kim static const char *acpi_sstate2sname(int sstate);
182d75de536SMitsuru IWASAKI static int	acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS);
1831d073b1dSJohn Baldwin static int	acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS);
1842a18c71dSJung-uk Kim static int	acpi_debug_objects_sysctl(SYSCTL_HANDLER_ARGS);
185f9390180SMitsuru IWASAKI static int	acpi_pm_func(u_long cmd, void *arg, ...);
186ddfc9c4cSWarner Losh static int	acpi_child_location_method(device_t acdev, device_t child,
187ddfc9c4cSWarner Losh 		    struct sbuf *sb);
188ddfc9c4cSWarner Losh static int	acpi_child_pnpinfo_method(device_t acdev, device_t child,
189ddfc9c4cSWarner Losh 		    struct sbuf *sb);
190d320e05cSJohn Baldwin static void	acpi_enable_pcie(void);
1910d484d24SJohn Baldwin static void	acpi_hint_device_unit(device_t acdev, device_t child,
1920d484d24SJohn Baldwin 		    const char *name, int *unitp);
193ae19af49SJung-uk Kim static void	acpi_reset_interfaces(device_t dev);
194879d6c23STakanori Watanabe 
19515e32d5dSMike Smith static device_method_t acpi_methods[] = {
19615e32d5dSMike Smith     /* Device interface */
19715e32d5dSMike Smith     DEVMETHOD(device_probe,		acpi_probe),
19815e32d5dSMike Smith     DEVMETHOD(device_attach,		acpi_attach),
199169b539aSNate Lawson     DEVMETHOD(device_shutdown,		acpi_shutdown),
20056a70eadSNate Lawson     DEVMETHOD(device_detach,		bus_generic_detach),
20110ce62b9SNate Lawson     DEVMETHOD(device_suspend,		acpi_suspend),
20210ce62b9SNate Lawson     DEVMETHOD(device_resume,		acpi_resume),
20315e32d5dSMike Smith 
20415e32d5dSMike Smith     /* Bus interface */
20515e32d5dSMike Smith     DEVMETHOD(bus_add_child,		acpi_add_child),
20615e32d5dSMike Smith     DEVMETHOD(bus_print_child,		acpi_print_child),
20710ce62b9SNate Lawson     DEVMETHOD(bus_probe_nomatch,	acpi_probe_nomatch),
20810ce62b9SNate Lawson     DEVMETHOD(bus_driver_added,		acpi_driver_added),
209709749aaSVladimir Kondratyev     DEVMETHOD(bus_child_deleted,	acpi_child_deleted),
21015e32d5dSMike Smith     DEVMETHOD(bus_read_ivar,		acpi_read_ivar),
21115e32d5dSMike Smith     DEVMETHOD(bus_write_ivar,		acpi_write_ivar),
21291233413SNate Lawson     DEVMETHOD(bus_get_resource_list,	acpi_get_rlist),
213ea233199SJohn Baldwin     DEVMETHOD(bus_set_resource,		acpi_set_resource),
21491233413SNate Lawson     DEVMETHOD(bus_get_resource,		bus_generic_rl_get_resource),
21515e32d5dSMike Smith     DEVMETHOD(bus_alloc_resource,	acpi_alloc_resource),
216049dc0d1SJohn Baldwin     DEVMETHOD(bus_adjust_resource,	acpi_adjust_resource),
21715e32d5dSMike Smith     DEVMETHOD(bus_release_resource,	acpi_release_resource),
2188b28b622SNate Lawson     DEVMETHOD(bus_delete_resource,	acpi_delete_resource),
219ddfc9c4cSWarner Losh     DEVMETHOD(bus_child_pnpinfo,	acpi_child_pnpinfo_method),
220ddfc9c4cSWarner Losh     DEVMETHOD(bus_child_location,	acpi_child_location_method),
22115e32d5dSMike Smith     DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
22215e32d5dSMike Smith     DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
22315e32d5dSMike Smith     DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
22415e32d5dSMike Smith     DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
2250d484d24SJohn Baldwin     DEVMETHOD(bus_hint_device_unit,	acpi_hint_device_unit),
2268d791e5aSJohn Baldwin     DEVMETHOD(bus_get_cpus,		acpi_get_cpus),
227ffcf962dSAdrian Chadd     DEVMETHOD(bus_get_domain,		acpi_get_domain),
228*3f9a00e3SBartlomiej Grzesik     DEVMETHOD(bus_get_property,		acpi_bus_get_prop),
22915e32d5dSMike Smith 
230ce619b2eSNate Lawson     /* ACPI bus */
231ce619b2eSNate Lawson     DEVMETHOD(acpi_id_probe,		acpi_device_id_probe),
232ce619b2eSNate Lawson     DEVMETHOD(acpi_evaluate_object,	acpi_device_eval_obj),
233b91fc6c4SBartlomiej Grzesik     DEVMETHOD(acpi_get_property,	acpi_device_get_prop),
23410ce62b9SNate Lawson     DEVMETHOD(acpi_pwr_for_sleep,	acpi_device_pwr_for_sleep),
235df8d2a32SNate Lawson     DEVMETHOD(acpi_scan_children,	acpi_device_scan_children),
236ce619b2eSNate Lawson 
237bc0f2195SMike Smith     /* ISA emulation */
238bc0f2195SMike Smith     DEVMETHOD(isa_pnp_probe,		acpi_isa_pnp_probe),
239bc0f2195SMike Smith 
24061bfd867SSofian Brabez     DEVMETHOD_END
24115e32d5dSMike Smith };
24215e32d5dSMike Smith 
24315e32d5dSMike Smith static driver_t acpi_driver = {
24415e32d5dSMike Smith     "acpi",
24515e32d5dSMike Smith     acpi_methods,
24615e32d5dSMike Smith     sizeof(struct acpi_softc),
24715e32d5dSMike Smith };
24815e32d5dSMike Smith 
2493273b005SMike Smith static devclass_t acpi_devclass;
250334790eaSAndrew Turner EARLY_DRIVER_MODULE(acpi, nexus, acpi_driver, acpi_devclass, acpi_modevent, 0,
251334790eaSAndrew Turner     BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
252a4ecd543SNate Lawson MODULE_VERSION(acpi, 1);
25315e32d5dSMike Smith 
25415e2f34fSNate Lawson ACPI_SERIAL_DECL(acpi, "ACPI root bus");
25515e2f34fSNate Lawson 
256adad4744SNate Lawson /* Local pools for managing system resources for ACPI child devices. */
257adad4744SNate Lawson static struct rman acpi_rman_io, acpi_rman_mem;
258adad4744SNate Lawson 
259bee4aa4aSNate Lawson #define ACPI_MINIMUM_AWAKETIME	5
260bee4aa4aSNate Lawson 
2615217af30SJohn Baldwin /* Holds the description of the acpi0 device. */
2625217af30SJohn Baldwin static char acpi_desc[ACPI_OEM_ID_SIZE + ACPI_OEM_TABLE_ID_SIZE + 2];
2635217af30SJohn Baldwin 
2647029da5cSPawel Biernacki SYSCTL_NODE(_debug, OID_AUTO, acpi, CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
2657029da5cSPawel Biernacki     "ACPI debugging");
2661d7b121cSNate Lawson static char acpi_ca_version[12];
2671d7b121cSNate Lawson SYSCTL_STRING(_debug_acpi, OID_AUTO, acpi_ca_version, CTLFLAG_RD,
2681d7b121cSNate Lawson 	      acpi_ca_version, 0, "Version of Intel ACPI-CA");
26915e32d5dSMike Smith 
27015e32d5dSMike Smith /*
271ae19af49SJung-uk Kim  * Allow overriding _OSI methods.
272ae19af49SJung-uk Kim  */
273ae19af49SJung-uk Kim static char acpi_install_interface[256];
274ae19af49SJung-uk Kim TUNABLE_STR("hw.acpi.install_interface", acpi_install_interface,
275ae19af49SJung-uk Kim     sizeof(acpi_install_interface));
276ae19af49SJung-uk Kim static char acpi_remove_interface[256];
277ae19af49SJung-uk Kim TUNABLE_STR("hw.acpi.remove_interface", acpi_remove_interface,
278ae19af49SJung-uk Kim     sizeof(acpi_remove_interface));
279ae19af49SJung-uk Kim 
2802a18c71dSJung-uk Kim /* Allow users to dump Debug objects without ACPI debugger. */
2812a18c71dSJung-uk Kim static int acpi_debug_objects;
2822a18c71dSJung-uk Kim TUNABLE_INT("debug.acpi.enable_debug_objects", &acpi_debug_objects);
2832a18c71dSJung-uk Kim SYSCTL_PROC(_debug_acpi, OID_AUTO, enable_debug_objects,
2847029da5cSPawel Biernacki     CTLFLAG_RW | CTLTYPE_INT | CTLFLAG_NEEDGIANT, NULL, 0,
2857029da5cSPawel Biernacki     acpi_debug_objects_sysctl, "I",
2862a18c71dSJung-uk Kim     "Enable Debug objects");
2872a18c71dSJung-uk Kim 
2882a18c71dSJung-uk Kim /* Allow the interpreter to ignore common mistakes in BIOS. */
2892a18c71dSJung-uk Kim static int acpi_interpreter_slack = 1;
2902a18c71dSJung-uk Kim TUNABLE_INT("debug.acpi.interpreter_slack", &acpi_interpreter_slack);
2912a18c71dSJung-uk Kim SYSCTL_INT(_debug_acpi, OID_AUTO, interpreter_slack, CTLFLAG_RDTUN,
2922a18c71dSJung-uk Kim     &acpi_interpreter_slack, 1, "Turn on interpreter slack mode.");
2932a18c71dSJung-uk Kim 
294313a0c13SJung-uk Kim /* Ignore register widths set by FADT and use default widths instead. */
295313a0c13SJung-uk Kim static int acpi_ignore_reg_width = 1;
296313a0c13SJung-uk Kim TUNABLE_INT("debug.acpi.default_register_width", &acpi_ignore_reg_width);
297313a0c13SJung-uk Kim SYSCTL_INT(_debug_acpi, OID_AUTO, default_register_width, CTLFLAG_RDTUN,
298313a0c13SJung-uk Kim     &acpi_ignore_reg_width, 1, "Ignore register widths set by FADT");
299313a0c13SJung-uk Kim 
30039da3eb3SNate Lawson /* Allow users to override quirks. */
30139da3eb3SNate Lawson TUNABLE_INT("debug.acpi.quirks", &acpi_quirks);
30239da3eb3SNate Lawson 
303e787342eSJung-uk Kim int acpi_susp_bounce;
30493bfd059SNate Lawson SYSCTL_INT(_debug_acpi, OID_AUTO, suspend_bounce, CTLFLAG_RW,
30593bfd059SNate Lawson     &acpi_susp_bounce, 0, "Don't actually suspend, just test devices.");
30693bfd059SNate Lawson 
307c9b8d77dSNate Lawson /*
308b91fc6c4SBartlomiej Grzesik  * ACPI standard UUID for Device Specific Data Package
309b91fc6c4SBartlomiej Grzesik  * "Device Properties UUID for _DSD" Rev. 2.0
310b91fc6c4SBartlomiej Grzesik  */
311b91fc6c4SBartlomiej Grzesik static const struct uuid acpi_dsd_uuid = {
312b91fc6c4SBartlomiej Grzesik 	0xdaffd814, 0x6eba, 0x4d8c, 0x8a, 0x91,
313b91fc6c4SBartlomiej Grzesik 	{ 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01 }
314b91fc6c4SBartlomiej Grzesik };
315b91fc6c4SBartlomiej Grzesik 
316b91fc6c4SBartlomiej Grzesik /*
3176d63101aSMike Smith  * ACPI can only be loaded as a module by the loader; activating it after
3186d63101aSMike Smith  * system bootstrap time is not useful, and can be fatal to the system.
3198c0879b6SJohn Baldwin  * It also cannot be unloaded, since the entire system bus hierarchy hangs
320be2b1797SNate Lawson  * off it.
3216d63101aSMike Smith  */
3226d63101aSMike Smith static int
3236d63101aSMike Smith acpi_modevent(struct module *mod, int event, void *junk)
3246d63101aSMike Smith {
3256d63101aSMike Smith     switch (event) {
3266d63101aSMike Smith     case MOD_LOAD:
32787b45ed5SMitsuru IWASAKI 	if (!cold) {
32887b45ed5SMitsuru IWASAKI 	    printf("The ACPI driver cannot be loaded after boot.\n");
3296d63101aSMike Smith 	    return (EPERM);
33087b45ed5SMitsuru IWASAKI 	}
3316d63101aSMike Smith 	break;
3326d63101aSMike Smith     case MOD_UNLOAD:
333f9390180SMitsuru IWASAKI 	if (!cold && power_pm_get_type() == POWER_PM_TYPE_ACPI)
3346d63101aSMike Smith 	    return (EBUSY);
335f9390180SMitsuru IWASAKI 	break;
3366d63101aSMike Smith     default:
3376d63101aSMike Smith 	break;
3386d63101aSMike Smith     }
3396d63101aSMike Smith     return (0);
3406d63101aSMike Smith }
3416d63101aSMike Smith 
3426d63101aSMike Smith /*
343bbc2815cSJohn Baldwin  * Perform early initialization.
34415e32d5dSMike Smith  */
345bbc2815cSJohn Baldwin ACPI_STATUS
346bbc2815cSJohn Baldwin acpi_Startup(void)
34715e32d5dSMike Smith {
34889fb5af8SNate Lawson     static int started = 0;
3492be4e471SJung-uk Kim     ACPI_STATUS status;
3502be4e471SJung-uk Kim     int val;
35115e32d5dSMike Smith 
3521b8c233dSPeter Pentchev     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
3531b8c233dSPeter Pentchev 
354bee4aa4aSNate Lawson     /* Only run the startup code once.  The MADT driver also calls this. */
355bbc2815cSJohn Baldwin     if (started)
3562be4e471SJung-uk Kim 	return_VALUE (AE_OK);
357bbc2815cSJohn Baldwin     started = 1;
35815e32d5dSMike Smith 
359413081d7SNate Lawson     /*
3605f9b24faSJung-uk Kim      * Initialize the ACPICA subsystem.
3615f9b24faSJung-uk Kim      */
3625f9b24faSJung-uk Kim     if (ACPI_FAILURE(status = AcpiInitializeSubsystem())) {
3635f9b24faSJung-uk Kim 	printf("ACPI: Could not initialize Subsystem: %s\n",
3645f9b24faSJung-uk Kim 	    AcpiFormatException(status));
3655f9b24faSJung-uk Kim 	return_VALUE (status);
3665f9b24faSJung-uk Kim     }
3675f9b24faSJung-uk Kim 
3685f9b24faSJung-uk Kim     /*
3692be4e471SJung-uk Kim      * Pre-allocate space for RSDT/XSDT and DSDT tables and allow resizing
3702be4e471SJung-uk Kim      * if more tables exist.
371413081d7SNate Lawson      */
3722be4e471SJung-uk Kim     if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 2, TRUE))) {
3732be4e471SJung-uk Kim 	printf("ACPI: Table initialisation failed: %s\n",
3742be4e471SJung-uk Kim 	    AcpiFormatException(status));
3752be4e471SJung-uk Kim 	return_VALUE (status);
37615e32d5dSMike Smith     }
3773184cf5aSNate Lawson 
37889fb5af8SNate Lawson     /* Set up any quirks we have for this system. */
3792be4e471SJung-uk Kim     if (acpi_quirks == ACPI_Q_OK)
38089fb5af8SNate Lawson 	acpi_table_quirks(&acpi_quirks);
38189fb5af8SNate Lawson 
38239da3eb3SNate Lawson     /* If the user manually set the disabled hint to 0, force-enable ACPI. */
38389fb5af8SNate Lawson     if (resource_int_value("acpi", 0, "disabled", &val) == 0 && val == 0)
38489fb5af8SNate Lawson 	acpi_quirks &= ~ACPI_Q_BROKEN;
38589fb5af8SNate Lawson     if (acpi_quirks & ACPI_Q_BROKEN) {
38689fb5af8SNate Lawson 	printf("ACPI disabled by blacklist.  Contact your BIOS vendor.\n");
3872be4e471SJung-uk Kim 	status = AE_SUPPORT;
38889fb5af8SNate Lawson     }
3893184cf5aSNate Lawson 
3902be4e471SJung-uk Kim     return_VALUE (status);
391bbc2815cSJohn Baldwin }
392bbc2815cSJohn Baldwin 
393bbc2815cSJohn Baldwin /*
3945217af30SJohn Baldwin  * Detect ACPI and perform early initialisation.
395bbc2815cSJohn Baldwin  */
3965217af30SJohn Baldwin int
3975217af30SJohn Baldwin acpi_identify(void)
398bbc2815cSJohn Baldwin {
3995217af30SJohn Baldwin     ACPI_TABLE_RSDP	*rsdp;
4005217af30SJohn Baldwin     ACPI_TABLE_HEADER	*rsdt;
4015217af30SJohn Baldwin     ACPI_PHYSICAL_ADDRESS paddr;
4025217af30SJohn Baldwin     struct sbuf		sb;
403bbc2815cSJohn Baldwin 
404bbc2815cSJohn Baldwin     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
405bbc2815cSJohn Baldwin 
406bbc2815cSJohn Baldwin     if (!cold)
4075217af30SJohn Baldwin 	return (ENXIO);
408bbc2815cSJohn Baldwin 
409a8de37b0SEitan Adler     /* Check that we haven't been disabled with a hint. */
410a8de37b0SEitan Adler     if (resource_disabled("acpi", 0))
411a8de37b0SEitan Adler 	return (ENXIO);
412a8de37b0SEitan Adler 
4135217af30SJohn Baldwin     /* Check for other PM systems. */
4145217af30SJohn Baldwin     if (power_pm_get_type() != POWER_PM_TYPE_NONE &&
4155217af30SJohn Baldwin 	power_pm_get_type() != POWER_PM_TYPE_ACPI) {
4165217af30SJohn Baldwin 	printf("ACPI identify failed, other PM system enabled.\n");
4175217af30SJohn Baldwin 	return (ENXIO);
4185217af30SJohn Baldwin     }
4194b1ff978SMark Santcroos 
4202be4e471SJung-uk Kim     /* Initialize root tables. */
4212be4e471SJung-uk Kim     if (ACPI_FAILURE(acpi_Startup())) {
4222be4e471SJung-uk Kim 	printf("ACPI: Try disabling either ACPI or apic support.\n");
4235217af30SJohn Baldwin 	return (ENXIO);
4242be4e471SJung-uk Kim     }
42515e32d5dSMike Smith 
4265217af30SJohn Baldwin     if ((paddr = AcpiOsGetRootPointer()) == 0 ||
4275217af30SJohn Baldwin 	(rsdp = AcpiOsMapMemory(paddr, sizeof(ACPI_TABLE_RSDP))) == NULL)
4285217af30SJohn Baldwin 	return (ENXIO);
4295217af30SJohn Baldwin     if (rsdp->Revision > 1 && rsdp->XsdtPhysicalAddress != 0)
4305217af30SJohn Baldwin 	paddr = (ACPI_PHYSICAL_ADDRESS)rsdp->XsdtPhysicalAddress;
4315217af30SJohn Baldwin     else
4325217af30SJohn Baldwin 	paddr = (ACPI_PHYSICAL_ADDRESS)rsdp->RsdtPhysicalAddress;
4335217af30SJohn Baldwin     AcpiOsUnmapMemory(rsdp, sizeof(ACPI_TABLE_RSDP));
4345217af30SJohn Baldwin 
4355217af30SJohn Baldwin     if ((rsdt = AcpiOsMapMemory(paddr, sizeof(ACPI_TABLE_HEADER))) == NULL)
4365217af30SJohn Baldwin 	return (ENXIO);
4375217af30SJohn Baldwin     sbuf_new(&sb, acpi_desc, sizeof(acpi_desc), SBUF_FIXEDLEN);
4385217af30SJohn Baldwin     sbuf_bcat(&sb, rsdt->OemId, ACPI_OEM_ID_SIZE);
4395217af30SJohn Baldwin     sbuf_trim(&sb);
4405217af30SJohn Baldwin     sbuf_putc(&sb, ' ');
4415217af30SJohn Baldwin     sbuf_bcat(&sb, rsdt->OemTableId, ACPI_OEM_TABLE_ID_SIZE);
4425217af30SJohn Baldwin     sbuf_trim(&sb);
4435217af30SJohn Baldwin     sbuf_finish(&sb);
4445217af30SJohn Baldwin     sbuf_delete(&sb);
4455217af30SJohn Baldwin     AcpiOsUnmapMemory(rsdt, sizeof(ACPI_TABLE_HEADER));
4465217af30SJohn Baldwin 
4475217af30SJohn Baldwin     snprintf(acpi_ca_version, sizeof(acpi_ca_version), "%x", ACPI_CA_VERSION);
4485217af30SJohn Baldwin 
4495217af30SJohn Baldwin     return (0);
45015e32d5dSMike Smith }
45115e32d5dSMike Smith 
45215e32d5dSMike Smith /*
453bee4aa4aSNate Lawson  * Fetch some descriptive data from ACPI to put in our attach message.
45415e32d5dSMike Smith  */
45515e32d5dSMike Smith static int
45615e32d5dSMike Smith acpi_probe(device_t dev)
45715e32d5dSMike Smith {
45815e32d5dSMike Smith 
459b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
460f9390180SMitsuru IWASAKI 
4615217af30SJohn Baldwin     device_set_desc(dev, acpi_desc);
462bee4aa4aSNate Lawson 
463feeec74dSNathan Whitehorn     return_VALUE (BUS_PROBE_NOWILDCARD);
46415e32d5dSMike Smith }
46515e32d5dSMike Smith 
46615e32d5dSMike Smith static int
46715e32d5dSMike Smith acpi_attach(device_t dev)
46815e32d5dSMike Smith {
46915e32d5dSMike Smith     struct acpi_softc	*sc;
470cb9b0d80SMike Smith     ACPI_STATUS		status;
471ea27c63eSNate Lawson     int			error, state;
47232d18aa5SMike Smith     UINT32		flags;
473ea27c63eSNate Lawson     UINT8		TypeA, TypeB;
474498d464fSMitsuru IWASAKI     char		*env;
47515e32d5dSMike Smith 
476b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
477bee4aa4aSNate Lawson 
47815e32d5dSMike Smith     sc = device_get_softc(dev);
47915e32d5dSMike Smith     sc->acpi_dev = dev;
480fd90e2edSJung-uk Kim     callout_init(&sc->susp_force_to, 1);
48115e32d5dSMike Smith 
4822be4e471SJung-uk Kim     error = ENXIO;
4832be4e471SJung-uk Kim 
48491233413SNate Lawson     /* Initialize resource manager. */
48591233413SNate Lawson     acpi_rman_io.rm_type = RMAN_ARRAY;
48691233413SNate Lawson     acpi_rman_io.rm_start = 0;
48791233413SNate Lawson     acpi_rman_io.rm_end = 0xffff;
4880bba6acfSJohn Baldwin     acpi_rman_io.rm_descr = "ACPI I/O ports";
48991233413SNate Lawson     if (rman_init(&acpi_rman_io) != 0)
49091233413SNate Lawson 	panic("acpi rman_init IO ports failed");
49191233413SNate Lawson     acpi_rman_mem.rm_type = RMAN_ARRAY;
4920bba6acfSJohn Baldwin     acpi_rman_mem.rm_descr = "ACPI I/O memory addresses";
49391233413SNate Lawson     if (rman_init(&acpi_rman_mem) != 0)
49491233413SNate Lawson 	panic("acpi rman_init memory failed");
49591233413SNate Lawson 
4962be4e471SJung-uk Kim     /* Initialise the ACPI mutex */
4972be4e471SJung-uk Kim     mtx_init(&acpi_mutex, "ACPI global lock", NULL, MTX_DEF);
4982be4e471SJung-uk Kim 
4992be4e471SJung-uk Kim     /*
5002be4e471SJung-uk Kim      * Set the globals from our tunables.  This is needed because ACPI-CA
5012be4e471SJung-uk Kim      * uses UINT8 for some values and we have no tunable_byte.
5022be4e471SJung-uk Kim      */
5032a18c71dSJung-uk Kim     AcpiGbl_EnableInterpreterSlack = acpi_interpreter_slack ? TRUE : FALSE;
5042a18c71dSJung-uk Kim     AcpiGbl_EnableAmlDebugObject = acpi_debug_objects ? TRUE : FALSE;
505313a0c13SJung-uk Kim     AcpiGbl_UseDefaultRegisterWidths = acpi_ignore_reg_width ? TRUE : FALSE;
5062a18c71dSJung-uk Kim 
5072a18c71dSJung-uk Kim #ifndef ACPI_DEBUG
5082a18c71dSJung-uk Kim     /*
5092a18c71dSJung-uk Kim      * Disable all debugging layers and levels.
5102a18c71dSJung-uk Kim      */
5112a18c71dSJung-uk Kim     AcpiDbgLayer = 0;
5122a18c71dSJung-uk Kim     AcpiDbgLevel = 0;
5132a18c71dSJung-uk Kim #endif
5142be4e471SJung-uk Kim 
515ae19af49SJung-uk Kim     /* Override OS interfaces if the user requested. */
516ae19af49SJung-uk Kim     acpi_reset_interfaces(dev);
517ae19af49SJung-uk Kim 
5182be4e471SJung-uk Kim     /* Load ACPI name space. */
5192be4e471SJung-uk Kim     status = AcpiLoadTables();
5202be4e471SJung-uk Kim     if (ACPI_FAILURE(status)) {
5212be4e471SJung-uk Kim 	device_printf(dev, "Could not load Namespace: %s\n",
5222be4e471SJung-uk Kim 		      AcpiFormatException(status));
5232be4e471SJung-uk Kim 	goto out;
5242be4e471SJung-uk Kim     }
5252be4e471SJung-uk Kim 
526d320e05cSJohn Baldwin     /* Handle MCFG table if present. */
527d320e05cSJohn Baldwin     acpi_enable_pcie();
528d320e05cSJohn Baldwin 
52915e32d5dSMike Smith     /*
530be2b1797SNate Lawson      * Note that some systems (specifically, those with namespace evaluation
531be2b1797SNate Lawson      * issues that require the avoidance of parts of the namespace) must
532be2b1797SNate Lawson      * avoid running _INI and _STA on everything, as well as dodging the final
533be2b1797SNate Lawson      * object init pass.
53415e32d5dSMike Smith      *
53532d18aa5SMike Smith      * For these devices, we set ACPI_NO_DEVICE_INIT and ACPI_NO_OBJECT_INIT).
53632d18aa5SMike Smith      *
537be2b1797SNate Lawson      * XXX We should arrange for the object init pass after we have attached
538be2b1797SNate Lawson      *     all our child devices, but on many systems it works here.
53915e32d5dSMike Smith      */
54032d18aa5SMike Smith     flags = 0;
541d786139cSMaxime Henrion     if (testenv("debug.acpi.avoid"))
54232d18aa5SMike Smith 	flags = ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT;
543bee4aa4aSNate Lawson 
544bee4aa4aSNate Lawson     /* Bring the hardware and basic handlers online. */
545b53f2771SMike Smith     if (ACPI_FAILURE(status = AcpiEnableSubsystem(flags))) {
546be2b1797SNate Lawson 	device_printf(dev, "Could not enable ACPI: %s\n",
547be2b1797SNate Lawson 		      AcpiFormatException(status));
548cb9b0d80SMike Smith 	goto out;
54915e32d5dSMike Smith     }
55015e32d5dSMike Smith 
551f8335e3aSNate Lawson     /*
552f8335e3aSNate Lawson      * Call the ECDT probe function to provide EC functionality before
553f8335e3aSNate Lawson      * the namespace has been evaluated.
554da72d149SNate Lawson      *
555da72d149SNate Lawson      * XXX This happens before the sysresource devices have been probed and
556da72d149SNate Lawson      * attached so its resources come from nexus0.  In practice, this isn't
557da72d149SNate Lawson      * a problem but should be addressed eventually.
558f8335e3aSNate Lawson      */
559f8335e3aSNate Lawson     acpi_ec_ecdt_probe(dev);
560f8335e3aSNate Lawson 
561bee4aa4aSNate Lawson     /* Bring device objects and regions online. */
562b69ed3f4SMitsuru IWASAKI     if (ACPI_FAILURE(status = AcpiInitializeObjects(flags))) {
563be2b1797SNate Lawson 	device_printf(dev, "Could not initialize ACPI objects: %s\n",
564be2b1797SNate Lawson 		      AcpiFormatException(status));
565b69ed3f4SMitsuru IWASAKI 	goto out;
566b69ed3f4SMitsuru IWASAKI     }
567b69ed3f4SMitsuru IWASAKI 
56815e32d5dSMike Smith     /*
5691d073b1dSJohn Baldwin      * Setup our sysctl tree.
5701d073b1dSJohn Baldwin      *
5711d073b1dSJohn Baldwin      * XXX: This doesn't check to make sure that none of these fail.
5721d073b1dSJohn Baldwin      */
5731d073b1dSJohn Baldwin     sysctl_ctx_init(&sc->acpi_sysctl_ctx);
5741d073b1dSJohn Baldwin     sc->acpi_sysctl_tree = SYSCTL_ADD_NODE(&sc->acpi_sysctl_ctx,
5757029da5cSPawel Biernacki         SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO, device_get_name(dev),
5767029da5cSPawel Biernacki 	CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "");
5771d073b1dSJohn Baldwin     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
5787029da5cSPawel Biernacki 	OID_AUTO, "supported_sleep_state",
5797029da5cSPawel Biernacki 	CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_NEEDGIANT,
580ad73b301SAdrian Chadd 	0, 0, acpi_supported_sleep_state_sysctl, "A",
581ad73b301SAdrian Chadd 	"List supported ACPI sleep states.");
582d75de536SMitsuru IWASAKI     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
5837029da5cSPawel Biernacki 	OID_AUTO, "power_button_state",
5847029da5cSPawel Biernacki 	CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
585ad73b301SAdrian Chadd 	&sc->acpi_power_button_sx, 0, acpi_sleep_state_sysctl, "A",
586ad73b301SAdrian Chadd 	"Power button ACPI sleep state.");
5871d073b1dSJohn Baldwin     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
5887029da5cSPawel Biernacki 	OID_AUTO, "sleep_button_state",
5897029da5cSPawel Biernacki 	CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
590ad73b301SAdrian Chadd 	&sc->acpi_sleep_button_sx, 0, acpi_sleep_state_sysctl, "A",
591ad73b301SAdrian Chadd 	"Sleep button ACPI sleep state.");
5921d073b1dSJohn Baldwin     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
5937029da5cSPawel Biernacki 	OID_AUTO, "lid_switch_state",
5947029da5cSPawel Biernacki 	CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
595ad73b301SAdrian Chadd 	&sc->acpi_lid_switch_sx, 0, acpi_sleep_state_sysctl, "A",
596ad73b301SAdrian Chadd 	"Lid ACPI sleep state. Set to S3 if you want to suspend your laptop when close the Lid.");
597f86214b6SMitsuru IWASAKI     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
5987029da5cSPawel Biernacki 	OID_AUTO, "standby_state",
5997029da5cSPawel Biernacki 	CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
600f86214b6SMitsuru IWASAKI 	&sc->acpi_standby_sx, 0, acpi_sleep_state_sysctl, "A", "");
601f86214b6SMitsuru IWASAKI     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
6027029da5cSPawel Biernacki 	OID_AUTO, "suspend_state",
6037029da5cSPawel Biernacki 	CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_NEEDGIANT,
604f86214b6SMitsuru IWASAKI 	&sc->acpi_suspend_sx, 0, acpi_sleep_state_sysctl, "A", "");
6052d644607SMitsuru IWASAKI     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
606197b4dccSNate Lawson 	OID_AUTO, "sleep_delay", CTLFLAG_RW, &sc->acpi_sleep_delay, 0,
60731f301d0SChristian Brueffer 	"sleep delay in seconds");
608ff01efb5SMitsuru IWASAKI     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
609197b4dccSNate Lawson 	OID_AUTO, "s4bios", CTLFLAG_RW, &sc->acpi_s4bios, 0, "S4BIOS mode");
6101611ea87SMitsuru IWASAKI     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
611197b4dccSNate Lawson 	OID_AUTO, "verbose", CTLFLAG_RW, &sc->acpi_verbose, 0, "verbose mode");
612d85e6785SNate Lawson     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
613d85e6785SNate Lawson 	OID_AUTO, "disable_on_reboot", CTLFLAG_RW,
614d85e6785SNate Lawson 	&sc->acpi_do_disable, 0, "Disable ACPI when rebooting/halting system");
615d1b16e18SNate Lawson     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
616d1b16e18SNate Lawson 	OID_AUTO, "handle_reboot", CTLFLAG_RW,
617d1b16e18SNate Lawson 	&sc->acpi_handle_reboot, 0, "Use ACPI Reset Register to reboot");
618bf0c18ecSNate Lawson 
619bf0c18ecSNate Lawson     /*
6202b9609abSNate Lawson      * Default to 1 second before sleeping to give some machines time to
621bf0c18ecSNate Lawson      * stabilize.
622bf0c18ecSNate Lawson      */
6232b9609abSNate Lawson     sc->acpi_sleep_delay = 1;
6242d644607SMitsuru IWASAKI     if (bootverbose)
6252d644607SMitsuru IWASAKI 	sc->acpi_verbose = 1;
6262be111bfSDavide Italiano     if ((env = kern_getenv("hw.acpi.verbose")) != NULL) {
627965a34fbSNate Lawson 	if (strcmp(env, "0") != 0)
628498d464fSMitsuru IWASAKI 	    sc->acpi_verbose = 1;
629498d464fSMitsuru IWASAKI 	freeenv(env);
630498d464fSMitsuru IWASAKI     }
6311d073b1dSJohn Baldwin 
632ac731af5SJung-uk Kim     /* Only enable reboot by default if the FADT says it is available. */
633ac731af5SJung-uk Kim     if (AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER)
634ac731af5SJung-uk Kim 	sc->acpi_handle_reboot = 1;
635ac731af5SJung-uk Kim 
636fe5d5d7dSAndrew Turner #if !ACPI_REDUCED_HARDWARE
6372d610c46SNate Lawson     /* Only enable S4BIOS by default if the FACS says it is available. */
638d8c37c3aSAndrew Turner     if (AcpiGbl_FACS != NULL && AcpiGbl_FACS->Flags & ACPI_FACS_S4_BIOS_PRESENT)
6392d610c46SNate Lawson 	sc->acpi_s4bios = 1;
640fe5d5d7dSAndrew Turner #endif
6412d610c46SNate Lawson 
642a0e73a12SJung-uk Kim     /* Probe all supported sleep states. */
643a0e73a12SJung-uk Kim     acpi_sleep_states[ACPI_STATE_S0] = TRUE;
644a0e73a12SJung-uk Kim     for (state = ACPI_STATE_S1; state < ACPI_S_STATE_COUNT; state++)
645efcc2a30SJung-uk Kim 	if (ACPI_SUCCESS(AcpiEvaluateObject(ACPI_ROOT_OBJECT,
646efcc2a30SJung-uk Kim 	    __DECONST(char *, AcpiGbl_SleepStateNames[state]), NULL, NULL)) &&
647efcc2a30SJung-uk Kim 	    ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB)))
648a0e73a12SJung-uk Kim 	    acpi_sleep_states[state] = TRUE;
649a0e73a12SJung-uk Kim 
6501d073b1dSJohn Baldwin     /*
651ea27c63eSNate Lawson      * Dispatch the default sleep state to devices.  The lid switch is set
652a0e73a12SJung-uk Kim      * to UNKNOWN by default to avoid surprising users.
65315e32d5dSMike Smith      */
654a0e73a12SJung-uk Kim     sc->acpi_power_button_sx = acpi_sleep_states[ACPI_STATE_S5] ?
655a0e73a12SJung-uk Kim 	ACPI_STATE_S5 : ACPI_STATE_UNKNOWN;
656a0e73a12SJung-uk Kim     sc->acpi_lid_switch_sx = ACPI_STATE_UNKNOWN;
657a0e73a12SJung-uk Kim     sc->acpi_standby_sx = acpi_sleep_states[ACPI_STATE_S1] ?
658a0e73a12SJung-uk Kim 	ACPI_STATE_S1 : ACPI_STATE_UNKNOWN;
659a0e73a12SJung-uk Kim     sc->acpi_suspend_sx = acpi_sleep_states[ACPI_STATE_S3] ?
660a0e73a12SJung-uk Kim 	ACPI_STATE_S3 : ACPI_STATE_UNKNOWN;
66115e32d5dSMike Smith 
662ea27c63eSNate Lawson     /* Pick the first valid sleep state for the sleep button default. */
663a0e73a12SJung-uk Kim     sc->acpi_sleep_button_sx = ACPI_STATE_UNKNOWN;
66400a30448SNate Lawson     for (state = ACPI_STATE_S1; state <= ACPI_STATE_S4; state++)
665a0e73a12SJung-uk Kim 	if (acpi_sleep_states[state]) {
666ea27c63eSNate Lawson 	    sc->acpi_sleep_button_sx = state;
667ea27c63eSNate Lawson 	    break;
668ea27c63eSNate Lawson 	}
669ea27c63eSNate Lawson 
67013d4f7baSMitsuru IWASAKI     acpi_enable_fixed_events(sc);
67115e32d5dSMike Smith 
67215e32d5dSMike Smith     /*
67315e32d5dSMike Smith      * Scan the namespace and attach/initialise children.
67415e32d5dSMike Smith      */
67515e32d5dSMike Smith 
67659e472e9SNate Lawson     /* Register our shutdown handler. */
677be2b1797SNate Lawson     EVENTHANDLER_REGISTER(shutdown_final, acpi_shutdown_final, sc,
678be2b1797SNate Lawson 	SHUTDOWN_PRI_LAST);
67915e32d5dSMike Smith 
68015e32d5dSMike Smith     /*
68115e32d5dSMike Smith      * Register our acpi event handlers.
68215e32d5dSMike Smith      * XXX should be configurable eg. via userland policy manager.
68315e32d5dSMike Smith      */
684be2b1797SNate Lawson     EVENTHANDLER_REGISTER(acpi_sleep_event, acpi_system_eventhandler_sleep,
685be2b1797SNate Lawson 	sc, ACPI_EVENT_PRI_LAST);
686be2b1797SNate Lawson     EVENTHANDLER_REGISTER(acpi_wakeup_event, acpi_system_eventhandler_wakeup,
687be2b1797SNate Lawson 	sc, ACPI_EVENT_PRI_LAST);
68815e32d5dSMike Smith 
689be2b1797SNate Lawson     /* Flag our initial states. */
690a0e73a12SJung-uk Kim     sc->acpi_enabled = TRUE;
69115e32d5dSMike Smith     sc->acpi_sstate = ACPI_STATE_S0;
692a0e73a12SJung-uk Kim     sc->acpi_sleep_disabled = TRUE;
69315e32d5dSMike Smith 
694be2b1797SNate Lawson     /* Create the control device */
695d1655c6fSEdward Tomasz Napierala     sc->acpi_dev_t = make_dev(&acpi_cdevsw, 0, UID_ROOT, GID_OPERATOR, 0664,
6962a4689e8SRobert Watson 			      "acpi");
69715e32d5dSMike Smith     sc->acpi_dev_t->si_drv1 = sc;
69815e32d5dSMike Smith 
699be2b1797SNate Lawson     if ((error = acpi_machdep_init(dev)))
700f86214b6SMitsuru IWASAKI 	goto out;
701f86214b6SMitsuru IWASAKI 
702f9390180SMitsuru IWASAKI     /* Register ACPI again to pass the correct argument of pm_func. */
703f9390180SMitsuru IWASAKI     power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, sc);
704f9390180SMitsuru IWASAKI 
705855e49f3SAlexander Motin     acpi_platform_osc(dev);
706855e49f3SAlexander Motin 
70764de8019SJohn Baldwin     if (!acpi_disabled("bus")) {
70864de8019SJohn Baldwin 	EVENTHANDLER_REGISTER(dev_lookup, acpi_lookup, NULL, 1000);
709eeb6dba2SJohn Baldwin 	acpi_probe_children(dev);
71064de8019SJohn Baldwin     }
711eeb6dba2SJohn Baldwin 
7125a77b11bSJung-uk Kim     /* Update all GPEs and enable runtime GPEs. */
7135a77b11bSJung-uk Kim     status = AcpiUpdateAllGpes();
7145a77b11bSJung-uk Kim     if (ACPI_FAILURE(status))
7155a77b11bSJung-uk Kim 	device_printf(dev, "Could not update all GPEs: %s\n",
7165a77b11bSJung-uk Kim 	    AcpiFormatException(status));
7175a77b11bSJung-uk Kim 
718a0e73a12SJung-uk Kim     /* Allow sleep request after a while. */
719fadf3fb9SJohn Baldwin     callout_init_mtx(&acpi_sleep_timer, &acpi_mutex, 0);
720fadf3fb9SJohn Baldwin     callout_reset(&acpi_sleep_timer, hz * ACPI_MINIMUM_AWAKETIME,
721fadf3fb9SJohn Baldwin 	acpi_sleep_enable, sc);
722a0e73a12SJung-uk Kim 
723cb9b0d80SMike Smith     error = 0;
724cb9b0d80SMike Smith 
725cb9b0d80SMike Smith  out:
726cb9b0d80SMike Smith     return_VALUE (error);
72715e32d5dSMike Smith }
72815e32d5dSMike Smith 
729a7a3177fSJung-uk Kim static void
730a7a3177fSJung-uk Kim acpi_set_power_children(device_t dev, int state)
731a7a3177fSJung-uk Kim {
73244aba0f6SJung-uk Kim 	device_t child;
733a7a3177fSJung-uk Kim 	device_t *devlist;
734a7a3177fSJung-uk Kim 	int dstate, i, numdevs;
735a7a3177fSJung-uk Kim 
736a7a3177fSJung-uk Kim 	if (device_get_children(dev, &devlist, &numdevs) != 0)
737a7a3177fSJung-uk Kim 		return;
738a7a3177fSJung-uk Kim 
739a7a3177fSJung-uk Kim 	/*
740a7a3177fSJung-uk Kim 	 * Retrieve and set D-state for the sleep state if _SxD is present.
741a7a3177fSJung-uk Kim 	 * Skip children who aren't attached since they are handled separately.
742a7a3177fSJung-uk Kim 	 */
743a7a3177fSJung-uk Kim 	for (i = 0; i < numdevs; i++) {
744a7a3177fSJung-uk Kim 		child = devlist[i];
745a7a3177fSJung-uk Kim 		dstate = state;
746a7a3177fSJung-uk Kim 		if (device_is_attached(child) &&
74744aba0f6SJung-uk Kim 		    acpi_device_pwr_for_sleep(dev, child, &dstate) == 0)
748a7a3177fSJung-uk Kim 			acpi_set_powerstate(child, dstate);
749a7a3177fSJung-uk Kim 	}
750a7a3177fSJung-uk Kim 	free(devlist, M_TEMP);
751a7a3177fSJung-uk Kim }
752a7a3177fSJung-uk Kim 
753169b539aSNate Lawson static int
75410ce62b9SNate Lawson acpi_suspend(device_t dev)
75510ce62b9SNate Lawson {
756a7a3177fSJung-uk Kim     int error;
75710ce62b9SNate Lawson 
758a56fe095SJohn Baldwin     GIANT_REQUIRED;
759a56fe095SJohn Baldwin 
76010ce62b9SNate Lawson     error = bus_generic_suspend(dev);
761a7a3177fSJung-uk Kim     if (error == 0)
762a7a3177fSJung-uk Kim 	acpi_set_power_children(dev, ACPI_STATE_D3);
76310ce62b9SNate Lawson 
76410ce62b9SNate Lawson     return (error);
76510ce62b9SNate Lawson }
76610ce62b9SNate Lawson 
76710ce62b9SNate Lawson static int
76810ce62b9SNate Lawson acpi_resume(device_t dev)
76910ce62b9SNate Lawson {
77010ce62b9SNate Lawson 
771a56fe095SJohn Baldwin     GIANT_REQUIRED;
772a56fe095SJohn Baldwin 
773a7a3177fSJung-uk Kim     acpi_set_power_children(dev, ACPI_STATE_D0);
77410ce62b9SNate Lawson 
77510ce62b9SNate Lawson     return (bus_generic_resume(dev));
77610ce62b9SNate Lawson }
77710ce62b9SNate Lawson 
77810ce62b9SNate Lawson static int
779169b539aSNate Lawson acpi_shutdown(device_t dev)
780169b539aSNate Lawson {
781169b539aSNate Lawson 
782a56fe095SJohn Baldwin     GIANT_REQUIRED;
783a56fe095SJohn Baldwin 
7840e414868SNate Lawson     /* Allow children to shutdown first. */
7850e414868SNate Lawson     bus_generic_shutdown(dev);
7860e414868SNate Lawson 
787bee4aa4aSNate Lawson     /*
788bee4aa4aSNate Lawson      * Enable any GPEs that are able to power-on the system (i.e., RTC).
789bee4aa4aSNate Lawson      * Also, disable any that are not valid for this state (most).
790bee4aa4aSNate Lawson      */
791d4b9ff91SNate Lawson     acpi_wake_prep_walk(ACPI_STATE_S5);
792d4b9ff91SNate Lawson 
793169b539aSNate Lawson     return (0);
794169b539aSNate Lawson }
795169b539aSNate Lawson 
79615e32d5dSMike Smith /*
79715e32d5dSMike Smith  * Handle a new device being added
79815e32d5dSMike Smith  */
79915e32d5dSMike Smith static device_t
8003d844eddSAndriy Gapon acpi_add_child(device_t bus, u_int order, const char *name, int unit)
80115e32d5dSMike Smith {
80215e32d5dSMike Smith     struct acpi_device	*ad;
80315e32d5dSMike Smith     device_t		child;
80415e32d5dSMike Smith 
805be2b1797SNate Lawson     if ((ad = malloc(sizeof(*ad), M_ACPIDEV, M_NOWAIT | M_ZERO)) == NULL)
80615e32d5dSMike Smith 	return (NULL);
80715e32d5dSMike Smith 
80815e32d5dSMike Smith     resource_list_init(&ad->ad_rl);
80915e32d5dSMike Smith 
81015e32d5dSMike Smith     child = device_add_child_ordered(bus, order, name, unit);
81115e32d5dSMike Smith     if (child != NULL)
81215e32d5dSMike Smith 	device_set_ivars(child, ad);
81343ce1c77SNate Lawson     else
81443ce1c77SNate Lawson 	free(ad, M_ACPIDEV);
81515e32d5dSMike Smith     return (child);
81615e32d5dSMike Smith }
81715e32d5dSMike Smith 
81815e32d5dSMike Smith static int
81915e32d5dSMike Smith acpi_print_child(device_t bus, device_t child)
82015e32d5dSMike Smith {
82115e32d5dSMike Smith     struct acpi_device	 *adev = device_get_ivars(child);
82215e32d5dSMike Smith     struct resource_list *rl = &adev->ad_rl;
82315e32d5dSMike Smith     int retval = 0;
82415e32d5dSMike Smith 
82515e32d5dSMike Smith     retval += bus_print_child_header(bus, child);
826da1b038aSJustin Hibbits     retval += resource_list_print_type(rl, "port",  SYS_RES_IOPORT, "%#jx");
827da1b038aSJustin Hibbits     retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#jx");
828da1b038aSJustin Hibbits     retval += resource_list_print_type(rl, "irq",   SYS_RES_IRQ,    "%jd");
829da1b038aSJustin Hibbits     retval += resource_list_print_type(rl, "drq",   SYS_RES_DRQ,    "%jd");
830a91c5fa8SNate Lawson     if (device_get_flags(child))
831a91c5fa8SNate Lawson 	retval += printf(" flags %#x", device_get_flags(child));
832ffcf962dSAdrian Chadd     retval += bus_print_child_domain(bus, child);
8332c8d3b23SNate Lawson     retval += bus_print_child_footer(bus, child);
83415e32d5dSMike Smith 
83515e32d5dSMike Smith     return (retval);
83615e32d5dSMike Smith }
83715e32d5dSMike Smith 
83810ce62b9SNate Lawson /*
83910ce62b9SNate Lawson  * If this device is an ACPI child but no one claimed it, attempt
84010ce62b9SNate Lawson  * to power it off.  We'll power it back up when a driver is added.
84110ce62b9SNate Lawson  *
84210ce62b9SNate Lawson  * XXX Disabled for now since many necessary devices (like fdc and
84310ce62b9SNate Lawson  * ATA) don't claim the devices we created for them but still expect
84410ce62b9SNate Lawson  * them to be powered up.
84510ce62b9SNate Lawson  */
84610ce62b9SNate Lawson static void
84710ce62b9SNate Lawson acpi_probe_nomatch(device_t bus, device_t child)
84810ce62b9SNate Lawson {
84996cf0b6dSWarner Losh #ifdef ACPI_ENABLE_POWERDOWN_NODRIVER
850a7a3177fSJung-uk Kim     acpi_set_powerstate(child, ACPI_STATE_D3);
85196cf0b6dSWarner Losh #endif
85210ce62b9SNate Lawson }
85310ce62b9SNate Lawson 
85410ce62b9SNate Lawson /*
85510ce62b9SNate Lawson  * If a new driver has a chance to probe a child, first power it up.
85610ce62b9SNate Lawson  *
85710ce62b9SNate Lawson  * XXX Disabled for now (see acpi_probe_nomatch for details).
85810ce62b9SNate Lawson  */
85910ce62b9SNate Lawson static void
86010ce62b9SNate Lawson acpi_driver_added(device_t dev, driver_t *driver)
86110ce62b9SNate Lawson {
86210ce62b9SNate Lawson     device_t child, *devlist;
86310ce62b9SNate Lawson     int i, numdevs;
86410ce62b9SNate Lawson 
86510ce62b9SNate Lawson     DEVICE_IDENTIFY(driver, dev);
866099ea4b5SWarner Losh     if (device_get_children(dev, &devlist, &numdevs))
867099ea4b5SWarner Losh 	    return;
86810ce62b9SNate Lawson     for (i = 0; i < numdevs; i++) {
86910ce62b9SNate Lawson 	child = devlist[i];
87010ce62b9SNate Lawson 	if (device_get_state(child) == DS_NOTPRESENT) {
87196cf0b6dSWarner Losh #ifdef ACPI_ENABLE_POWERDOWN_NODRIVER
872a7a3177fSJung-uk Kim 	    acpi_set_powerstate(child, ACPI_STATE_D0);
87310ce62b9SNate Lawson 	    if (device_probe_and_attach(child) != 0)
874a7a3177fSJung-uk Kim 		acpi_set_powerstate(child, ACPI_STATE_D3);
87596cf0b6dSWarner Losh #else
87696cf0b6dSWarner Losh 	    device_probe_and_attach(child);
87796cf0b6dSWarner Losh #endif
87810ce62b9SNate Lawson 	}
87910ce62b9SNate Lawson     }
88010ce62b9SNate Lawson     free(devlist, M_TEMP);
88110ce62b9SNate Lawson }
88210ce62b9SNate Lawson 
88363600cc3SNate Lawson /* Location hint for devctl(8) */
88463600cc3SNate Lawson static int
885ddfc9c4cSWarner Losh acpi_child_location_method(device_t cbdev, device_t child, struct sbuf *sb)
886247648afSTakanori Watanabe {
887247648afSTakanori Watanabe     struct acpi_device *dinfo = device_get_ivars(child);
8889cf5a6aaSAdrian Chadd     int pxm;
889247648afSTakanori Watanabe 
8909cf5a6aaSAdrian Chadd     if (dinfo->ad_handle) {
891ddfc9c4cSWarner Losh         sbuf_printf(sb, "handle=%s", acpi_name(dinfo->ad_handle));
8929cf5a6aaSAdrian Chadd         if (ACPI_SUCCESS(acpi_GetInteger(dinfo->ad_handle, "_PXM", &pxm))) {
893ddfc9c4cSWarner Losh             sbuf_printf(sb, " _PXM=%d", pxm);
8949cf5a6aaSAdrian Chadd 	}
8959cf5a6aaSAdrian Chadd     }
896247648afSTakanori Watanabe     return (0);
897247648afSTakanori Watanabe }
898247648afSTakanori Watanabe 
89963600cc3SNate Lawson /* PnP information for devctl(8) */
900ddf8c230SVladimir Kondratyev int
901ddfc9c4cSWarner Losh acpi_pnpinfo(ACPI_HANDLE handle, struct sbuf *sb)
902247648afSTakanori Watanabe {
90392488a57SJung-uk Kim     ACPI_DEVICE_INFO *adinfo;
904247648afSTakanori Watanabe 
905ddf8c230SVladimir Kondratyev     if (ACPI_FAILURE(AcpiGetObjectInfo(handle, &adinfo))) {
906ddfc9c4cSWarner Losh 	sbuf_printf(sb, "unknown");
90792488a57SJung-uk Kim 	return (0);
90892488a57SJung-uk Kim     }
90992488a57SJung-uk Kim 
910ddfc9c4cSWarner Losh     sbuf_printf(sb, "_HID=%s _UID=%lu _CID=%s",
911247648afSTakanori Watanabe 	(adinfo->Valid & ACPI_VALID_HID) ?
91292488a57SJung-uk Kim 	adinfo->HardwareId.String : "none",
91363600cc3SNate Lawson 	(adinfo->Valid & ACPI_VALID_UID) ?
914359a5f96SConrad Meyer 	strtoul(adinfo->UniqueId.String, NULL, 10) : 0UL,
915359a5f96SConrad Meyer 	((adinfo->Valid & ACPI_VALID_CID) &&
916359a5f96SConrad Meyer 	 adinfo->CompatibleIdList.Count > 0) ?
917359a5f96SConrad Meyer 	adinfo->CompatibleIdList.Ids[0].String : "none");
918247648afSTakanori Watanabe     AcpiOsFree(adinfo);
919247648afSTakanori Watanabe 
920247648afSTakanori Watanabe     return (0);
921247648afSTakanori Watanabe }
922247648afSTakanori Watanabe 
923ddf8c230SVladimir Kondratyev static int
924ddfc9c4cSWarner Losh acpi_child_pnpinfo_method(device_t cbdev, device_t child, struct sbuf *sb)
925ddf8c230SVladimir Kondratyev {
926ddf8c230SVladimir Kondratyev     struct acpi_device *dinfo = device_get_ivars(child);
927ddf8c230SVladimir Kondratyev 
928ddfc9c4cSWarner Losh     return (acpi_pnpinfo(dinfo->ad_handle, sb));
929ddf8c230SVladimir Kondratyev }
930ddf8c230SVladimir Kondratyev 
931247648afSTakanori Watanabe /*
932709749aaSVladimir Kondratyev  * Handle device deletion.
933709749aaSVladimir Kondratyev  */
934709749aaSVladimir Kondratyev static void
935709749aaSVladimir Kondratyev acpi_child_deleted(device_t dev, device_t child)
936709749aaSVladimir Kondratyev {
937709749aaSVladimir Kondratyev     struct acpi_device *dinfo = device_get_ivars(child);
938709749aaSVladimir Kondratyev 
939709749aaSVladimir Kondratyev     if (acpi_get_device(dinfo->ad_handle) == child)
940709749aaSVladimir Kondratyev 	AcpiDetachData(dinfo->ad_handle, acpi_fake_objhandler);
941709749aaSVladimir Kondratyev }
942709749aaSVladimir Kondratyev 
943709749aaSVladimir Kondratyev /*
94415e32d5dSMike Smith  * Handle per-device ivars
94515e32d5dSMike Smith  */
94615e32d5dSMike Smith static int
94715e32d5dSMike Smith acpi_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
94815e32d5dSMike Smith {
94915e32d5dSMike Smith     struct acpi_device	*ad;
95015e32d5dSMike Smith 
95115e32d5dSMike Smith     if ((ad = device_get_ivars(child)) == NULL) {
9522d0c82e8SJung-uk Kim 	device_printf(child, "device has no ivars\n");
95315e32d5dSMike Smith 	return (ENOENT);
95415e32d5dSMike Smith     }
95515e32d5dSMike Smith 
956be2b1797SNate Lawson     /* ACPI and ISA compatibility ivars */
95715e32d5dSMike Smith     switch(index) {
95815e32d5dSMike Smith     case ACPI_IVAR_HANDLE:
95915e32d5dSMike Smith 	*(ACPI_HANDLE *)result = ad->ad_handle;
96015e32d5dSMike Smith 	break;
96115e32d5dSMike Smith     case ACPI_IVAR_PRIVATE:
96215e32d5dSMike Smith 	*(void **)result = ad->ad_private;
96315e32d5dSMike Smith 	break;
964d4b9ff91SNate Lawson     case ACPI_IVAR_FLAGS:
965d4b9ff91SNate Lawson 	*(int *)result = ad->ad_flags;
966d4b9ff91SNate Lawson 	break;
96732d18aa5SMike Smith     case ISA_IVAR_VENDORID:
96832d18aa5SMike Smith     case ISA_IVAR_SERIAL:
96932d18aa5SMike Smith     case ISA_IVAR_COMPATID:
97032d18aa5SMike Smith 	*(int *)result = -1;
97132d18aa5SMike Smith 	break;
97232d18aa5SMike Smith     case ISA_IVAR_LOGICALID:
97332d18aa5SMike Smith 	*(int *)result = acpi_isa_get_logicalid(child);
97432d18aa5SMike Smith 	break;
9750e68afe5SAndrew Turner     case PCI_IVAR_CLASS:
9760e68afe5SAndrew Turner 	*(uint8_t*)result = (ad->ad_cls_class >> 16) & 0xff;
9770e68afe5SAndrew Turner 	break;
9780e68afe5SAndrew Turner     case PCI_IVAR_SUBCLASS:
9790e68afe5SAndrew Turner 	*(uint8_t*)result = (ad->ad_cls_class >> 8) & 0xff;
9800e68afe5SAndrew Turner 	break;
9810e68afe5SAndrew Turner     case PCI_IVAR_PROGIF:
9820e68afe5SAndrew Turner 	*(uint8_t*)result = (ad->ad_cls_class >> 0) & 0xff;
9830e68afe5SAndrew Turner 	break;
98415e32d5dSMike Smith     default:
98515e32d5dSMike Smith 	return (ENOENT);
98615e32d5dSMike Smith     }
987be2b1797SNate Lawson 
98815e32d5dSMike Smith     return (0);
98915e32d5dSMike Smith }
99015e32d5dSMike Smith 
99115e32d5dSMike Smith static int
99215e32d5dSMike Smith acpi_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
99315e32d5dSMike Smith {
99415e32d5dSMike Smith     struct acpi_device	*ad;
99515e32d5dSMike Smith 
99615e32d5dSMike Smith     if ((ad = device_get_ivars(child)) == NULL) {
9972d0c82e8SJung-uk Kim 	device_printf(child, "device has no ivars\n");
99815e32d5dSMike Smith 	return (ENOENT);
99915e32d5dSMike Smith     }
100015e32d5dSMike Smith 
100115e32d5dSMike Smith     switch(index) {
100215e32d5dSMike Smith     case ACPI_IVAR_HANDLE:
100315e32d5dSMike Smith 	ad->ad_handle = (ACPI_HANDLE)value;
100415e32d5dSMike Smith 	break;
100515e32d5dSMike Smith     case ACPI_IVAR_PRIVATE:
100615e32d5dSMike Smith 	ad->ad_private = (void *)value;
100715e32d5dSMike Smith 	break;
1008d4b9ff91SNate Lawson     case ACPI_IVAR_FLAGS:
1009d4b9ff91SNate Lawson 	ad->ad_flags = (int)value;
1010d4b9ff91SNate Lawson 	break;
101115e32d5dSMike Smith     default:
10122ab060eeSWarner Losh 	panic("bad ivar write request (%d)", index);
101315e32d5dSMike Smith 	return (ENOENT);
101415e32d5dSMike Smith     }
1015be2b1797SNate Lawson 
101615e32d5dSMike Smith     return (0);
101715e32d5dSMike Smith }
101815e32d5dSMike Smith 
101915e32d5dSMike Smith /*
102015e32d5dSMike Smith  * Handle child resource allocation/removal
102115e32d5dSMike Smith  */
102291233413SNate Lawson static struct resource_list *
102391233413SNate Lawson acpi_get_rlist(device_t dev, device_t child)
102415e32d5dSMike Smith {
102591233413SNate Lawson     struct acpi_device		*ad;
102615e32d5dSMike Smith 
102791233413SNate Lawson     ad = device_get_ivars(child);
102891233413SNate Lawson     return (&ad->ad_rl);
102915e32d5dSMike Smith }
103015e32d5dSMike Smith 
10310d484d24SJohn Baldwin static int
10320d484d24SJohn Baldwin acpi_match_resource_hint(device_t dev, int type, long value)
10330d484d24SJohn Baldwin {
10340d484d24SJohn Baldwin     struct acpi_device *ad = device_get_ivars(dev);
10350d484d24SJohn Baldwin     struct resource_list *rl = &ad->ad_rl;
10360d484d24SJohn Baldwin     struct resource_list_entry *rle;
10370d484d24SJohn Baldwin 
10380d484d24SJohn Baldwin     STAILQ_FOREACH(rle, rl, link) {
10390d484d24SJohn Baldwin 	if (rle->type != type)
10400d484d24SJohn Baldwin 	    continue;
10410d484d24SJohn Baldwin 	if (rle->start <= value && rle->end >= value)
10420d484d24SJohn Baldwin 	    return (1);
10430d484d24SJohn Baldwin     }
10440d484d24SJohn Baldwin     return (0);
10450d484d24SJohn Baldwin }
10460d484d24SJohn Baldwin 
10470d484d24SJohn Baldwin /*
10480d484d24SJohn Baldwin  * Wire device unit numbers based on resource matches in hints.
10490d484d24SJohn Baldwin  */
10500d484d24SJohn Baldwin static void
10510d484d24SJohn Baldwin acpi_hint_device_unit(device_t acdev, device_t child, const char *name,
10520d484d24SJohn Baldwin     int *unitp)
10530d484d24SJohn Baldwin {
10540d484d24SJohn Baldwin     const char *s;
10550d484d24SJohn Baldwin     long value;
10560d484d24SJohn Baldwin     int line, matches, unit;
10570d484d24SJohn Baldwin 
10580d484d24SJohn Baldwin     /*
10590d484d24SJohn Baldwin      * Iterate over all the hints for the devices with the specified
10600d484d24SJohn Baldwin      * name to see if one's resources are a subset of this device.
10610d484d24SJohn Baldwin      */
10620d484d24SJohn Baldwin     line = 0;
10634571c92fSWarner Losh     while (resource_find_dev(&line, name, &unit, "at", NULL) == 0) {
10640d484d24SJohn Baldwin 	/* Must have an "at" for acpi or isa. */
10650d484d24SJohn Baldwin 	resource_string_value(name, unit, "at", &s);
10660d484d24SJohn Baldwin 	if (!(strcmp(s, "acpi0") == 0 || strcmp(s, "acpi") == 0 ||
10670d484d24SJohn Baldwin 	    strcmp(s, "isa0") == 0 || strcmp(s, "isa") == 0))
10680d484d24SJohn Baldwin 	    continue;
10690d484d24SJohn Baldwin 
10700d484d24SJohn Baldwin 	/*
10712fcd493cSJohn Baldwin 	 * Check for matching resources.  We must have at least one match.
10722fcd493cSJohn Baldwin 	 * Since I/O and memory resources cannot be shared, if we get a
10732fcd493cSJohn Baldwin 	 * match on either of those, ignore any mismatches in IRQs or DRQs.
10740d484d24SJohn Baldwin 	 *
10750d484d24SJohn Baldwin 	 * XXX: We may want to revisit this to be more lenient and wire
10760d484d24SJohn Baldwin 	 * as long as it gets one match.
10770d484d24SJohn Baldwin 	 */
10780d484d24SJohn Baldwin 	matches = 0;
10790d484d24SJohn Baldwin 	if (resource_long_value(name, unit, "port", &value) == 0) {
10802fcd493cSJohn Baldwin 	    /*
10812fcd493cSJohn Baldwin 	     * Floppy drive controllers are notorious for having a
10822fcd493cSJohn Baldwin 	     * wide variety of resources not all of which include the
10832fcd493cSJohn Baldwin 	     * first port that is specified by the hint (typically
10842fcd493cSJohn Baldwin 	     * 0x3f0) (see the comment above fdc_isa_alloc_resources()
10852fcd493cSJohn Baldwin 	     * in fdc_isa.c).  However, they do all seem to include
10862fcd493cSJohn Baldwin 	     * port + 2 (e.g. 0x3f2) so for a floppy device, look for
10872fcd493cSJohn Baldwin 	     * 'value + 2' in the port resources instead of the hint
10882fcd493cSJohn Baldwin 	     * value.
10892fcd493cSJohn Baldwin 	     */
10902fcd493cSJohn Baldwin 	    if (strcmp(name, "fdc") == 0)
10912fcd493cSJohn Baldwin 		value += 2;
10920d484d24SJohn Baldwin 	    if (acpi_match_resource_hint(child, SYS_RES_IOPORT, value))
10930d484d24SJohn Baldwin 		matches++;
10940d484d24SJohn Baldwin 	    else
10950d484d24SJohn Baldwin 		continue;
10960d484d24SJohn Baldwin 	}
10970d484d24SJohn Baldwin 	if (resource_long_value(name, unit, "maddr", &value) == 0) {
10980d484d24SJohn Baldwin 	    if (acpi_match_resource_hint(child, SYS_RES_MEMORY, value))
10990d484d24SJohn Baldwin 		matches++;
11000d484d24SJohn Baldwin 	    else
11010d484d24SJohn Baldwin 		continue;
11020d484d24SJohn Baldwin 	}
11032fcd493cSJohn Baldwin 	if (matches > 0)
11042fcd493cSJohn Baldwin 	    goto matched;
11050d484d24SJohn Baldwin 	if (resource_long_value(name, unit, "irq", &value) == 0) {
11060d484d24SJohn Baldwin 	    if (acpi_match_resource_hint(child, SYS_RES_IRQ, value))
11070d484d24SJohn Baldwin 		matches++;
11080d484d24SJohn Baldwin 	    else
11090d484d24SJohn Baldwin 		continue;
11100d484d24SJohn Baldwin 	}
11110d484d24SJohn Baldwin 	if (resource_long_value(name, unit, "drq", &value) == 0) {
11120d484d24SJohn Baldwin 	    if (acpi_match_resource_hint(child, SYS_RES_DRQ, value))
11130d484d24SJohn Baldwin 		matches++;
11140d484d24SJohn Baldwin 	    else
11150d484d24SJohn Baldwin 		continue;
11160d484d24SJohn Baldwin 	}
11170d484d24SJohn Baldwin 
11182fcd493cSJohn Baldwin     matched:
11190d484d24SJohn Baldwin 	if (matches > 0) {
11200d484d24SJohn Baldwin 	    /* We have a winner! */
11210d484d24SJohn Baldwin 	    *unitp = unit;
11220d484d24SJohn Baldwin 	    break;
11230d484d24SJohn Baldwin 	}
11240d484d24SJohn Baldwin     }
11250d484d24SJohn Baldwin }
11260d484d24SJohn Baldwin 
1127adad4744SNate Lawson /*
11288d791e5aSJohn Baldwin  * Fetch the NUMA domain for a device by mapping the value returned by
11298d791e5aSJohn Baldwin  * _PXM to a NUMA domain.  If the device does not have a _PXM method,
11308d791e5aSJohn Baldwin  * -2 is returned.  If any other error occurs, -1 is returned.
11315d18c60aSAdrian Chadd  */
11328d791e5aSJohn Baldwin static int
11338d791e5aSJohn Baldwin acpi_parse_pxm(device_t dev)
11345d18c60aSAdrian Chadd {
1135b6715dabSJeff Roberson #ifdef NUMA
1136523a67bbSOleksandr Tymoshenko #if defined(__i386__) || defined(__amd64__) || defined(__aarch64__)
11378d791e5aSJohn Baldwin 	ACPI_HANDLE handle;
11388d791e5aSJohn Baldwin 	ACPI_STATUS status;
11398d791e5aSJohn Baldwin 	int pxm;
11405d18c60aSAdrian Chadd 
11418d791e5aSJohn Baldwin 	handle = acpi_get_handle(dev);
11428d791e5aSJohn Baldwin 	if (handle == NULL)
11438d791e5aSJohn Baldwin 		return (-2);
11448d791e5aSJohn Baldwin 	status = acpi_GetInteger(handle, "_PXM", &pxm);
11458d791e5aSJohn Baldwin 	if (ACPI_SUCCESS(status))
11468d791e5aSJohn Baldwin 		return (acpi_map_pxm_to_vm_domainid(pxm));
11478d791e5aSJohn Baldwin 	if (status == AE_NOT_FOUND)
11488d791e5aSJohn Baldwin 		return (-2);
11498a08b7d3SJohn Baldwin #endif
1150bcc51ef4SMark Johnston #endif
11518d791e5aSJohn Baldwin 	return (-1);
11528d791e5aSJohn Baldwin }
11538a08b7d3SJohn Baldwin 
11548d791e5aSJohn Baldwin int
11558d791e5aSJohn Baldwin acpi_get_cpus(device_t dev, device_t child, enum cpu_sets op, size_t setsize,
11568d791e5aSJohn Baldwin     cpuset_t *cpuset)
11578d791e5aSJohn Baldwin {
11588d791e5aSJohn Baldwin 	int d, error;
11598d791e5aSJohn Baldwin 
11608d791e5aSJohn Baldwin 	d = acpi_parse_pxm(child);
11618d791e5aSJohn Baldwin 	if (d < 0)
11628d791e5aSJohn Baldwin 		return (bus_generic_get_cpus(dev, child, op, setsize, cpuset));
11638d791e5aSJohn Baldwin 
11648d791e5aSJohn Baldwin 	switch (op) {
11658d791e5aSJohn Baldwin 	case LOCAL_CPUS:
11668d791e5aSJohn Baldwin 		if (setsize != sizeof(cpuset_t))
11678d791e5aSJohn Baldwin 			return (EINVAL);
11688d791e5aSJohn Baldwin 		*cpuset = cpuset_domain[d];
11698a08b7d3SJohn Baldwin 		return (0);
11708d791e5aSJohn Baldwin 	case INTR_CPUS:
11718d791e5aSJohn Baldwin 		error = bus_generic_get_cpus(dev, child, op, setsize, cpuset);
11728d791e5aSJohn Baldwin 		if (error != 0)
11738d791e5aSJohn Baldwin 			return (error);
11748d791e5aSJohn Baldwin 		if (setsize != sizeof(cpuset_t))
11758d791e5aSJohn Baldwin 			return (EINVAL);
11768d791e5aSJohn Baldwin 		CPU_AND(cpuset, &cpuset_domain[d]);
11778d791e5aSJohn Baldwin 		return (0);
11788d791e5aSJohn Baldwin 	default:
11798d791e5aSJohn Baldwin 		return (bus_generic_get_cpus(dev, child, op, setsize, cpuset));
11808d791e5aSJohn Baldwin 	}
11815d18c60aSAdrian Chadd }
11825d18c60aSAdrian Chadd 
11835d18c60aSAdrian Chadd /*
11848d791e5aSJohn Baldwin  * Fetch the NUMA domain for the given device 'dev'.
1185ffcf962dSAdrian Chadd  *
1186ffcf962dSAdrian Chadd  * If a device has a _PXM method, map that to a NUMA domain.
11878d791e5aSJohn Baldwin  * Otherwise, pass the request up to the parent.
11888d791e5aSJohn Baldwin  * If there's no matching domain or the domain cannot be
11898d791e5aSJohn Baldwin  * determined, return ENOENT.
1190ffcf962dSAdrian Chadd  */
1191ffcf962dSAdrian Chadd int
1192ffcf962dSAdrian Chadd acpi_get_domain(device_t dev, device_t child, int *domain)
1193ffcf962dSAdrian Chadd {
11948d791e5aSJohn Baldwin 	int d;
1195ffcf962dSAdrian Chadd 
11968d791e5aSJohn Baldwin 	d = acpi_parse_pxm(child);
11978d791e5aSJohn Baldwin 	if (d >= 0) {
11988d791e5aSJohn Baldwin 		*domain = d;
11998a08b7d3SJohn Baldwin 		return (0);
12008d791e5aSJohn Baldwin 	}
12018d791e5aSJohn Baldwin 	if (d == -1)
12028d791e5aSJohn Baldwin 		return (ENOENT);
12035d18c60aSAdrian Chadd 
1204ffcf962dSAdrian Chadd 	/* No _PXM node; go up a level */
1205ffcf962dSAdrian Chadd 	return (bus_generic_get_domain(dev, child, domain));
1206ffcf962dSAdrian Chadd }
1207ffcf962dSAdrian Chadd 
1208ffcf962dSAdrian Chadd /*
1209adad4744SNate Lawson  * Pre-allocate/manage all memory and IO resources.  Since rman can't handle
1210adad4744SNate Lawson  * duplicates, we merge any in the sysresource attach routine.
1211adad4744SNate Lawson  */
1212adad4744SNate Lawson static int
1213adad4744SNate Lawson acpi_sysres_alloc(device_t dev)
1214adad4744SNate Lawson {
1215adad4744SNate Lawson     struct resource *res;
1216adad4744SNate Lawson     struct resource_list *rl;
1217adad4744SNate Lawson     struct resource_list_entry *rle;
1218adad4744SNate Lawson     struct rman *rm;
1219da72d149SNate Lawson     device_t *children;
1220da72d149SNate Lawson     int child_count, i;
1221da72d149SNate Lawson 
1222da72d149SNate Lawson     /*
1223da72d149SNate Lawson      * Probe/attach any sysresource devices.  This would be unnecessary if we
1224da72d149SNate Lawson      * had multi-pass probe/attach.
1225da72d149SNate Lawson      */
1226da72d149SNate Lawson     if (device_get_children(dev, &children, &child_count) != 0)
1227da72d149SNate Lawson 	return (ENXIO);
1228da72d149SNate Lawson     for (i = 0; i < child_count; i++) {
12295efca36fSTakanori Watanabe 	if (ACPI_ID_PROBE(dev, children[i], sysres_ids, NULL) <= 0)
1230da72d149SNate Lawson 	    device_probe_and_attach(children[i]);
1231da72d149SNate Lawson     }
1232da72d149SNate Lawson     free(children, M_TEMP);
1233adad4744SNate Lawson 
1234adad4744SNate Lawson     rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
1235be1bf4d2SPoul-Henning Kamp     STAILQ_FOREACH(rle, rl, link) {
1236adad4744SNate Lawson 	if (rle->res != NULL) {
1237da1b038aSJustin Hibbits 	    device_printf(dev, "duplicate resource for %jx\n", rle->start);
1238adad4744SNate Lawson 	    continue;
1239adad4744SNate Lawson 	}
1240adad4744SNate Lawson 
1241adad4744SNate Lawson 	/* Only memory and IO resources are valid here. */
1242adad4744SNate Lawson 	switch (rle->type) {
1243adad4744SNate Lawson 	case SYS_RES_IOPORT:
1244adad4744SNate Lawson 	    rm = &acpi_rman_io;
1245adad4744SNate Lawson 	    break;
1246adad4744SNate Lawson 	case SYS_RES_MEMORY:
1247adad4744SNate Lawson 	    rm = &acpi_rman_mem;
1248adad4744SNate Lawson 	    break;
1249adad4744SNate Lawson 	default:
1250adad4744SNate Lawson 	    continue;
1251adad4744SNate Lawson 	}
1252adad4744SNate Lawson 
1253adad4744SNate Lawson 	/* Pre-allocate resource and add to our rman pool. */
1254adad4744SNate Lawson 	res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, rle->type,
1255adad4744SNate Lawson 	    &rle->rid, rle->start, rle->start + rle->count - 1, rle->count, 0);
1256adad4744SNate Lawson 	if (res != NULL) {
1257adad4744SNate Lawson 	    rman_manage_region(rm, rman_get_start(res), rman_get_end(res));
1258adad4744SNate Lawson 	    rle->res = res;
125944947d3aSJohn Baldwin 	} else if (bootverbose)
1260da1b038aSJustin Hibbits 	    device_printf(dev, "reservation of %jx, %jx (%d) failed\n",
1261adad4744SNate Lawson 		rle->start, rle->count, rle->type);
1262adad4744SNate Lawson     }
1263adad4744SNate Lawson     return (0);
1264adad4744SNate Lawson }
1265adad4744SNate Lawson 
1266ea233199SJohn Baldwin /*
1267ea233199SJohn Baldwin  * Reserve declared resources for devices found during attach once system
1268ea233199SJohn Baldwin  * resources have been allocated.
1269ea233199SJohn Baldwin  */
1270ea233199SJohn Baldwin static void
1271ea233199SJohn Baldwin acpi_reserve_resources(device_t dev)
1272ea233199SJohn Baldwin {
1273ea233199SJohn Baldwin     struct resource_list_entry *rle;
1274ea233199SJohn Baldwin     struct resource_list *rl;
1275ea233199SJohn Baldwin     struct acpi_device *ad;
1276ea233199SJohn Baldwin     struct acpi_softc *sc;
1277ea233199SJohn Baldwin     device_t *children;
1278ea233199SJohn Baldwin     int child_count, i;
1279ea233199SJohn Baldwin 
1280ea233199SJohn Baldwin     sc = device_get_softc(dev);
1281ea233199SJohn Baldwin     if (device_get_children(dev, &children, &child_count) != 0)
1282ea233199SJohn Baldwin 	return;
1283ea233199SJohn Baldwin     for (i = 0; i < child_count; i++) {
1284ea233199SJohn Baldwin 	ad = device_get_ivars(children[i]);
1285ea233199SJohn Baldwin 	rl = &ad->ad_rl;
1286ea233199SJohn Baldwin 
1287ea233199SJohn Baldwin 	/* Don't reserve system resources. */
12885efca36fSTakanori Watanabe 	if (ACPI_ID_PROBE(dev, children[i], sysres_ids, NULL) <= 0)
1289ea233199SJohn Baldwin 	    continue;
1290ea233199SJohn Baldwin 
1291ea233199SJohn Baldwin 	STAILQ_FOREACH(rle, rl, link) {
1292ea233199SJohn Baldwin 	    /*
1293ea233199SJohn Baldwin 	     * Don't reserve IRQ resources.  There are many sticky things
1294ea233199SJohn Baldwin 	     * to get right otherwise (e.g. IRQs for psm, atkbd, and HPET
1295ea233199SJohn Baldwin 	     * when using legacy routing).
1296ea233199SJohn Baldwin 	     */
1297ea233199SJohn Baldwin 	    if (rle->type == SYS_RES_IRQ)
1298ea233199SJohn Baldwin 		continue;
1299ea233199SJohn Baldwin 
1300ea233199SJohn Baldwin 	    /*
13010d81cf12SJohn Baldwin 	     * Don't reserve the resource if it is already allocated.
13020d81cf12SJohn Baldwin 	     * The acpi_ec(4) driver can allocate its resources early
13030d81cf12SJohn Baldwin 	     * if ECDT is present.
13040d81cf12SJohn Baldwin 	     */
13050d81cf12SJohn Baldwin 	    if (rle->res != NULL)
13060d81cf12SJohn Baldwin 		continue;
13070d81cf12SJohn Baldwin 
13080d81cf12SJohn Baldwin 	    /*
1309ea233199SJohn Baldwin 	     * Try to reserve the resource from our parent.  If this
1310ea233199SJohn Baldwin 	     * fails because the resource is a system resource, just
1311ea233199SJohn Baldwin 	     * let it be.  The resource range is already reserved so
1312ea233199SJohn Baldwin 	     * that other devices will not use it.  If the driver
1313ea233199SJohn Baldwin 	     * needs to allocate the resource, then
1314ea233199SJohn Baldwin 	     * acpi_alloc_resource() will sub-alloc from the system
1315ea233199SJohn Baldwin 	     * resource.
1316ea233199SJohn Baldwin 	     */
1317ea233199SJohn Baldwin 	    resource_list_reserve(rl, dev, children[i], rle->type, &rle->rid,
1318ea233199SJohn Baldwin 		rle->start, rle->end, rle->count, 0);
1319ea233199SJohn Baldwin 	}
1320ea233199SJohn Baldwin     }
1321ea233199SJohn Baldwin     free(children, M_TEMP);
1322ea233199SJohn Baldwin     sc->acpi_resources_reserved = 1;
1323ea233199SJohn Baldwin }
1324ea233199SJohn Baldwin 
1325ea233199SJohn Baldwin static int
1326ea233199SJohn Baldwin acpi_set_resource(device_t dev, device_t child, int type, int rid,
13272dd1bdf1SJustin Hibbits     rman_res_t start, rman_res_t count)
1328ea233199SJohn Baldwin {
1329ea233199SJohn Baldwin     struct acpi_softc *sc = device_get_softc(dev);
1330ea233199SJohn Baldwin     struct acpi_device *ad = device_get_ivars(child);
1331ea233199SJohn Baldwin     struct resource_list *rl = &ad->ad_rl;
13327e3343bfSJohn Baldwin     ACPI_DEVICE_INFO *devinfo;
13332dd1bdf1SJustin Hibbits     rman_res_t end;
1334185c34f7SJayachandran C.     int allow;
1335ea233199SJohn Baldwin 
1336ea233199SJohn Baldwin     /* Ignore IRQ resources for PCI link devices. */
13375efca36fSTakanori Watanabe     if (type == SYS_RES_IRQ &&
13385efca36fSTakanori Watanabe 	ACPI_ID_PROBE(dev, child, pcilink_ids, NULL) <= 0)
1339ea233199SJohn Baldwin 	return (0);
1340ea233199SJohn Baldwin 
13417e3343bfSJohn Baldwin     /*
1342d2dc06caSJohn Baldwin      * Ignore most resources for PCI root bridges.  Some BIOSes
13437e3343bfSJohn Baldwin      * incorrectly enumerate the memory ranges they decode as plain
1344d2dc06caSJohn Baldwin      * memory resources instead of as ResourceProducer ranges.  Other
1345d2dc06caSJohn Baldwin      * BIOSes incorrectly list system resource entries for I/O ranges
1346d2dc06caSJohn Baldwin      * under the PCI bridge.  Do allow the one known-correct case on
1347d2dc06caSJohn Baldwin      * x86 of a PCI bridge claiming the I/O ports used for PCI config
1348d2dc06caSJohn Baldwin      * access.
13497e3343bfSJohn Baldwin      */
1350d2dc06caSJohn Baldwin     if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) {
13517e3343bfSJohn Baldwin 	if (ACPI_SUCCESS(AcpiGetObjectInfo(ad->ad_handle, &devinfo))) {
13527e3343bfSJohn Baldwin 	    if ((devinfo->Flags & ACPI_PCI_ROOT_BRIDGE) != 0) {
1353185c34f7SJayachandran C. #if defined(__i386__) || defined(__amd64__)
1354185c34f7SJayachandran C. 		allow = (type == SYS_RES_IOPORT && start == CONF1_ADDR_PORT);
1355185c34f7SJayachandran C. #else
1356185c34f7SJayachandran C. 		allow = 0;
1357185c34f7SJayachandran C. #endif
1358185c34f7SJayachandran C. 		if (!allow) {
13597e3343bfSJohn Baldwin 		    AcpiOsFree(devinfo);
13607e3343bfSJohn Baldwin 		    return (0);
13617e3343bfSJohn Baldwin 		}
1362d2dc06caSJohn Baldwin 	    }
13637e3343bfSJohn Baldwin 	    AcpiOsFree(devinfo);
13647e3343bfSJohn Baldwin 	}
13657e3343bfSJohn Baldwin     }
13667e3343bfSJohn Baldwin 
1367d4d6ad3fSJayachandran C. #ifdef INTRNG
1368d4d6ad3fSJayachandran C.     /* map with default for now */
1369d4d6ad3fSJayachandran C.     if (type == SYS_RES_IRQ)
1370d4d6ad3fSJayachandran C. 	start = (rman_res_t)acpi_map_intr(child, (u_int)start,
1371d4d6ad3fSJayachandran C. 			acpi_get_handle(child));
1372d4d6ad3fSJayachandran C. #endif
1373d4d6ad3fSJayachandran C. 
1374ea233199SJohn Baldwin     /* If the resource is already allocated, fail. */
1375ea233199SJohn Baldwin     if (resource_list_busy(rl, type, rid))
1376ea233199SJohn Baldwin 	return (EBUSY);
1377ea233199SJohn Baldwin 
1378ea233199SJohn Baldwin     /* If the resource is already reserved, release it. */
1379ea233199SJohn Baldwin     if (resource_list_reserved(rl, type, rid))
1380ea233199SJohn Baldwin 	resource_list_unreserve(rl, dev, child, type, rid);
1381ea233199SJohn Baldwin 
1382ea233199SJohn Baldwin     /* Add the resource. */
1383ea233199SJohn Baldwin     end = (start + count - 1);
1384ea233199SJohn Baldwin     resource_list_add(rl, type, rid, start, end, count);
1385ea233199SJohn Baldwin 
1386ea233199SJohn Baldwin     /* Don't reserve resources until the system resources are allocated. */
1387ea233199SJohn Baldwin     if (!sc->acpi_resources_reserved)
1388ea233199SJohn Baldwin 	return (0);
1389ea233199SJohn Baldwin 
1390ea233199SJohn Baldwin     /* Don't reserve system resources. */
13915efca36fSTakanori Watanabe     if (ACPI_ID_PROBE(dev, child, sysres_ids, NULL) <= 0)
1392ea233199SJohn Baldwin 	return (0);
1393ea233199SJohn Baldwin 
1394ea233199SJohn Baldwin     /*
1395ea233199SJohn Baldwin      * Don't reserve IRQ resources.  There are many sticky things to
1396ea233199SJohn Baldwin      * get right otherwise (e.g. IRQs for psm, atkbd, and HPET when
1397ea233199SJohn Baldwin      * using legacy routing).
1398ea233199SJohn Baldwin      */
1399ea233199SJohn Baldwin     if (type == SYS_RES_IRQ)
1400ea233199SJohn Baldwin 	return (0);
1401ea233199SJohn Baldwin 
1402ea233199SJohn Baldwin     /*
14031fe39413SJohn Baldwin      * Don't reserve resources for CPU devices.  Some of these
14041fe39413SJohn Baldwin      * resources need to be allocated as shareable, but reservations
14051fe39413SJohn Baldwin      * are always non-shareable.
14061fe39413SJohn Baldwin      */
14071fe39413SJohn Baldwin     if (device_get_devclass(child) == devclass_find("cpu"))
14081fe39413SJohn Baldwin 	return (0);
14091fe39413SJohn Baldwin 
14101fe39413SJohn Baldwin     /*
1411ea233199SJohn Baldwin      * Reserve the resource.
1412ea233199SJohn Baldwin      *
1413ea233199SJohn Baldwin      * XXX: Ignores failure for now.  Failure here is probably a
1414ea233199SJohn Baldwin      * BIOS/firmware bug?
1415ea233199SJohn Baldwin      */
1416ea233199SJohn Baldwin     resource_list_reserve(rl, dev, child, type, &rid, start, end, count, 0);
1417ea233199SJohn Baldwin     return (0);
1418ea233199SJohn Baldwin }
1419ea233199SJohn Baldwin 
142015e32d5dSMike Smith static struct resource *
142115e32d5dSMike Smith acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
14222dd1bdf1SJustin Hibbits     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
142315e32d5dSMike Smith {
1424224c3776SAndrew Turner #ifndef INTRNG
142595957f62SJohn Baldwin     ACPI_RESOURCE ares;
1426224c3776SAndrew Turner #endif
1427ea233199SJohn Baldwin     struct acpi_device *ad;
142891233413SNate Lawson     struct resource_list_entry *rle;
1429ea233199SJohn Baldwin     struct resource_list *rl;
143091233413SNate Lawson     struct resource *res;
14317915adb5SJustin Hibbits     int isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
143215e2f34fSNate Lawson 
143391233413SNate Lawson     /*
1434ea233199SJohn Baldwin      * First attempt at allocating the resource.  For direct children,
1435ea233199SJohn Baldwin      * use resource_list_alloc() to handle reserved resources.  For
1436f6133e71SJohn Baldwin      * other devices, pass the request up to our parent.
143791233413SNate Lawson      */
1438ea233199SJohn Baldwin     if (bus == device_get_parent(child)) {
1439ea233199SJohn Baldwin 	ad = device_get_ivars(child);
1440ea233199SJohn Baldwin 	rl = &ad->ad_rl;
144191233413SNate Lawson 
1442397c30a8SJohn Baldwin 	/*
1443ea233199SJohn Baldwin 	 * Simulate the behavior of the ISA bus for direct children
1444ea233199SJohn Baldwin 	 * devices.  That is, if a non-default range is specified for
1445ea233199SJohn Baldwin 	 * a resource that doesn't exist, use bus_set_resource() to
1446ea233199SJohn Baldwin 	 * add the resource before allocating it.  Note that these
1447ea233199SJohn Baldwin 	 * resources will not be reserved.
1448397c30a8SJohn Baldwin 	 */
1449ea233199SJohn Baldwin 	if (!isdefault && resource_list_find(rl, type, *rid) == NULL)
1450ea233199SJohn Baldwin 		resource_list_add(rl, type, *rid, start, end, count);
1451ea233199SJohn Baldwin 	res = resource_list_alloc(rl, bus, child, type, rid, start, end, count,
1452ea233199SJohn Baldwin 	    flags);
1453224c3776SAndrew Turner #ifndef INTRNG
1454ea233199SJohn Baldwin 	if (res != NULL && type == SYS_RES_IRQ) {
145595957f62SJohn Baldwin 	    /*
145695957f62SJohn Baldwin 	     * Since bus_config_intr() takes immediate effect, we cannot
145795957f62SJohn Baldwin 	     * configure the interrupt associated with a device when we
145895957f62SJohn Baldwin 	     * parse the resources but have to defer it until a driver
145995957f62SJohn Baldwin 	     * actually allocates the interrupt via bus_alloc_resource().
146095957f62SJohn Baldwin 	     *
146195957f62SJohn Baldwin 	     * XXX: Should we handle the lookup failing?
146295957f62SJohn Baldwin 	     */
146395957f62SJohn Baldwin 	    if (ACPI_SUCCESS(acpi_lookup_irq_resource(child, *rid, res, &ares)))
146495957f62SJohn Baldwin 		acpi_config_intr(child, &ares);
146595957f62SJohn Baldwin 	}
1466224c3776SAndrew Turner #endif
146715e2f34fSNate Lawson 
1468ea233199SJohn Baldwin 	/*
1469ea233199SJohn Baldwin 	 * If this is an allocation of the "default" range for a given
1470ea233199SJohn Baldwin 	 * RID, fetch the exact bounds for this resource from the
1471ea233199SJohn Baldwin 	 * resource list entry to try to allocate the range from the
1472ea233199SJohn Baldwin 	 * system resource regions.
1473ea233199SJohn Baldwin 	 */
1474ea233199SJohn Baldwin 	if (res == NULL && isdefault) {
1475ea233199SJohn Baldwin 	    rle = resource_list_find(rl, type, *rid);
1476ea233199SJohn Baldwin 	    if (rle != NULL) {
1477ea233199SJohn Baldwin 		start = rle->start;
1478ea233199SJohn Baldwin 		end = rle->end;
1479ea233199SJohn Baldwin 		count = rle->count;
1480ea233199SJohn Baldwin 	    }
1481ea233199SJohn Baldwin 	}
1482ea233199SJohn Baldwin     } else
1483ea233199SJohn Baldwin 	res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid,
1484ea233199SJohn Baldwin 	    start, end, count, flags);
1485ea233199SJohn Baldwin 
1486ea233199SJohn Baldwin     /*
1487ea233199SJohn Baldwin      * If the first attempt failed and this is an allocation of a
1488ea233199SJohn Baldwin      * specific range, try to satisfy the request via a suballocation
14895d0d779bSJohn Baldwin      * from our system resource regions.
1490ea233199SJohn Baldwin      */
14915d0d779bSJohn Baldwin     if (res == NULL && start + count - 1 == end)
14925d0d779bSJohn Baldwin 	res = acpi_alloc_sysres(child, type, rid, start, end, count, flags);
14935d0d779bSJohn Baldwin     return (res);
14945d0d779bSJohn Baldwin }
14955d0d779bSJohn Baldwin 
14965d0d779bSJohn Baldwin /*
14975d0d779bSJohn Baldwin  * Attempt to allocate a specific resource range from the system
14985d0d779bSJohn Baldwin  * resource ranges.  Note that we only handle memory and I/O port
14995d0d779bSJohn Baldwin  * system resources.
15005d0d779bSJohn Baldwin  */
15015d0d779bSJohn Baldwin struct resource *
15022dd1bdf1SJustin Hibbits acpi_alloc_sysres(device_t child, int type, int *rid, rman_res_t start,
15032dd1bdf1SJustin Hibbits     rman_res_t end, rman_res_t count, u_int flags)
15045d0d779bSJohn Baldwin {
15055d0d779bSJohn Baldwin     struct rman *rm;
15065d0d779bSJohn Baldwin     struct resource *res;
15075d0d779bSJohn Baldwin 
1508ea233199SJohn Baldwin     switch (type) {
1509ea233199SJohn Baldwin     case SYS_RES_IOPORT:
1510ea233199SJohn Baldwin 	rm = &acpi_rman_io;
1511ea233199SJohn Baldwin 	break;
1512ea233199SJohn Baldwin     case SYS_RES_MEMORY:
1513ea233199SJohn Baldwin 	rm = &acpi_rman_mem;
1514ea233199SJohn Baldwin 	break;
1515ea233199SJohn Baldwin     default:
1516ea233199SJohn Baldwin 	return (NULL);
1517ea233199SJohn Baldwin     }
1518ea233199SJohn Baldwin 
15195d0d779bSJohn Baldwin     KASSERT(start + count - 1 == end, ("wildcard resource range"));
1520ea233199SJohn Baldwin     res = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
1521ea233199SJohn Baldwin 	child);
1522ea233199SJohn Baldwin     if (res == NULL)
1523ea233199SJohn Baldwin 	return (NULL);
1524ea233199SJohn Baldwin 
1525ea233199SJohn Baldwin     rman_set_rid(res, *rid);
1526ea233199SJohn Baldwin 
1527ea233199SJohn Baldwin     /* If requested, activate the resource using the parent's method. */
1528ea233199SJohn Baldwin     if (flags & RF_ACTIVE)
1529ea233199SJohn Baldwin 	if (bus_activate_resource(child, type, *rid, res) != 0) {
1530ea233199SJohn Baldwin 	    rman_release_resource(res);
1531ea233199SJohn Baldwin 	    return (NULL);
1532ea233199SJohn Baldwin 	}
1533ea233199SJohn Baldwin 
153491233413SNate Lawson     return (res);
153515e32d5dSMike Smith }
153615e32d5dSMike Smith 
153715e32d5dSMike Smith static int
1538049dc0d1SJohn Baldwin acpi_is_resource_managed(int type, struct resource *r)
153915e32d5dSMike Smith {
154015e32d5dSMike Smith 
1541397c30a8SJohn Baldwin     /* We only handle memory and IO resources through rman. */
1542397c30a8SJohn Baldwin     switch (type) {
1543397c30a8SJohn Baldwin     case SYS_RES_IOPORT:
1544049dc0d1SJohn Baldwin 	return (rman_is_region_manager(r, &acpi_rman_io));
1545397c30a8SJohn Baldwin     case SYS_RES_MEMORY:
1546049dc0d1SJohn Baldwin 	return (rman_is_region_manager(r, &acpi_rman_mem));
1547397c30a8SJohn Baldwin     }
1548049dc0d1SJohn Baldwin     return (0);
1549049dc0d1SJohn Baldwin }
1550049dc0d1SJohn Baldwin 
1551049dc0d1SJohn Baldwin static int
1552049dc0d1SJohn Baldwin acpi_adjust_resource(device_t bus, device_t child, int type, struct resource *r,
15532dd1bdf1SJustin Hibbits     rman_res_t start, rman_res_t end)
1554049dc0d1SJohn Baldwin {
1555049dc0d1SJohn Baldwin 
1556049dc0d1SJohn Baldwin     if (acpi_is_resource_managed(type, r))
1557049dc0d1SJohn Baldwin 	return (rman_adjust_resource(r, start, end));
1558049dc0d1SJohn Baldwin     return (bus_generic_adjust_resource(bus, child, type, r, start, end));
1559049dc0d1SJohn Baldwin }
1560049dc0d1SJohn Baldwin 
1561049dc0d1SJohn Baldwin static int
1562049dc0d1SJohn Baldwin acpi_release_resource(device_t bus, device_t child, int type, int rid,
1563049dc0d1SJohn Baldwin     struct resource *r)
1564049dc0d1SJohn Baldwin {
1565049dc0d1SJohn Baldwin     int ret;
1566397c30a8SJohn Baldwin 
156791233413SNate Lawson     /*
1568397c30a8SJohn Baldwin      * If this resource belongs to one of our internal managers,
1569ea233199SJohn Baldwin      * deactivate it and release it to the local pool.
157091233413SNate Lawson      */
1571049dc0d1SJohn Baldwin     if (acpi_is_resource_managed(type, r)) {
157291233413SNate Lawson 	if (rman_get_flags(r) & RF_ACTIVE) {
157391233413SNate Lawson 	    ret = bus_deactivate_resource(child, type, rid, r);
157491233413SNate Lawson 	    if (ret != 0)
157591233413SNate Lawson 		return (ret);
157615e32d5dSMike Smith 	}
1577ea233199SJohn Baldwin 	return (rman_release_resource(r));
1578ea233199SJohn Baldwin     }
1579ea233199SJohn Baldwin 
1580ea233199SJohn Baldwin     return (bus_generic_rl_release_resource(bus, child, type, rid, r));
1581ea233199SJohn Baldwin }
158215e32d5dSMike Smith 
15838b28b622SNate Lawson static void
15848b28b622SNate Lawson acpi_delete_resource(device_t bus, device_t child, int type, int rid)
15858b28b622SNate Lawson {
15868b28b622SNate Lawson     struct resource_list *rl;
15878b28b622SNate Lawson 
15888b28b622SNate Lawson     rl = acpi_get_rlist(bus, child);
1589ea233199SJohn Baldwin     if (resource_list_busy(rl, type, rid)) {
1590ea233199SJohn Baldwin 	device_printf(bus, "delete_resource: Resource still owned by child"
1591ea233199SJohn Baldwin 	    " (type=%d, rid=%d)\n", type, rid);
1592ea233199SJohn Baldwin 	return;
1593ea233199SJohn Baldwin     }
1594ea233199SJohn Baldwin     resource_list_unreserve(rl, bus, child, type, rid);
15958b28b622SNate Lawson     resource_list_delete(rl, type, rid);
15968b28b622SNate Lawson }
15978b28b622SNate Lawson 
1598dc750869SNate Lawson /* Allocate an IO port or memory resource, given its GAS. */
1599e1c4bf3fSNate Lawson int
1600e1c4bf3fSNate Lawson acpi_bus_alloc_gas(device_t dev, int *type, int *rid, ACPI_GENERIC_ADDRESS *gas,
1601907b6777SNate Lawson     struct resource **res, u_int flags)
1602dc750869SNate Lawson {
1603e1c4bf3fSNate Lawson     int error, res_type;
1604dc750869SNate Lawson 
1605e1c4bf3fSNate Lawson     error = ENOMEM;
16068f118e25SNate Lawson     if (type == NULL || rid == NULL || gas == NULL || res == NULL)
1607e1c4bf3fSNate Lawson 	return (EINVAL);
1608dc750869SNate Lawson 
16098f118e25SNate Lawson     /* We only support memory and IO spaces. */
16102be4e471SJung-uk Kim     switch (gas->SpaceId) {
1611dc750869SNate Lawson     case ACPI_ADR_SPACE_SYSTEM_MEMORY:
1612e1c4bf3fSNate Lawson 	res_type = SYS_RES_MEMORY;
1613dc750869SNate Lawson 	break;
1614dc750869SNate Lawson     case ACPI_ADR_SPACE_SYSTEM_IO:
1615e1c4bf3fSNate Lawson 	res_type = SYS_RES_IOPORT;
1616dc750869SNate Lawson 	break;
1617dc750869SNate Lawson     default:
1618e1c4bf3fSNate Lawson 	return (EOPNOTSUPP);
1619dc750869SNate Lawson     }
1620dc750869SNate Lawson 
16212fe912dfSNate Lawson     /*
1622f45fc848SNate Lawson      * If the register width is less than 8, assume the BIOS author means
1623f45fc848SNate Lawson      * it is a bit field and just allocate a byte.
16242fe912dfSNate Lawson      */
16252be4e471SJung-uk Kim     if (gas->BitWidth && gas->BitWidth < 8)
16262be4e471SJung-uk Kim 	gas->BitWidth = 8;
16272fe912dfSNate Lawson 
16288f118e25SNate Lawson     /* Validate the address after we're sure we support the space. */
16292be4e471SJung-uk Kim     if (gas->Address == 0 || gas->BitWidth == 0)
16308f118e25SNate Lawson 	return (EINVAL);
16318f118e25SNate Lawson 
1632e1c4bf3fSNate Lawson     bus_set_resource(dev, res_type, *rid, gas->Address,
16332be4e471SJung-uk Kim 	gas->BitWidth / 8);
1634907b6777SNate Lawson     *res = bus_alloc_resource_any(dev, res_type, rid, RF_ACTIVE | flags);
1635e1c4bf3fSNate Lawson     if (*res != NULL) {
1636e1c4bf3fSNate Lawson 	*type = res_type;
1637e1c4bf3fSNate Lawson 	error = 0;
1638ca2c69c8SNate Lawson     } else
1639ca2c69c8SNate Lawson 	bus_delete_resource(dev, res_type, *rid);
1640ca2c69c8SNate Lawson 
1641e1c4bf3fSNate Lawson     return (error);
1642dc750869SNate Lawson }
1643dc750869SNate Lawson 
1644c796e27bSNate Lawson /* Probe _HID and _CID for compatible ISA PNP ids. */
16451e4925e8SNate Lawson static uint32_t
164632d18aa5SMike Smith acpi_isa_get_logicalid(device_t dev)
1647bc0f2195SMike Smith {
16481e4925e8SNate Lawson     ACPI_DEVICE_INFO	*devinfo;
1649bc0f2195SMike Smith     ACPI_HANDLE		h;
165092488a57SJung-uk Kim     uint32_t		pnpid;
165132d18aa5SMike Smith 
1652b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
165332d18aa5SMike Smith 
16546fca9360SNate Lawson     /* Fetch and validate the HID. */
165592488a57SJung-uk Kim     if ((h = acpi_get_handle(dev)) == NULL ||
165692488a57SJung-uk Kim 	ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo)))
165792488a57SJung-uk Kim 	return_VALUE (0);
165832d18aa5SMike Smith 
165992488a57SJung-uk Kim     pnpid = (devinfo->Valid & ACPI_VALID_HID) != 0 &&
166092488a57SJung-uk Kim 	devinfo->HardwareId.Length >= ACPI_EISAID_STRING_SIZE ?
166192488a57SJung-uk Kim 	PNP_EISAID(devinfo->HardwareId.String) : 0;
166292488a57SJung-uk Kim     AcpiOsFree(devinfo);
1663be2b1797SNate Lawson 
166432d18aa5SMike Smith     return_VALUE (pnpid);
166532d18aa5SMike Smith }
166632d18aa5SMike Smith 
16671e4925e8SNate Lawson static int
16681e4925e8SNate Lawson acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count)
1669b2566207STakanori Watanabe {
16701e4925e8SNate Lawson     ACPI_DEVICE_INFO	*devinfo;
16718ef1a331SJung-uk Kim     ACPI_PNP_DEVICE_ID	*ids;
1672b2566207STakanori Watanabe     ACPI_HANDLE		h;
16731e4925e8SNate Lawson     uint32_t		*pnpid;
167492488a57SJung-uk Kim     int			i, valid;
1675b2566207STakanori Watanabe 
1676b2566207STakanori Watanabe     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
1677b2566207STakanori Watanabe 
16781e4925e8SNate Lawson     pnpid = cids;
1679bd189fe7SNate Lawson 
16801e4925e8SNate Lawson     /* Fetch and validate the CID */
168192488a57SJung-uk Kim     if ((h = acpi_get_handle(dev)) == NULL ||
168292488a57SJung-uk Kim 	ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo)))
168392488a57SJung-uk Kim 	return_VALUE (0);
1684b2566207STakanori Watanabe 
168592488a57SJung-uk Kim     if ((devinfo->Valid & ACPI_VALID_CID) == 0) {
168692488a57SJung-uk Kim 	AcpiOsFree(devinfo);
168792488a57SJung-uk Kim 	return_VALUE (0);
1688b2566207STakanori Watanabe     }
1689b2566207STakanori Watanabe 
169092488a57SJung-uk Kim     if (devinfo->CompatibleIdList.Count < count)
169192488a57SJung-uk Kim 	count = devinfo->CompatibleIdList.Count;
169292488a57SJung-uk Kim     ids = devinfo->CompatibleIdList.Ids;
169392488a57SJung-uk Kim     for (i = 0, valid = 0; i < count; i++)
169492488a57SJung-uk Kim 	if (ids[i].Length >= ACPI_EISAID_STRING_SIZE &&
169592488a57SJung-uk Kim 	    strncmp(ids[i].String, "PNP", 3) == 0) {
169692488a57SJung-uk Kim 	    *pnpid++ = PNP_EISAID(ids[i].String);
169792488a57SJung-uk Kim 	    valid++;
169892488a57SJung-uk Kim 	}
169992488a57SJung-uk Kim     AcpiOsFree(devinfo);
170092488a57SJung-uk Kim 
17011e4925e8SNate Lawson     return_VALUE (valid);
17021e4925e8SNate Lawson }
1703b2566207STakanori Watanabe 
17045efca36fSTakanori Watanabe static int
17055efca36fSTakanori Watanabe acpi_device_id_probe(device_t bus, device_t dev, char **ids, char **match)
1706ce619b2eSNate Lawson {
1707ce619b2eSNate Lawson     ACPI_HANDLE h;
170892488a57SJung-uk Kim     ACPI_OBJECT_TYPE t;
17095efca36fSTakanori Watanabe     int rv;
1710ce619b2eSNate Lawson     int i;
1711ce619b2eSNate Lawson 
1712ce619b2eSNate Lawson     h = acpi_get_handle(dev);
171392488a57SJung-uk Kim     if (ids == NULL || h == NULL)
17145efca36fSTakanori Watanabe 	return (ENXIO);
171592488a57SJung-uk Kim     t = acpi_get_type(dev);
171692488a57SJung-uk Kim     if (t != ACPI_TYPE_DEVICE && t != ACPI_TYPE_PROCESSOR)
17175efca36fSTakanori Watanabe 	return (ENXIO);
1718ce619b2eSNate Lawson 
1719ce619b2eSNate Lawson     /* Try to match one of the array of IDs with a HID or CID. */
1720ce619b2eSNate Lawson     for (i = 0; ids[i] != NULL; i++) {
17215efca36fSTakanori Watanabe 	rv = acpi_MatchHid(h, ids[i]);
17225efca36fSTakanori Watanabe 	if (rv == ACPI_MATCHHID_NOMATCH)
17235efca36fSTakanori Watanabe 	    continue;
17245efca36fSTakanori Watanabe 
17255efca36fSTakanori Watanabe 	if (match != NULL) {
17265efca36fSTakanori Watanabe 	    *match = ids[i];
1727ce619b2eSNate Lawson 	}
17285efca36fSTakanori Watanabe 	return ((rv == ACPI_MATCHHID_HID)?
17295efca36fSTakanori Watanabe 		    BUS_PROBE_DEFAULT : BUS_PROBE_LOW_PRIORITY);
17305efca36fSTakanori Watanabe     }
17315efca36fSTakanori Watanabe     return (ENXIO);
1732ce619b2eSNate Lawson }
1733ce619b2eSNate Lawson 
1734ce619b2eSNate Lawson static ACPI_STATUS
1735ce619b2eSNate Lawson acpi_device_eval_obj(device_t bus, device_t dev, ACPI_STRING pathname,
1736ce619b2eSNate Lawson     ACPI_OBJECT_LIST *parameters, ACPI_BUFFER *ret)
1737ce619b2eSNate Lawson {
1738ce619b2eSNate Lawson     ACPI_HANDLE h;
1739ce619b2eSNate Lawson 
1740df8d2a32SNate Lawson     if (dev == NULL)
1741df8d2a32SNate Lawson 	h = ACPI_ROOT_OBJECT;
1742df8d2a32SNate Lawson     else if ((h = acpi_get_handle(dev)) == NULL)
1743ce619b2eSNate Lawson 	return (AE_BAD_PARAMETER);
1744ce619b2eSNate Lawson     return (AcpiEvaluateObject(h, pathname, parameters, ret));
1745ce619b2eSNate Lawson }
1746ce619b2eSNate Lawson 
1747b91fc6c4SBartlomiej Grzesik static ACPI_STATUS
1748b91fc6c4SBartlomiej Grzesik acpi_device_get_prop(device_t bus, device_t dev, ACPI_STRING propname,
1749b91fc6c4SBartlomiej Grzesik     const ACPI_OBJECT **value)
1750b91fc6c4SBartlomiej Grzesik {
1751b91fc6c4SBartlomiej Grzesik 	const ACPI_OBJECT *pkg, *name, *val;
1752b91fc6c4SBartlomiej Grzesik 	struct acpi_device *ad;
1753b91fc6c4SBartlomiej Grzesik 	ACPI_STATUS status;
1754b91fc6c4SBartlomiej Grzesik 	int i;
1755b91fc6c4SBartlomiej Grzesik 
1756b91fc6c4SBartlomiej Grzesik 	ad = device_get_ivars(dev);
1757b91fc6c4SBartlomiej Grzesik 
1758b91fc6c4SBartlomiej Grzesik 	if (ad == NULL || propname == NULL)
1759b91fc6c4SBartlomiej Grzesik 		return (AE_BAD_PARAMETER);
1760b91fc6c4SBartlomiej Grzesik 	if (ad->dsd_pkg == NULL) {
1761b91fc6c4SBartlomiej Grzesik 		if (ad->dsd.Pointer == NULL) {
1762b91fc6c4SBartlomiej Grzesik 			status = acpi_find_dsd(bus, dev);
1763b91fc6c4SBartlomiej Grzesik 			if (ACPI_FAILURE(status))
1764b91fc6c4SBartlomiej Grzesik 				return (status);
1765b91fc6c4SBartlomiej Grzesik 		} else {
1766b91fc6c4SBartlomiej Grzesik 			return (AE_NOT_FOUND);
1767b91fc6c4SBartlomiej Grzesik 		}
1768b91fc6c4SBartlomiej Grzesik 	}
1769b91fc6c4SBartlomiej Grzesik 
1770b91fc6c4SBartlomiej Grzesik 	for (i = 0; i < ad->dsd_pkg->Package.Count; i ++) {
1771b91fc6c4SBartlomiej Grzesik 		pkg = &ad->dsd_pkg->Package.Elements[i];
1772b91fc6c4SBartlomiej Grzesik 		if (pkg->Type != ACPI_TYPE_PACKAGE || pkg->Package.Count != 2)
1773b91fc6c4SBartlomiej Grzesik 			continue;
1774b91fc6c4SBartlomiej Grzesik 
1775b91fc6c4SBartlomiej Grzesik 		name = &pkg->Package.Elements[0];
1776b91fc6c4SBartlomiej Grzesik 		val = &pkg->Package.Elements[1];
1777b91fc6c4SBartlomiej Grzesik 		if (name->Type != ACPI_TYPE_STRING)
1778b91fc6c4SBartlomiej Grzesik 			continue;
1779b91fc6c4SBartlomiej Grzesik 		if (strncmp(propname, name->String.Pointer, name->String.Length) == 0) {
1780b91fc6c4SBartlomiej Grzesik 			if (value != NULL)
1781b91fc6c4SBartlomiej Grzesik 				*value = val;
1782b91fc6c4SBartlomiej Grzesik 
1783b91fc6c4SBartlomiej Grzesik 			return (AE_OK);
1784b91fc6c4SBartlomiej Grzesik 		}
1785b91fc6c4SBartlomiej Grzesik 	}
1786b91fc6c4SBartlomiej Grzesik 
1787b91fc6c4SBartlomiej Grzesik 	return (AE_NOT_FOUND);
1788b91fc6c4SBartlomiej Grzesik }
1789b91fc6c4SBartlomiej Grzesik 
1790b91fc6c4SBartlomiej Grzesik static ACPI_STATUS
1791b91fc6c4SBartlomiej Grzesik acpi_find_dsd(device_t bus, device_t dev)
1792b91fc6c4SBartlomiej Grzesik {
1793b91fc6c4SBartlomiej Grzesik 	const ACPI_OBJECT *dsd, *guid, *pkg;
1794b91fc6c4SBartlomiej Grzesik 	struct acpi_device *ad;
1795b91fc6c4SBartlomiej Grzesik 	ACPI_STATUS status;
1796b91fc6c4SBartlomiej Grzesik 
1797b91fc6c4SBartlomiej Grzesik 	ad = device_get_ivars(dev);
1798b91fc6c4SBartlomiej Grzesik 	ad->dsd.Length = ACPI_ALLOCATE_BUFFER;
1799b91fc6c4SBartlomiej Grzesik 	ad->dsd.Pointer = NULL;
1800b91fc6c4SBartlomiej Grzesik 	ad->dsd_pkg = NULL;
1801b91fc6c4SBartlomiej Grzesik 
1802b91fc6c4SBartlomiej Grzesik 	status = ACPI_EVALUATE_OBJECT(bus, dev, "_DSD", NULL, &ad->dsd);
1803b91fc6c4SBartlomiej Grzesik 	if (ACPI_FAILURE(status))
1804b91fc6c4SBartlomiej Grzesik 		return (status);
1805b91fc6c4SBartlomiej Grzesik 
1806b91fc6c4SBartlomiej Grzesik 	dsd = ad->dsd.Pointer;
1807b91fc6c4SBartlomiej Grzesik 	guid = &dsd->Package.Elements[0];
1808b91fc6c4SBartlomiej Grzesik 	pkg = &dsd->Package.Elements[1];
1809b91fc6c4SBartlomiej Grzesik 
1810b91fc6c4SBartlomiej Grzesik 	if (guid->Type != ACPI_TYPE_BUFFER || pkg->Type != ACPI_TYPE_PACKAGE ||
1811b91fc6c4SBartlomiej Grzesik 		guid->Buffer.Length != sizeof(acpi_dsd_uuid))
1812b91fc6c4SBartlomiej Grzesik 		return (AE_NOT_FOUND);
1813b91fc6c4SBartlomiej Grzesik 	if (memcmp(guid->Buffer.Pointer, &acpi_dsd_uuid,
1814b91fc6c4SBartlomiej Grzesik 		sizeof(acpi_dsd_uuid)) == 0) {
1815b91fc6c4SBartlomiej Grzesik 
1816b91fc6c4SBartlomiej Grzesik 		ad->dsd_pkg = pkg;
1817b91fc6c4SBartlomiej Grzesik 		return (AE_OK);
1818b91fc6c4SBartlomiej Grzesik 	}
1819b91fc6c4SBartlomiej Grzesik 
1820b91fc6c4SBartlomiej Grzesik 	return (AE_NOT_FOUND);
1821b91fc6c4SBartlomiej Grzesik }
1822b91fc6c4SBartlomiej Grzesik 
1823*3f9a00e3SBartlomiej Grzesik static ssize_t
1824*3f9a00e3SBartlomiej Grzesik acpi_bus_get_prop(device_t bus, device_t child, const char *propname,
1825*3f9a00e3SBartlomiej Grzesik     void *propvalue, size_t size)
1826*3f9a00e3SBartlomiej Grzesik {
1827*3f9a00e3SBartlomiej Grzesik 	ACPI_STATUS status;
1828*3f9a00e3SBartlomiej Grzesik 	const ACPI_OBJECT *obj;
1829*3f9a00e3SBartlomiej Grzesik 
1830*3f9a00e3SBartlomiej Grzesik 	status = acpi_device_get_prop(bus, child, __DECONST(char *, propname),
1831*3f9a00e3SBartlomiej Grzesik 		&obj);
1832*3f9a00e3SBartlomiej Grzesik 	if (ACPI_FAILURE(status))
1833*3f9a00e3SBartlomiej Grzesik 		return (-1);
1834*3f9a00e3SBartlomiej Grzesik 
1835*3f9a00e3SBartlomiej Grzesik 	switch (obj->Type) {
1836*3f9a00e3SBartlomiej Grzesik 	case ACPI_TYPE_INTEGER:
1837*3f9a00e3SBartlomiej Grzesik 		if (propvalue != NULL && size >= sizeof(uint64_t))
1838*3f9a00e3SBartlomiej Grzesik 			*((uint64_t *) propvalue) = obj->Integer.Value;
1839*3f9a00e3SBartlomiej Grzesik 		return (sizeof(uint64_t));
1840*3f9a00e3SBartlomiej Grzesik 
1841*3f9a00e3SBartlomiej Grzesik 	case ACPI_TYPE_STRING:
1842*3f9a00e3SBartlomiej Grzesik 		if (propvalue != NULL && size > 0)
1843*3f9a00e3SBartlomiej Grzesik 			memcpy(propvalue, obj->String.Pointer,
1844*3f9a00e3SBartlomiej Grzesik 			    MIN(size, obj->String.Length));
1845*3f9a00e3SBartlomiej Grzesik 		return (obj->String.Length);
1846*3f9a00e3SBartlomiej Grzesik 
1847*3f9a00e3SBartlomiej Grzesik 	case ACPI_TYPE_BUFFER:
1848*3f9a00e3SBartlomiej Grzesik 		if (propvalue != NULL && size > 0)
1849*3f9a00e3SBartlomiej Grzesik 			memcpy(propvalue, obj->Buffer.Pointer,
1850*3f9a00e3SBartlomiej Grzesik 			    MIN(size, obj->Buffer.Length));
1851*3f9a00e3SBartlomiej Grzesik 		return (obj->Buffer.Length);
1852*3f9a00e3SBartlomiej Grzesik 	}
1853*3f9a00e3SBartlomiej Grzesik 
1854*3f9a00e3SBartlomiej Grzesik 	return (-1);
1855*3f9a00e3SBartlomiej Grzesik }
1856*3f9a00e3SBartlomiej Grzesik 
185762508c53SJohn Baldwin int
185810ce62b9SNate Lawson acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate)
185910ce62b9SNate Lawson {
186010ce62b9SNate Lawson     struct acpi_softc *sc;
186110ce62b9SNate Lawson     ACPI_HANDLE handle;
186210ce62b9SNate Lawson     ACPI_STATUS status;
186310ce62b9SNate Lawson     char sxd[8];
186410ce62b9SNate Lawson 
186510ce62b9SNate Lawson     handle = acpi_get_handle(dev);
186610ce62b9SNate Lawson 
186710ce62b9SNate Lawson     /*
186810ce62b9SNate Lawson      * XXX If we find these devices, don't try to power them down.
186910ce62b9SNate Lawson      * The serial and IRDA ports on my T23 hang the system when
187010ce62b9SNate Lawson      * set to D3 and it appears that such legacy devices may
187110ce62b9SNate Lawson      * need special handling in their drivers.
187210ce62b9SNate Lawson      */
1873a7a3177fSJung-uk Kim     if (dstate == NULL || handle == NULL ||
187410ce62b9SNate Lawson 	acpi_MatchHid(handle, "PNP0500") ||
187510ce62b9SNate Lawson 	acpi_MatchHid(handle, "PNP0501") ||
187610ce62b9SNate Lawson 	acpi_MatchHid(handle, "PNP0502") ||
187710ce62b9SNate Lawson 	acpi_MatchHid(handle, "PNP0510") ||
187810ce62b9SNate Lawson 	acpi_MatchHid(handle, "PNP0511"))
187910ce62b9SNate Lawson 	return (ENXIO);
188010ce62b9SNate Lawson 
188110ce62b9SNate Lawson     /*
1882a7a3177fSJung-uk Kim      * Override next state with the value from _SxD, if present.
1883a7a3177fSJung-uk Kim      * Note illegal _S0D is evaluated because some systems expect this.
188410ce62b9SNate Lawson      */
1885a7a3177fSJung-uk Kim     sc = device_get_softc(bus);
188610ce62b9SNate Lawson     snprintf(sxd, sizeof(sxd), "_S%dD", sc->acpi_sstate);
188710ce62b9SNate Lawson     status = acpi_GetInteger(handle, sxd, dstate);
1888a7a3177fSJung-uk Kim     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND) {
1889a7a3177fSJung-uk Kim 	    device_printf(dev, "failed to get %s on %s: %s\n", sxd,
1890a7a3177fSJung-uk Kim 		acpi_name(handle), AcpiFormatException(status));
1891a7a3177fSJung-uk Kim 	    return (ENXIO);
189210ce62b9SNate Lawson     }
189310ce62b9SNate Lawson 
1894a7a3177fSJung-uk Kim     return (0);
189510ce62b9SNate Lawson }
189610ce62b9SNate Lawson 
1897df8d2a32SNate Lawson /* Callback arg for our implementation of walking the namespace. */
1898df8d2a32SNate Lawson struct acpi_device_scan_ctx {
1899df8d2a32SNate Lawson     acpi_scan_cb_t	user_fn;
1900df8d2a32SNate Lawson     void		*arg;
1901df8d2a32SNate Lawson     ACPI_HANDLE		parent;
1902df8d2a32SNate Lawson };
1903df8d2a32SNate Lawson 
1904ce619b2eSNate Lawson static ACPI_STATUS
1905df8d2a32SNate Lawson acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level, void *arg, void **retval)
1906df8d2a32SNate Lawson {
1907df8d2a32SNate Lawson     struct acpi_device_scan_ctx *ctx;
1908df8d2a32SNate Lawson     device_t dev, old_dev;
1909df8d2a32SNate Lawson     ACPI_STATUS status;
1910df8d2a32SNate Lawson     ACPI_OBJECT_TYPE type;
1911df8d2a32SNate Lawson 
1912df8d2a32SNate Lawson     /*
1913df8d2a32SNate Lawson      * Skip this device if we think we'll have trouble with it or it is
1914df8d2a32SNate Lawson      * the parent where the scan began.
1915df8d2a32SNate Lawson      */
1916df8d2a32SNate Lawson     ctx = (struct acpi_device_scan_ctx *)arg;
1917df8d2a32SNate Lawson     if (acpi_avoid(h) || h == ctx->parent)
1918df8d2a32SNate Lawson 	return (AE_OK);
1919df8d2a32SNate Lawson 
1920df8d2a32SNate Lawson     /* If this is not a valid device type (e.g., a method), skip it. */
1921df8d2a32SNate Lawson     if (ACPI_FAILURE(AcpiGetType(h, &type)))
1922df8d2a32SNate Lawson 	return (AE_OK);
1923df8d2a32SNate Lawson     if (type != ACPI_TYPE_DEVICE && type != ACPI_TYPE_PROCESSOR &&
1924df8d2a32SNate Lawson 	type != ACPI_TYPE_THERMAL && type != ACPI_TYPE_POWER)
1925df8d2a32SNate Lawson 	return (AE_OK);
1926df8d2a32SNate Lawson 
1927df8d2a32SNate Lawson     /*
1928df8d2a32SNate Lawson      * Call the user function with the current device.  If it is unchanged
1929df8d2a32SNate Lawson      * afterwards, return.  Otherwise, we update the handle to the new dev.
1930df8d2a32SNate Lawson      */
1931df8d2a32SNate Lawson     old_dev = acpi_get_device(h);
1932df8d2a32SNate Lawson     dev = old_dev;
1933df8d2a32SNate Lawson     status = ctx->user_fn(h, &dev, level, ctx->arg);
1934df8d2a32SNate Lawson     if (ACPI_FAILURE(status) || old_dev == dev)
1935df8d2a32SNate Lawson 	return (status);
1936df8d2a32SNate Lawson 
1937df8d2a32SNate Lawson     /* Remove the old child and its connection to the handle. */
1938709749aaSVladimir Kondratyev     if (old_dev != NULL)
1939df8d2a32SNate Lawson 	device_delete_child(device_get_parent(old_dev), old_dev);
1940df8d2a32SNate Lawson 
1941df8d2a32SNate Lawson     /* Recreate the handle association if the user created a device. */
1942df8d2a32SNate Lawson     if (dev != NULL)
1943df8d2a32SNate Lawson 	AcpiAttachData(h, acpi_fake_objhandler, dev);
1944df8d2a32SNate Lawson 
1945df8d2a32SNate Lawson     return (AE_OK);
1946df8d2a32SNate Lawson }
1947df8d2a32SNate Lawson 
1948df8d2a32SNate Lawson static ACPI_STATUS
1949df8d2a32SNate Lawson acpi_device_scan_children(device_t bus, device_t dev, int max_depth,
1950df8d2a32SNate Lawson     acpi_scan_cb_t user_fn, void *arg)
1951ce619b2eSNate Lawson {
1952ce619b2eSNate Lawson     ACPI_HANDLE h;
1953df8d2a32SNate Lawson     struct acpi_device_scan_ctx ctx;
1954ce619b2eSNate Lawson 
1955df8d2a32SNate Lawson     if (acpi_disabled("children"))
1956df8d2a32SNate Lawson 	return (AE_OK);
1957df8d2a32SNate Lawson 
1958df8d2a32SNate Lawson     if (dev == NULL)
1959df8d2a32SNate Lawson 	h = ACPI_ROOT_OBJECT;
1960df8d2a32SNate Lawson     else if ((h = acpi_get_handle(dev)) == NULL)
1961ce619b2eSNate Lawson 	return (AE_BAD_PARAMETER);
1962df8d2a32SNate Lawson     ctx.user_fn = user_fn;
1963df8d2a32SNate Lawson     ctx.arg = arg;
1964df8d2a32SNate Lawson     ctx.parent = h;
1965df8d2a32SNate Lawson     return (AcpiWalkNamespace(ACPI_TYPE_ANY, h, max_depth,
19662272d050SJung-uk Kim 	acpi_device_scan_cb, NULL, &ctx, NULL));
1967ce619b2eSNate Lawson }
1968ce619b2eSNate Lawson 
196910ce62b9SNate Lawson /*
197010ce62b9SNate Lawson  * Even though ACPI devices are not PCI, we use the PCI approach for setting
197110ce62b9SNate Lawson  * device power states since it's close enough to ACPI.
197210ce62b9SNate Lawson  */
1973ddf8c230SVladimir Kondratyev int
1974a7a3177fSJung-uk Kim acpi_set_powerstate(device_t child, int state)
197510ce62b9SNate Lawson {
197610ce62b9SNate Lawson     ACPI_HANDLE h;
197710ce62b9SNate Lawson     ACPI_STATUS status;
197810ce62b9SNate Lawson 
197910ce62b9SNate Lawson     h = acpi_get_handle(child);
1980a0e73a12SJung-uk Kim     if (state < ACPI_STATE_D0 || state > ACPI_D_STATES_MAX)
198110ce62b9SNate Lawson 	return (EINVAL);
198210ce62b9SNate Lawson     if (h == NULL)
198310ce62b9SNate Lawson 	return (0);
198410ce62b9SNate Lawson 
198510ce62b9SNate Lawson     /* Ignore errors if the power methods aren't present. */
198610ce62b9SNate Lawson     status = acpi_pwr_switch_consumer(h, state);
1987a7a3177fSJung-uk Kim     if (ACPI_SUCCESS(status)) {
1988a7a3177fSJung-uk Kim 	if (bootverbose)
1989a7a3177fSJung-uk Kim 	    device_printf(child, "set ACPI power state D%d on %s\n",
1990a7a3177fSJung-uk Kim 		state, acpi_name(h));
1991a7a3177fSJung-uk Kim     } else if (status != AE_NOT_FOUND)
1992a7a3177fSJung-uk Kim 	device_printf(child,
1993a7a3177fSJung-uk Kim 	    "failed to set ACPI power state D%d on %s: %s\n", state,
1994a7a3177fSJung-uk Kim 	    acpi_name(h), AcpiFormatException(status));
199510ce62b9SNate Lawson 
1996a7a3177fSJung-uk Kim     return (0);
199710ce62b9SNate Lawson }
199810ce62b9SNate Lawson 
199932d18aa5SMike Smith static int
200032d18aa5SMike Smith acpi_isa_pnp_probe(device_t bus, device_t child, struct isa_pnp_id *ids)
200132d18aa5SMike Smith {
20021e4925e8SNate Lawson     int			result, cid_count, i;
20031e4925e8SNate Lawson     uint32_t		lid, cids[8];
2004bc0f2195SMike Smith 
2005b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
2006bc0f2195SMike Smith 
2007bc0f2195SMike Smith     /*
2008bc0f2195SMike Smith      * ISA-style drivers attached to ACPI may persist and
2009bc0f2195SMike Smith      * probe manually if we return ENOENT.  We never want
2010bc0f2195SMike Smith      * that to happen, so don't ever return it.
2011bc0f2195SMike Smith      */
2012bc0f2195SMike Smith     result = ENXIO;
2013bc0f2195SMike Smith 
2014be2b1797SNate Lawson     /* Scan the supplied IDs for a match */
2015b2566207STakanori Watanabe     lid = acpi_isa_get_logicalid(child);
20161e4925e8SNate Lawson     cid_count = acpi_isa_get_compatid(child, cids, 8);
2017bc0f2195SMike Smith     while (ids && ids->ip_id) {
20181e4925e8SNate Lawson 	if (lid == ids->ip_id) {
2019bc0f2195SMike Smith 	    result = 0;
2020bc0f2195SMike Smith 	    goto out;
2021bc0f2195SMike Smith 	}
20221e4925e8SNate Lawson 	for (i = 0; i < cid_count; i++) {
20231e4925e8SNate Lawson 	    if (cids[i] == ids->ip_id) {
20241e4925e8SNate Lawson 		result = 0;
20251e4925e8SNate Lawson 		goto out;
20261e4925e8SNate Lawson 	    }
20271e4925e8SNate Lawson 	}
2028bc0f2195SMike Smith 	ids++;
2029bc0f2195SMike Smith     }
2030be2b1797SNate Lawson 
2031bc0f2195SMike Smith  out:
20329e0dd54fSNate Lawson     if (result == 0 && ids->ip_desc)
20339e0dd54fSNate Lawson 	device_set_desc(child, ids->ip_desc);
20349e0dd54fSNate Lawson 
2035bc0f2195SMike Smith     return_VALUE (result);
2036bc0f2195SMike Smith }
2037bc0f2195SMike Smith 
2038d320e05cSJohn Baldwin /*
2039d320e05cSJohn Baldwin  * Look for a MCFG table.  If it is present, use the settings for
2040d320e05cSJohn Baldwin  * domain (segment) 0 to setup PCI config space access via the memory
2041d320e05cSJohn Baldwin  * map.
2042185c34f7SJayachandran C.  *
2043185c34f7SJayachandran C.  * On non-x86 architectures (arm64 for now), this will be done from the
2044185c34f7SJayachandran C.  * PCI host bridge driver.
2045d320e05cSJohn Baldwin  */
2046d320e05cSJohn Baldwin static void
2047d320e05cSJohn Baldwin acpi_enable_pcie(void)
2048d320e05cSJohn Baldwin {
2049185c34f7SJayachandran C. #if defined(__i386__) || defined(__amd64__)
2050d320e05cSJohn Baldwin 	ACPI_TABLE_HEADER *hdr;
2051d320e05cSJohn Baldwin 	ACPI_MCFG_ALLOCATION *alloc, *end;
2052d320e05cSJohn Baldwin 	ACPI_STATUS status;
2053d320e05cSJohn Baldwin 
2054d320e05cSJohn Baldwin 	status = AcpiGetTable(ACPI_SIG_MCFG, 1, &hdr);
2055d320e05cSJohn Baldwin 	if (ACPI_FAILURE(status))
2056d320e05cSJohn Baldwin 		return;
2057d320e05cSJohn Baldwin 
2058d320e05cSJohn Baldwin 	end = (ACPI_MCFG_ALLOCATION *)((char *)hdr + hdr->Length);
2059d320e05cSJohn Baldwin 	alloc = (ACPI_MCFG_ALLOCATION *)((ACPI_TABLE_MCFG *)hdr + 1);
2060d320e05cSJohn Baldwin 	while (alloc < end) {
2061d320e05cSJohn Baldwin 		if (alloc->PciSegment == 0) {
2062d320e05cSJohn Baldwin 			pcie_cfgregopen(alloc->Address, alloc->StartBusNumber,
2063d320e05cSJohn Baldwin 			    alloc->EndBusNumber);
2064d320e05cSJohn Baldwin 			return;
2065d320e05cSJohn Baldwin 		}
2066d320e05cSJohn Baldwin 		alloc++;
2067d320e05cSJohn Baldwin 	}
2068d320e05cSJohn Baldwin #endif
2069185c34f7SJayachandran C. }
2070d320e05cSJohn Baldwin 
2071855e49f3SAlexander Motin static void
2072855e49f3SAlexander Motin acpi_platform_osc(device_t dev)
2073855e49f3SAlexander Motin {
2074855e49f3SAlexander Motin 	ACPI_HANDLE sb_handle;
2075855e49f3SAlexander Motin 	ACPI_STATUS status;
2076855e49f3SAlexander Motin 	uint32_t cap_set[2];
2077855e49f3SAlexander Motin 
2078855e49f3SAlexander Motin 	/* 0811B06E-4A27-44F9-8D60-3CBBC22E7B48 */
2079855e49f3SAlexander Motin 	static uint8_t acpi_platform_uuid[ACPI_UUID_LENGTH] = {
2080855e49f3SAlexander Motin 		0x6e, 0xb0, 0x11, 0x08, 0x27, 0x4a, 0xf9, 0x44,
2081855e49f3SAlexander Motin 		0x8d, 0x60, 0x3c, 0xbb, 0xc2, 0x2e, 0x7b, 0x48
2082855e49f3SAlexander Motin 	};
2083855e49f3SAlexander Motin 
2084855e49f3SAlexander Motin 	if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle)))
2085855e49f3SAlexander Motin 		return;
2086855e49f3SAlexander Motin 
2087855e49f3SAlexander Motin 	cap_set[1] = 0x10;	/* APEI Support */
2088855e49f3SAlexander Motin 	status = acpi_EvaluateOSC(sb_handle, acpi_platform_uuid, 1,
2089855e49f3SAlexander Motin 	    nitems(cap_set), cap_set, cap_set, false);
2090855e49f3SAlexander Motin 	if (ACPI_FAILURE(status)) {
2091855e49f3SAlexander Motin 		if (status == AE_NOT_FOUND)
2092855e49f3SAlexander Motin 			return;
2093855e49f3SAlexander Motin 		device_printf(dev, "_OSC failed: %s\n",
2094855e49f3SAlexander Motin 		    AcpiFormatException(status));
2095855e49f3SAlexander Motin 		return;
2096855e49f3SAlexander Motin 	}
2097855e49f3SAlexander Motin }
2098855e49f3SAlexander Motin 
2099bc0f2195SMike Smith /*
210033332dc2SNate Lawson  * Scan all of the ACPI namespace and attach child devices.
210115e32d5dSMike Smith  *
210233332dc2SNate Lawson  * We should only expect to find devices in the \_PR, \_TZ, \_SI, and
210333332dc2SNate Lawson  * \_SB scopes, and \_PR and \_TZ became obsolete in the ACPI 2.0 spec.
210433332dc2SNate Lawson  * However, in violation of the spec, some systems place their PCI link
210533332dc2SNate Lawson  * devices in \, so we have to walk the whole namespace.  We check the
210633332dc2SNate Lawson  * type of namespace nodes, so this should be ok.
210715e32d5dSMike Smith  */
210815e32d5dSMike Smith static void
210915e32d5dSMike Smith acpi_probe_children(device_t bus)
211015e32d5dSMike Smith {
211115e32d5dSMike Smith 
2112b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
21130ae55423SMike Smith 
211415e32d5dSMike Smith     /*
211515e32d5dSMike Smith      * Scan the namespace and insert placeholders for all the devices that
2116edc13633SNate Lawson      * we find.  We also probe/attach any early devices.
211715e32d5dSMike Smith      *
211815e32d5dSMike Smith      * Note that we use AcpiWalkNamespace rather than AcpiGetDevices because
2119be2b1797SNate Lawson      * we want to create nodes for all devices, not just those that are
2120be2b1797SNate Lawson      * currently present. (This assumes that we don't want to create/remove
2121be2b1797SNate Lawson      * devices as they appear, which might be smarter.)
212215e32d5dSMike Smith      */
21234c1cdee6SMike Smith     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "namespace scan\n"));
212433332dc2SNate Lawson     AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 100, acpi_probe_child,
21252272d050SJung-uk Kim 	NULL, bus, NULL);
212615e32d5dSMike Smith 
2127adad4744SNate Lawson     /* Pre-allocate resources for our rman from any sysresource devices. */
2128adad4744SNate Lawson     acpi_sysres_alloc(bus);
2129adad4744SNate Lawson 
2130ea233199SJohn Baldwin     /* Reserve resources already allocated to children. */
2131ea233199SJohn Baldwin     acpi_reserve_resources(bus);
2132ea233199SJohn Baldwin 
2133edc13633SNate Lawson     /* Create any static children by calling device identify methods. */
2134edc13633SNate Lawson     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "device identify routines\n"));
2135edc13633SNate Lawson     bus_generic_probe(bus);
2136edc13633SNate Lawson 
21375e66b8e2SJohn Baldwin     /* Probe/attach all children, created statically and from the namespace. */
21380430ba9eSAndriy Gapon     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "acpi bus_generic_attach\n"));
213915e32d5dSMike Smith     bus_generic_attach(bus);
21400ae55423SMike Smith 
214188a79fc0SNate Lawson     /* Attach wake sysctls. */
21425c9ea25eSNate Lawson     acpi_wake_sysctl_walk(bus);
214388a79fc0SNate Lawson 
2144bc0f2195SMike Smith     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "done attaching children\n"));
21450ae55423SMike Smith     return_VOID;
214615e32d5dSMike Smith }
214715e32d5dSMike Smith 
2148b82ca9a9SNate Lawson /*
2149d227204dSJohn Baldwin  * Determine the probe order for a given device.
2150b82ca9a9SNate Lawson  */
2151d227204dSJohn Baldwin static void
2152b82ca9a9SNate Lawson acpi_probe_order(ACPI_HANDLE handle, int *order)
215391233413SNate Lawson {
2154463e0f91SJohn Baldwin 	ACPI_OBJECT_TYPE type;
215591233413SNate Lawson 
2156b82ca9a9SNate Lawson 	/*
2157404b0d10SJung-uk Kim 	 * 0. CPUs
2158404b0d10SJung-uk Kim 	 * 1. I/O port and memory system resource holders
2159404b0d10SJung-uk Kim 	 * 2. Clocks and timers (to handle early accesses)
2160b1f9b996SAndriy Gapon 	 * 3. Embedded controllers (to handle early accesses)
2161b1f9b996SAndriy Gapon 	 * 4. PCI Link Devices
2162b82ca9a9SNate Lawson 	 */
2163463e0f91SJohn Baldwin 	AcpiGetType(handle, &type);
2164aa835160SAndriy Gapon 	if (type == ACPI_TYPE_PROCESSOR)
2165404b0d10SJung-uk Kim 		*order = 0;
2166404b0d10SJung-uk Kim 	else if (acpi_MatchHid(handle, "PNP0C01") ||
2167404b0d10SJung-uk Kim 	    acpi_MatchHid(handle, "PNP0C02"))
216891233413SNate Lawson 		*order = 1;
2169404b0d10SJung-uk Kim 	else if (acpi_MatchHid(handle, "PNP0100") ||
2170404b0d10SJung-uk Kim 	    acpi_MatchHid(handle, "PNP0103") ||
2171404b0d10SJung-uk Kim 	    acpi_MatchHid(handle, "PNP0B00"))
217291233413SNate Lawson 		*order = 2;
2173aa835160SAndriy Gapon 	else if (acpi_MatchHid(handle, "PNP0C09"))
2174b460c6f8SJohn Baldwin 		*order = 3;
2175aa835160SAndriy Gapon 	else if (acpi_MatchHid(handle, "PNP0C0F"))
2176aa835160SAndriy Gapon 		*order = 4;
217791233413SNate Lawson }
217891233413SNate Lawson 
217915e32d5dSMike Smith /*
218015e32d5dSMike Smith  * Evaluate a child device and determine whether we might attach a device to
218115e32d5dSMike Smith  * it.
218215e32d5dSMike Smith  */
218315e32d5dSMike Smith static ACPI_STATUS
218415e32d5dSMike Smith acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
218515e32d5dSMike Smith {
21860e68afe5SAndrew Turner     ACPI_DEVICE_INFO *devinfo;
21870e68afe5SAndrew Turner     struct acpi_device	*ad;
21885a77b11bSJung-uk Kim     struct acpi_prw_data prw;
218915e32d5dSMike Smith     ACPI_OBJECT_TYPE type;
2190858a52f4SMitsuru IWASAKI     ACPI_HANDLE h;
219133332dc2SNate Lawson     device_t bus, child;
2192495a4144SJung-uk Kim     char *handle_str;
2193e4cd9dcfSJohn Baldwin     int order;
219415e32d5dSMike Smith 
2195b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
21960ae55423SMike Smith 
2197495a4144SJung-uk Kim     if (acpi_disabled("children"))
2198495a4144SJung-uk Kim 	return_ACPI_STATUS (AE_OK);
2199495a4144SJung-uk Kim 
2200be2b1797SNate Lawson     /* Skip this device if we think we'll have trouble with it. */
22010ae55423SMike Smith     if (acpi_avoid(handle))
22020ae55423SMike Smith 	return_ACPI_STATUS (AE_OK);
22030ae55423SMike Smith 
220491233413SNate Lawson     bus = (device_t)context;
2205b53f2771SMike Smith     if (ACPI_SUCCESS(AcpiGetType(handle, &type))) {
2206495a4144SJung-uk Kim 	handle_str = acpi_name(handle);
220715e32d5dSMike Smith 	switch (type) {
220815e32d5dSMike Smith 	case ACPI_TYPE_DEVICE:
2209495a4144SJung-uk Kim 	    /*
2210495a4144SJung-uk Kim 	     * Since we scan from \, be sure to skip system scope objects.
2211495a4144SJung-uk Kim 	     * \_SB_ and \_TZ_ are defined in ACPICA as devices to work around
2212affa1826SJung-uk Kim 	     * BIOS bugs.  For example, \_SB_ is to allow \_SB_._INI to be run
2213453130d9SPedro F. Giffuni 	     * during the initialization and \_TZ_ is to support Notify() on it.
2214495a4144SJung-uk Kim 	     */
2215495a4144SJung-uk Kim 	    if (strcmp(handle_str, "\\_SB_") == 0 ||
2216495a4144SJung-uk Kim 		strcmp(handle_str, "\\_TZ_") == 0)
2217495a4144SJung-uk Kim 		break;
22185a77b11bSJung-uk Kim 	    if (acpi_parse_prw(handle, &prw) == 0)
22195a77b11bSJung-uk Kim 		AcpiSetupGpeForWake(handle, prw.gpe_handle, prw.gpe_bit);
2220183c8af3SJohn Baldwin 
2221183c8af3SJohn Baldwin 	    /*
2222183c8af3SJohn Baldwin 	     * Ignore devices that do not have a _HID or _CID.  They should
2223183c8af3SJohn Baldwin 	     * be discovered by other buses (e.g. the PCI bus driver).
2224183c8af3SJohn Baldwin 	     */
2225183c8af3SJohn Baldwin 	    if (!acpi_has_hid(handle))
2226183c8af3SJohn Baldwin 		break;
2227495a4144SJung-uk Kim 	    /* FALLTHROUGH */
222815e32d5dSMike Smith 	case ACPI_TYPE_PROCESSOR:
222915e32d5dSMike Smith 	case ACPI_TYPE_THERMAL:
223015e32d5dSMike Smith 	case ACPI_TYPE_POWER:
223133332dc2SNate Lawson 	    /*
2232463e0f91SJohn Baldwin 	     * Create a placeholder device for this node.  Sort the
2233463e0f91SJohn Baldwin 	     * placeholder so that the probe/attach passes will run
2234463e0f91SJohn Baldwin 	     * breadth-first.  Orders less than ACPI_DEV_BASE_ORDER
2235463e0f91SJohn Baldwin 	     * are reserved for special objects (i.e., system
2236b1f9b996SAndriy Gapon 	     * resources).
223715e32d5dSMike Smith 	     */
223833332dc2SNate Lawson 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "scanning '%s'\n", handle_str));
2239404b0d10SJung-uk Kim 	    order = level * 10 + ACPI_DEV_BASE_ORDER;
2240da72d149SNate Lawson 	    acpi_probe_order(handle, &order);
2241e4cd9dcfSJohn Baldwin 	    child = BUS_ADD_CHILD(bus, order, NULL, -1);
2242bc0f2195SMike Smith 	    if (child == NULL)
2243bc0f2195SMike Smith 		break;
224459a890e6SNate Lawson 
224559a890e6SNate Lawson 	    /* Associate the handle with the device_t and vice versa. */
224615e32d5dSMike Smith 	    acpi_set_handle(child, handle);
224759a890e6SNate Lawson 	    AcpiAttachData(handle, acpi_fake_objhandler, child);
2248bc0f2195SMike Smith 
2249bc0f2195SMike Smith 	    /*
2250b519f9d6SMike Smith 	     * Check that the device is present.  If it's not present,
2251b519f9d6SMike Smith 	     * leave it disabled (so that we have a device_t attached to
2252b519f9d6SMike Smith 	     * the handle, but we don't probe it).
2253893f750aSNate Lawson 	     *
2254893f750aSNate Lawson 	     * XXX PCI link devices sometimes report "present" but not
2255893f750aSNate Lawson 	     * "functional" (i.e. if disabled).  Go ahead and probe them
2256893f750aSNate Lawson 	     * anyway since we may enable them later.
2257b519f9d6SMike Smith 	     */
2258858a52f4SMitsuru IWASAKI 	    if (type == ACPI_TYPE_DEVICE && !acpi_DeviceIsPresent(child)) {
2259858a52f4SMitsuru IWASAKI 		/* Never disable PCI link devices. */
2260858a52f4SMitsuru IWASAKI 		if (acpi_MatchHid(handle, "PNP0C0F"))
2261858a52f4SMitsuru IWASAKI 		    break;
2262858a52f4SMitsuru IWASAKI 		/*
2263858a52f4SMitsuru IWASAKI 		 * Docking stations should remain enabled since the system
2264858a52f4SMitsuru IWASAKI 		 * may be undocked at boot.
2265858a52f4SMitsuru IWASAKI 		 */
2266858a52f4SMitsuru IWASAKI 		if (ACPI_SUCCESS(AcpiGetHandle(handle, "_DCK", &h)))
2267858a52f4SMitsuru IWASAKI 		    break;
2268858a52f4SMitsuru IWASAKI 
2269b519f9d6SMike Smith 		device_disable(child);
2270b519f9d6SMike Smith 		break;
2271b519f9d6SMike Smith 	    }
2272b519f9d6SMike Smith 
2273b519f9d6SMike Smith 	    /*
2274bc0f2195SMike Smith 	     * Get the device's resource settings and attach them.
2275bc0f2195SMike Smith 	     * Note that if the device has _PRS but no _CRS, we need
2276bc0f2195SMike Smith 	     * to decide when it's appropriate to try to configure the
2277bc0f2195SMike Smith 	     * device.  Ignore the return value here; it's OK for the
2278bc0f2195SMike Smith 	     * device not to have any resources.
2279bc0f2195SMike Smith 	     */
228072ad60adSNate Lawson 	    acpi_parse_resources(child, handle, &acpi_res_parse_set, NULL);
22810e68afe5SAndrew Turner 
22820e68afe5SAndrew Turner 	    ad = device_get_ivars(child);
22830e68afe5SAndrew Turner 	    ad->ad_cls_class = 0xffffff;
22840e68afe5SAndrew Turner 	    if (ACPI_SUCCESS(AcpiGetObjectInfo(handle, &devinfo))) {
22850e68afe5SAndrew Turner 		if ((devinfo->Valid & ACPI_VALID_CLS) != 0 &&
22860e68afe5SAndrew Turner 		    devinfo->ClassCode.Length >= ACPI_PCICLS_STRING_SIZE) {
22870e68afe5SAndrew Turner 		    ad->ad_cls_class = strtoul(devinfo->ClassCode.String,
22880e68afe5SAndrew Turner 			NULL, 16);
22890e68afe5SAndrew Turner 		}
22900e68afe5SAndrew Turner 		AcpiOsFree(devinfo);
22910e68afe5SAndrew Turner 	    }
22920ae55423SMike Smith 	    break;
229315e32d5dSMike Smith 	}
229415e32d5dSMike Smith     }
2295be2b1797SNate Lawson 
22960ae55423SMike Smith     return_ACPI_STATUS (AE_OK);
229715e32d5dSMike Smith }
229815e32d5dSMike Smith 
229959a890e6SNate Lawson /*
230059a890e6SNate Lawson  * AcpiAttachData() requires an object handler but never uses it.  This is a
230159a890e6SNate Lawson  * placeholder object handler so we can store a device_t in an ACPI_HANDLE.
230259a890e6SNate Lawson  */
230359a890e6SNate Lawson void
230492488a57SJung-uk Kim acpi_fake_objhandler(ACPI_HANDLE h, void *data)
230559a890e6SNate Lawson {
230659a890e6SNate Lawson }
230759a890e6SNate Lawson 
230815e32d5dSMike Smith static void
230915e32d5dSMike Smith acpi_shutdown_final(void *arg, int howto)
231015e32d5dSMike Smith {
23112d0c82e8SJung-uk Kim     struct acpi_softc *sc = (struct acpi_softc *)arg;
231271804adcSJung-uk Kim     register_t intr;
2313d33f4987STakanori Watanabe     ACPI_STATUS status;
2314eeb3a05fSNate Lawson 
2315eeb3a05fSNate Lawson     /*
231680f0e4c2SNate Lawson      * XXX Shutdown code should only run on the BSP (cpuid 0).
231780f0e4c2SNate Lawson      * Some chipsets do not power off the system correctly if called from
231880f0e4c2SNate Lawson      * an AP.
2319eeb3a05fSNate Lawson      */
2320eeb3a05fSNate Lawson     if ((howto & RB_POWEROFF) != 0) {
2321904bf0c2SNate Lawson 	status = AcpiEnterSleepStatePrep(ACPI_STATE_S5);
2322904bf0c2SNate Lawson 	if (ACPI_FAILURE(status)) {
23232d0c82e8SJung-uk Kim 	    device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n",
2324904bf0c2SNate Lawson 		AcpiFormatException(status));
2325904bf0c2SNate Lawson 	    return;
2326904bf0c2SNate Lawson 	}
23272d0c82e8SJung-uk Kim 	device_printf(sc->acpi_dev, "Powering system off\n");
232871804adcSJung-uk Kim 	intr = intr_disable();
23291df130f1SJung-uk Kim 	status = AcpiEnterSleepState(ACPI_STATE_S5);
233071804adcSJung-uk Kim 	if (ACPI_FAILURE(status)) {
233171804adcSJung-uk Kim 	    intr_restore(intr);
23322d0c82e8SJung-uk Kim 	    device_printf(sc->acpi_dev, "power-off failed - %s\n",
23332d0c82e8SJung-uk Kim 		AcpiFormatException(status));
233471804adcSJung-uk Kim 	} else {
233515e32d5dSMike Smith 	    DELAY(1000000);
233671804adcSJung-uk Kim 	    intr_restore(intr);
23372d0c82e8SJung-uk Kim 	    device_printf(sc->acpi_dev, "power-off failed - timeout\n");
233815e32d5dSMike Smith 	}
2339ac731af5SJung-uk Kim     } else if ((howto & RB_HALT) == 0 && sc->acpi_handle_reboot) {
2340d85e6785SNate Lawson 	/* Reboot using the reset register. */
2341ac731af5SJung-uk Kim 	status = AcpiReset();
2342ac731af5SJung-uk Kim 	if (ACPI_SUCCESS(status)) {
234387a500cdSNate Lawson 	    DELAY(1000000);
23442d0c82e8SJung-uk Kim 	    device_printf(sc->acpi_dev, "reset failed - timeout\n");
2345ac731af5SJung-uk Kim 	} else if (status != AE_NOT_EXIST)
2346ac731af5SJung-uk Kim 	    device_printf(sc->acpi_dev, "reset failed - %s\n",
2347ac731af5SJung-uk Kim 		AcpiFormatException(status));
2348879e0604SMateusz Guzik     } else if (sc->acpi_do_disable && !KERNEL_PANICKED()) {
2349d85e6785SNate Lawson 	/*
2350d85e6785SNate Lawson 	 * Only disable ACPI if the user requested.  On some systems, writing
2351d85e6785SNate Lawson 	 * the disable value to SMI_CMD hangs the system.
2352d85e6785SNate Lawson 	 */
23532d0c82e8SJung-uk Kim 	device_printf(sc->acpi_dev, "Shutting down\n");
235480f0e4c2SNate Lawson 	AcpiTerminate();
235580f0e4c2SNate Lawson     }
235615e32d5dSMike Smith }
235715e32d5dSMike Smith 
235813d4f7baSMitsuru IWASAKI static void
235913d4f7baSMitsuru IWASAKI acpi_enable_fixed_events(struct acpi_softc *sc)
236013d4f7baSMitsuru IWASAKI {
236113d4f7baSMitsuru IWASAKI     static int	first_time = 1;
236213d4f7baSMitsuru IWASAKI 
236313d4f7baSMitsuru IWASAKI     /* Enable and clear fixed events and install handlers. */
23642be4e471SJung-uk Kim     if ((AcpiGbl_FADT.Flags & ACPI_FADT_POWER_BUTTON) == 0) {
236559ddeb18SNate Lawson 	AcpiClearEvent(ACPI_EVENT_POWER_BUTTON);
236613d4f7baSMitsuru IWASAKI 	AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
236733febf93SNate Lawson 				     acpi_event_power_button_sleep, sc);
2368be2b1797SNate Lawson 	if (first_time)
23696c0e8467SNate Lawson 	    device_printf(sc->acpi_dev, "Power Button (fixed)\n");
237013d4f7baSMitsuru IWASAKI     }
23712be4e471SJung-uk Kim     if ((AcpiGbl_FADT.Flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
237259ddeb18SNate Lawson 	AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON);
237313d4f7baSMitsuru IWASAKI 	AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON,
237433febf93SNate Lawson 				     acpi_event_sleep_button_sleep, sc);
2375be2b1797SNate Lawson 	if (first_time)
23766c0e8467SNate Lawson 	    device_printf(sc->acpi_dev, "Sleep Button (fixed)\n");
237713d4f7baSMitsuru IWASAKI     }
237813d4f7baSMitsuru IWASAKI 
237913d4f7baSMitsuru IWASAKI     first_time = 0;
238013d4f7baSMitsuru IWASAKI }
238113d4f7baSMitsuru IWASAKI 
238215e32d5dSMike Smith /*
2383c5ba0be4SMike Smith  * Returns true if the device is actually present and should
2384c5ba0be4SMike Smith  * be attached to.  This requires the present, enabled, UI-visible
2385c5ba0be4SMike Smith  * and diagnostics-passed bits to be set.
2386c5ba0be4SMike Smith  */
2387c5ba0be4SMike Smith BOOLEAN
2388c5ba0be4SMike Smith acpi_DeviceIsPresent(device_t dev)
2389c5ba0be4SMike Smith {
2390c5ba0be4SMike Smith 	ACPI_HANDLE h;
23918438a7a8SJung-uk Kim 	UINT32 s;
23928438a7a8SJung-uk Kim 	ACPI_STATUS status;
2393c5ba0be4SMike Smith 
23948438a7a8SJung-uk Kim 	h = acpi_get_handle(dev);
23958438a7a8SJung-uk Kim 	if (h == NULL)
2396c5ba0be4SMike Smith 		return (FALSE);
239735af9331SWarner Losh 
239835af9331SWarner Losh #ifdef ACPI_EARLY_EPYC_WAR
2399381388b9SMatt Macy 	/*
2400bf15eaf2SWarner Losh 	 * Certain Treadripper boards always returns 0 for FreeBSD because it
2401bf15eaf2SWarner Losh 	 * only returns non-zero for the OS string "Windows 2015". Otherwise it
2402bf15eaf2SWarner Losh 	 * will return zero. Force them to always be treated as present.
2403bf15eaf2SWarner Losh 	 * Beata versions were worse: they always returned 0.
2404381388b9SMatt Macy 	 */
2405381388b9SMatt Macy 	if (acpi_MatchHid(h, "AMDI0020") || acpi_MatchHid(h, "AMDI0010"))
2406381388b9SMatt Macy 		return (TRUE);
240735af9331SWarner Losh #endif
2408381388b9SMatt Macy 
2409817b71bbSAndriy Gapon 	status = acpi_GetInteger(h, "_STA", &s);
2410817b71bbSAndriy Gapon 
2411817b71bbSAndriy Gapon 	/*
2412817b71bbSAndriy Gapon 	 * If no _STA method or if it failed, then assume that
2413817b71bbSAndriy Gapon 	 * the device is present.
2414817b71bbSAndriy Gapon 	 */
24158438a7a8SJung-uk Kim 	if (ACPI_FAILURE(status))
2416817b71bbSAndriy Gapon 		return (TRUE);
2417be2b1797SNate Lawson 
24188438a7a8SJung-uk Kim 	return (ACPI_DEVICE_PRESENT(s) ? TRUE : FALSE);
2419c5ba0be4SMike Smith }
2420c5ba0be4SMike Smith 
2421c5ba0be4SMike Smith /*
2422b53f2771SMike Smith  * Returns true if the battery is actually present and inserted.
2423b53f2771SMike Smith  */
2424b53f2771SMike Smith BOOLEAN
2425b53f2771SMike Smith acpi_BatteryIsPresent(device_t dev)
2426b53f2771SMike Smith {
2427b53f2771SMike Smith 	ACPI_HANDLE h;
24288438a7a8SJung-uk Kim 	UINT32 s;
24298438a7a8SJung-uk Kim 	ACPI_STATUS status;
2430b53f2771SMike Smith 
24318438a7a8SJung-uk Kim 	h = acpi_get_handle(dev);
24328438a7a8SJung-uk Kim 	if (h == NULL)
2433b53f2771SMike Smith 		return (FALSE);
24348438a7a8SJung-uk Kim 	status = acpi_GetInteger(h, "_STA", &s);
2435be2b1797SNate Lawson 
2436817b71bbSAndriy Gapon 	/*
2437817b71bbSAndriy Gapon 	 * If no _STA method or if it failed, then assume that
2438817b71bbSAndriy Gapon 	 * the device is present.
2439817b71bbSAndriy Gapon 	 */
24408438a7a8SJung-uk Kim 	if (ACPI_FAILURE(status))
2441817b71bbSAndriy Gapon 		return (TRUE);
2442be2b1797SNate Lawson 
24438438a7a8SJung-uk Kim 	return (ACPI_BATTERY_PRESENT(s) ? TRUE : FALSE);
2444b53f2771SMike Smith }
2445b53f2771SMike Smith 
2446b53f2771SMike Smith /*
2447183c8af3SJohn Baldwin  * Returns true if a device has at least one valid device ID.
2448183c8af3SJohn Baldwin  */
2449ddf8c230SVladimir Kondratyev BOOLEAN
2450183c8af3SJohn Baldwin acpi_has_hid(ACPI_HANDLE h)
2451183c8af3SJohn Baldwin {
2452183c8af3SJohn Baldwin     ACPI_DEVICE_INFO	*devinfo;
2453183c8af3SJohn Baldwin     BOOLEAN		ret;
2454183c8af3SJohn Baldwin 
2455183c8af3SJohn Baldwin     if (h == NULL ||
2456183c8af3SJohn Baldwin 	ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo)))
2457183c8af3SJohn Baldwin 	return (FALSE);
2458183c8af3SJohn Baldwin 
2459183c8af3SJohn Baldwin     ret = FALSE;
2460183c8af3SJohn Baldwin     if ((devinfo->Valid & ACPI_VALID_HID) != 0)
2461183c8af3SJohn Baldwin 	ret = TRUE;
2462183c8af3SJohn Baldwin     else if ((devinfo->Valid & ACPI_VALID_CID) != 0)
2463183c8af3SJohn Baldwin 	if (devinfo->CompatibleIdList.Count > 0)
2464183c8af3SJohn Baldwin 	    ret = TRUE;
2465183c8af3SJohn Baldwin 
2466183c8af3SJohn Baldwin     AcpiOsFree(devinfo);
2467183c8af3SJohn Baldwin     return (ret);
2468183c8af3SJohn Baldwin }
2469183c8af3SJohn Baldwin 
2470183c8af3SJohn Baldwin /*
247191233413SNate Lawson  * Match a HID string against a handle
24725efca36fSTakanori Watanabe  * returns ACPI_MATCHHID_HID if _HID match
24735efca36fSTakanori Watanabe  *         ACPI_MATCHHID_CID if _CID match and not _HID match.
24745efca36fSTakanori Watanabe  *         ACPI_MATCHHID_NOMATCH=0 if no match.
247515e32d5dSMike Smith  */
24765efca36fSTakanori Watanabe int
2477ce619b2eSNate Lawson acpi_MatchHid(ACPI_HANDLE h, const char *hid)
247815e32d5dSMike Smith {
24791e4925e8SNate Lawson     ACPI_DEVICE_INFO	*devinfo;
248092488a57SJung-uk Kim     BOOLEAN		ret;
248192488a57SJung-uk Kim     int			i;
248292488a57SJung-uk Kim 
248392488a57SJung-uk Kim     if (hid == NULL || h == NULL ||
248492488a57SJung-uk Kim 	ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo)))
24855efca36fSTakanori Watanabe 	return (ACPI_MATCHHID_NOMATCH);
248615e32d5dSMike Smith 
24876d29ba58SAndriy Gapon     ret = ACPI_MATCHHID_NOMATCH;
2488c59c9a8eSJohn Baldwin     if ((devinfo->Valid & ACPI_VALID_HID) != 0 &&
248992488a57SJung-uk Kim 	strcmp(hid, devinfo->HardwareId.String) == 0)
24905efca36fSTakanori Watanabe 	    ret = ACPI_MATCHHID_HID;
249192488a57SJung-uk Kim     else if ((devinfo->Valid & ACPI_VALID_CID) != 0)
249292488a57SJung-uk Kim 	for (i = 0; i < devinfo->CompatibleIdList.Count; i++) {
249392488a57SJung-uk Kim 	    if (strcmp(hid, devinfo->CompatibleIdList.Ids[i].String) == 0) {
24945efca36fSTakanori Watanabe 		ret = ACPI_MATCHHID_CID;
24951e4925e8SNate Lawson 		break;
24961e4925e8SNate Lawson 	    }
24971e4925e8SNate Lawson 	}
2498be2b1797SNate Lawson 
249992488a57SJung-uk Kim     AcpiOsFree(devinfo);
25001e4925e8SNate Lawson     return (ret);
250115e32d5dSMike Smith }
250215e32d5dSMike Smith 
250315e32d5dSMike Smith /*
2504c5ba0be4SMike Smith  * Return the handle of a named object within our scope, ie. that of (parent)
2505c5ba0be4SMike Smith  * or one if its parents.
2506c5ba0be4SMike Smith  */
2507c5ba0be4SMike Smith ACPI_STATUS
2508c5ba0be4SMike Smith acpi_GetHandleInScope(ACPI_HANDLE parent, char *path, ACPI_HANDLE *result)
2509c5ba0be4SMike Smith {
2510c5ba0be4SMike Smith     ACPI_HANDLE		r;
2511c5ba0be4SMike Smith     ACPI_STATUS		status;
2512c5ba0be4SMike Smith 
2513be2b1797SNate Lawson     /* Walk back up the tree to the root */
2514c5ba0be4SMike Smith     for (;;) {
2515be2b1797SNate Lawson 	status = AcpiGetHandle(parent, path, &r);
2516be2b1797SNate Lawson 	if (ACPI_SUCCESS(status)) {
2517c5ba0be4SMike Smith 	    *result = r;
2518c5ba0be4SMike Smith 	    return (AE_OK);
2519c5ba0be4SMike Smith 	}
2520bee4aa4aSNate Lawson 	/* XXX Return error here? */
2521c5ba0be4SMike Smith 	if (status != AE_NOT_FOUND)
2522c5ba0be4SMike Smith 	    return (AE_OK);
2523b53f2771SMike Smith 	if (ACPI_FAILURE(AcpiGetParent(parent, &r)))
2524c5ba0be4SMike Smith 	    return (AE_NOT_FOUND);
2525c5ba0be4SMike Smith 	parent = r;
2526c5ba0be4SMike Smith     }
2527c5ba0be4SMike Smith }
2528c5ba0be4SMike Smith 
2529b91fc6c4SBartlomiej Grzesik ACPI_STATUS
2530b91fc6c4SBartlomiej Grzesik acpi_GetProperty(device_t dev, ACPI_STRING propname,
2531b91fc6c4SBartlomiej Grzesik     const ACPI_OBJECT **value)
2532b91fc6c4SBartlomiej Grzesik {
2533b91fc6c4SBartlomiej Grzesik 	device_t bus = device_get_parent(dev);
2534b91fc6c4SBartlomiej Grzesik 
2535b91fc6c4SBartlomiej Grzesik 	return (ACPI_GET_PROPERTY(bus, dev, propname, value));
2536b91fc6c4SBartlomiej Grzesik }
2537b91fc6c4SBartlomiej Grzesik 
2538c5ba0be4SMike Smith /*
2539c5ba0be4SMike Smith  * Allocate a buffer with a preset data size.
2540c5ba0be4SMike Smith  */
2541c5ba0be4SMike Smith ACPI_BUFFER *
2542c5ba0be4SMike Smith acpi_AllocBuffer(int size)
2543c5ba0be4SMike Smith {
2544c5ba0be4SMike Smith     ACPI_BUFFER	*buf;
2545c5ba0be4SMike Smith 
2546c5ba0be4SMike Smith     if ((buf = malloc(size + sizeof(*buf), M_ACPIDEV, M_NOWAIT)) == NULL)
2547c5ba0be4SMike Smith 	return (NULL);
2548c5ba0be4SMike Smith     buf->Length = size;
2549c5ba0be4SMike Smith     buf->Pointer = (void *)(buf + 1);
2550c5ba0be4SMike Smith     return (buf);
2551c5ba0be4SMike Smith }
2552c5ba0be4SMike Smith 
2553c310653eSNate Lawson ACPI_STATUS
2554cc58e4eeSNate Lawson acpi_SetInteger(ACPI_HANDLE handle, char *path, UINT32 number)
2555c310653eSNate Lawson {
2556c310653eSNate Lawson     ACPI_OBJECT arg1;
2557c310653eSNate Lawson     ACPI_OBJECT_LIST args;
2558c310653eSNate Lawson 
2559c310653eSNate Lawson     arg1.Type = ACPI_TYPE_INTEGER;
2560c310653eSNate Lawson     arg1.Integer.Value = number;
2561c310653eSNate Lawson     args.Count = 1;
2562c310653eSNate Lawson     args.Pointer = &arg1;
2563c310653eSNate Lawson 
2564c310653eSNate Lawson     return (AcpiEvaluateObject(handle, path, &args, NULL));
2565c310653eSNate Lawson }
2566c310653eSNate Lawson 
2567c5ba0be4SMike Smith /*
2568c5ba0be4SMike Smith  * Evaluate a path that should return an integer.
2569c5ba0be4SMike Smith  */
2570c5ba0be4SMike Smith ACPI_STATUS
2571cc58e4eeSNate Lawson acpi_GetInteger(ACPI_HANDLE handle, char *path, UINT32 *number)
2572c5ba0be4SMike Smith {
2573be2b1797SNate Lawson     ACPI_STATUS	status;
2574c5ba0be4SMike Smith     ACPI_BUFFER	buf;
2575c573e654SMitsuru IWASAKI     ACPI_OBJECT	param;
2576c5ba0be4SMike Smith 
2577c5ba0be4SMike Smith     if (handle == NULL)
2578c5ba0be4SMike Smith 	handle = ACPI_ROOT_OBJECT;
25790c7da7acSJohn Baldwin 
25800c7da7acSJohn Baldwin     /*
25810c7da7acSJohn Baldwin      * Assume that what we've been pointed at is an Integer object, or
25820c7da7acSJohn Baldwin      * a method that will return an Integer.
25830c7da7acSJohn Baldwin      */
2584c5ba0be4SMike Smith     buf.Pointer = &param;
2585c5ba0be4SMike Smith     buf.Length = sizeof(param);
2586be2b1797SNate Lawson     status = AcpiEvaluateObject(handle, path, NULL, &buf);
2587be2b1797SNate Lawson     if (ACPI_SUCCESS(status)) {
2588be2b1797SNate Lawson 	if (param.Type == ACPI_TYPE_INTEGER)
2589c5ba0be4SMike Smith 	    *number = param.Integer.Value;
2590be2b1797SNate Lawson 	else
2591be2b1797SNate Lawson 	    status = AE_TYPE;
2592c5ba0be4SMike Smith     }
25930c7da7acSJohn Baldwin 
25940c7da7acSJohn Baldwin     /*
25950c7da7acSJohn Baldwin      * In some applications, a method that's expected to return an Integer
25960c7da7acSJohn Baldwin      * may instead return a Buffer (probably to simplify some internal
25970c7da7acSJohn Baldwin      * arithmetic).  We'll try to fetch whatever it is, and if it's a Buffer,
25980c7da7acSJohn Baldwin      * convert it into an Integer as best we can.
25990c7da7acSJohn Baldwin      *
26000c7da7acSJohn Baldwin      * This is a hack.
26010c7da7acSJohn Baldwin      */
2602be2b1797SNate Lawson     if (status == AE_BUFFER_OVERFLOW) {
2603b53f2771SMike Smith 	if ((buf.Pointer = AcpiOsAllocate(buf.Length)) == NULL) {
2604be2b1797SNate Lawson 	    status = AE_NO_MEMORY;
26050c7da7acSJohn Baldwin 	} else {
2606be2b1797SNate Lawson 	    status = AcpiEvaluateObject(handle, path, NULL, &buf);
2607be2b1797SNate Lawson 	    if (ACPI_SUCCESS(status))
2608be2b1797SNate Lawson 		status = acpi_ConvertBufferToInteger(&buf, number);
26090c7da7acSJohn Baldwin 	    AcpiOsFree(buf.Pointer);
26100c7da7acSJohn Baldwin 	}
2611f97739daSNate Lawson     }
2612be2b1797SNate Lawson     return (status);
2613c5ba0be4SMike Smith }
2614c5ba0be4SMike Smith 
2615c573e654SMitsuru IWASAKI ACPI_STATUS
2616cc58e4eeSNate Lawson acpi_ConvertBufferToInteger(ACPI_BUFFER *bufp, UINT32 *number)
2617c573e654SMitsuru IWASAKI {
2618c573e654SMitsuru IWASAKI     ACPI_OBJECT	*p;
2619dba55fa2SNate Lawson     UINT8	*val;
2620c573e654SMitsuru IWASAKI     int		i;
2621c573e654SMitsuru IWASAKI 
2622c573e654SMitsuru IWASAKI     p = (ACPI_OBJECT *)bufp->Pointer;
2623c573e654SMitsuru IWASAKI     if (p->Type == ACPI_TYPE_INTEGER) {
2624c573e654SMitsuru IWASAKI 	*number = p->Integer.Value;
2625c573e654SMitsuru IWASAKI 	return (AE_OK);
2626c573e654SMitsuru IWASAKI     }
2627c573e654SMitsuru IWASAKI     if (p->Type != ACPI_TYPE_BUFFER)
2628c573e654SMitsuru IWASAKI 	return (AE_TYPE);
2629c573e654SMitsuru IWASAKI     if (p->Buffer.Length > sizeof(int))
2630c573e654SMitsuru IWASAKI 	return (AE_BAD_DATA);
2631be2b1797SNate Lawson 
2632c573e654SMitsuru IWASAKI     *number = 0;
2633dba55fa2SNate Lawson     val = p->Buffer.Pointer;
2634c573e654SMitsuru IWASAKI     for (i = 0; i < p->Buffer.Length; i++)
2635dba55fa2SNate Lawson 	*number += val[i] << (i * 8);
2636c573e654SMitsuru IWASAKI     return (AE_OK);
2637c573e654SMitsuru IWASAKI }
2638c573e654SMitsuru IWASAKI 
2639c5ba0be4SMike Smith /*
2640c5ba0be4SMike Smith  * Iterate over the elements of an a package object, calling the supplied
2641c5ba0be4SMike Smith  * function for each element.
2642c5ba0be4SMike Smith  *
2643c5ba0be4SMike Smith  * XXX possible enhancement might be to abort traversal on error.
2644c5ba0be4SMike Smith  */
2645c5ba0be4SMike Smith ACPI_STATUS
2646be2b1797SNate Lawson acpi_ForeachPackageObject(ACPI_OBJECT *pkg,
2647be2b1797SNate Lawson 	void (*func)(ACPI_OBJECT *comp, void *arg), void *arg)
2648c5ba0be4SMike Smith {
2649c5ba0be4SMike Smith     ACPI_OBJECT	*comp;
2650c5ba0be4SMike Smith     int		i;
2651c5ba0be4SMike Smith 
2652be2b1797SNate Lawson     if (pkg == NULL || pkg->Type != ACPI_TYPE_PACKAGE)
2653c5ba0be4SMike Smith 	return (AE_BAD_PARAMETER);
2654c5ba0be4SMike Smith 
2655be2b1797SNate Lawson     /* Iterate over components */
2656be2b1797SNate Lawson     i = 0;
2657be2b1797SNate Lawson     comp = pkg->Package.Elements;
2658be2b1797SNate Lawson     for (; i < pkg->Package.Count; i++, comp++)
2659c5ba0be4SMike Smith 	func(comp, arg);
2660c5ba0be4SMike Smith 
2661c5ba0be4SMike Smith     return (AE_OK);
2662c5ba0be4SMike Smith }
2663c5ba0be4SMike Smith 
26646f69255bSMike Smith /*
26656f69255bSMike Smith  * Find the (index)th resource object in a set.
26666f69255bSMike Smith  */
26676f69255bSMike Smith ACPI_STATUS
26686d63101aSMike Smith acpi_FindIndexedResource(ACPI_BUFFER *buf, int index, ACPI_RESOURCE **resp)
26696f69255bSMike Smith {
26706d63101aSMike Smith     ACPI_RESOURCE	*rp;
26716f69255bSMike Smith     int			i;
26726f69255bSMike Smith 
26736d63101aSMike Smith     rp = (ACPI_RESOURCE *)buf->Pointer;
26746f69255bSMike Smith     i = index;
26756d63101aSMike Smith     while (i-- > 0) {
2676be2b1797SNate Lawson 	/* Range check */
26776d63101aSMike Smith 	if (rp > (ACPI_RESOURCE *)((u_int8_t *)buf->Pointer + buf->Length))
26786f69255bSMike Smith 	    return (AE_BAD_PARAMETER);
2679be2b1797SNate Lawson 
2680be2b1797SNate Lawson 	/* Check for terminator */
2681e8d472a7SJung-uk Kim 	if (rp->Type == ACPI_RESOURCE_TYPE_END_TAG || rp->Length == 0)
26826d63101aSMike Smith 	    return (AE_NOT_FOUND);
2683abcbc5bcSNate Lawson 	rp = ACPI_NEXT_RESOURCE(rp);
26846f69255bSMike Smith     }
26856f69255bSMike Smith     if (resp != NULL)
26866d63101aSMike Smith 	*resp = rp;
2687be2b1797SNate Lawson 
26886d63101aSMike Smith     return (AE_OK);
26896d63101aSMike Smith }
26906d63101aSMike Smith 
26916d63101aSMike Smith /*
26926d63101aSMike Smith  * Append an ACPI_RESOURCE to an ACPI_BUFFER.
26936d63101aSMike Smith  *
26946d63101aSMike Smith  * Given a pointer to an ACPI_RESOURCE structure, expand the ACPI_BUFFER
26956d63101aSMike Smith  * provided to contain it.  If the ACPI_BUFFER is empty, allocate a sensible
26966d63101aSMike Smith  * backing block.  If the ACPI_RESOURCE is NULL, return an empty set of
26976d63101aSMike Smith  * resources.
26986d63101aSMike Smith  */
26996d63101aSMike Smith #define ACPI_INITIAL_RESOURCE_BUFFER_SIZE	512
27006d63101aSMike Smith 
27016d63101aSMike Smith ACPI_STATUS
27026d63101aSMike Smith acpi_AppendBufferResource(ACPI_BUFFER *buf, ACPI_RESOURCE *res)
27036d63101aSMike Smith {
27046d63101aSMike Smith     ACPI_RESOURCE	*rp;
27056d63101aSMike Smith     void		*newp;
27066d63101aSMike Smith 
2707be2b1797SNate Lawson     /* Initialise the buffer if necessary. */
27086d63101aSMike Smith     if (buf->Pointer == NULL) {
27096d63101aSMike Smith 	buf->Length = ACPI_INITIAL_RESOURCE_BUFFER_SIZE;
27106d63101aSMike Smith 	if ((buf->Pointer = AcpiOsAllocate(buf->Length)) == NULL)
27116d63101aSMike Smith 	    return (AE_NO_MEMORY);
27126d63101aSMike Smith 	rp = (ACPI_RESOURCE *)buf->Pointer;
2713e8d472a7SJung-uk Kim 	rp->Type = ACPI_RESOURCE_TYPE_END_TAG;
271460d306f0SJohn Baldwin 	rp->Length = ACPI_RS_SIZE_MIN;
27156d63101aSMike Smith     }
27166d63101aSMike Smith     if (res == NULL)
27176d63101aSMike Smith 	return (AE_OK);
27186d63101aSMike Smith 
27196d63101aSMike Smith     /*
27206d63101aSMike Smith      * Scan the current buffer looking for the terminator.
27216d63101aSMike Smith      * This will either find the terminator or hit the end
27226d63101aSMike Smith      * of the buffer and return an error.
27236d63101aSMike Smith      */
27246d63101aSMike Smith     rp = (ACPI_RESOURCE *)buf->Pointer;
27256d63101aSMike Smith     for (;;) {
2726be2b1797SNate Lawson 	/* Range check, don't go outside the buffer */
27276d63101aSMike Smith 	if (rp >= (ACPI_RESOURCE *)((u_int8_t *)buf->Pointer + buf->Length))
27286d63101aSMike Smith 	    return (AE_BAD_PARAMETER);
2729e8d472a7SJung-uk Kim 	if (rp->Type == ACPI_RESOURCE_TYPE_END_TAG || rp->Length == 0)
27306d63101aSMike Smith 	    break;
2731abcbc5bcSNate Lawson 	rp = ACPI_NEXT_RESOURCE(rp);
27326d63101aSMike Smith     }
27336d63101aSMike Smith 
27346d63101aSMike Smith     /*
27356d63101aSMike Smith      * Check the size of the buffer and expand if required.
27366d63101aSMike Smith      *
27376d63101aSMike Smith      * Required size is:
27386d63101aSMike Smith      *	size of existing resources before terminator +
27396d63101aSMike Smith      *	size of new resource and header +
27406d63101aSMike Smith      * 	size of terminator.
27416d63101aSMike Smith      *
27426d63101aSMike Smith      * Note that this loop should really only run once, unless
27436d63101aSMike Smith      * for some reason we are stuffing a *really* huge resource.
27446d63101aSMike Smith      */
27456d63101aSMike Smith     while ((((u_int8_t *)rp - (u_int8_t *)buf->Pointer) +
2746e8d472a7SJung-uk Kim 	    res->Length + ACPI_RS_SIZE_NO_DATA +
2747e8d472a7SJung-uk Kim 	    ACPI_RS_SIZE_MIN) >= buf->Length) {
27486d63101aSMike Smith 	if ((newp = AcpiOsAllocate(buf->Length * 2)) == NULL)
27496d63101aSMike Smith 	    return (AE_NO_MEMORY);
27506d63101aSMike Smith 	bcopy(buf->Pointer, newp, buf->Length);
2751a692219dSMike Smith 	rp = (ACPI_RESOURCE *)((u_int8_t *)newp +
2752a692219dSMike Smith 			       ((u_int8_t *)rp - (u_int8_t *)buf->Pointer));
27536d63101aSMike Smith 	AcpiOsFree(buf->Pointer);
27546d63101aSMike Smith 	buf->Pointer = newp;
27556d63101aSMike Smith 	buf->Length += buf->Length;
27566d63101aSMike Smith     }
27576d63101aSMike Smith 
2758be2b1797SNate Lawson     /* Insert the new resource. */
2759e8d472a7SJung-uk Kim     bcopy(res, rp, res->Length + ACPI_RS_SIZE_NO_DATA);
27606d63101aSMike Smith 
2761be2b1797SNate Lawson     /* And add the terminator. */
2762abcbc5bcSNate Lawson     rp = ACPI_NEXT_RESOURCE(rp);
2763e8d472a7SJung-uk Kim     rp->Type = ACPI_RESOURCE_TYPE_END_TAG;
276460d306f0SJohn Baldwin     rp->Length = ACPI_RS_SIZE_MIN;
27656d63101aSMike Smith 
27666f69255bSMike Smith     return (AE_OK);
27676f69255bSMike Smith }
2768c5ba0be4SMike Smith 
2769fe64ff3cSVladimir Kondratyev UINT64
2770fe64ff3cSVladimir Kondratyev acpi_DSMQuery(ACPI_HANDLE h, const uint8_t *uuid, int revision)
27718fd10880SBen Widawsky {
27728fd10880SBen Widawsky     /*
27738fd10880SBen Widawsky      * ACPI spec 9.1.1 defines this.
27748fd10880SBen Widawsky      *
27758fd10880SBen Widawsky      * "Arg2: Function Index Represents a specific function whose meaning is
27768fd10880SBen Widawsky      * specific to the UUID and Revision ID. Function indices should start
27778fd10880SBen Widawsky      * with 1. Function number zero is a query function (see the special
27788fd10880SBen Widawsky      * return code defined below)."
27798fd10880SBen Widawsky      */
27808fd10880SBen Widawsky     ACPI_BUFFER buf;
27818fd10880SBen Widawsky     ACPI_OBJECT *obj;
2782fe64ff3cSVladimir Kondratyev     UINT64 ret = 0;
2783fe64ff3cSVladimir Kondratyev     int i;
27848fd10880SBen Widawsky 
27858fd10880SBen Widawsky     if (!ACPI_SUCCESS(acpi_EvaluateDSM(h, uuid, revision, 0, NULL, &buf))) {
27868fd10880SBen Widawsky 	ACPI_INFO(("Failed to enumerate DSM functions\n"));
27878fd10880SBen Widawsky 	return (0);
27888fd10880SBen Widawsky     }
27898fd10880SBen Widawsky 
27908fd10880SBen Widawsky     obj = (ACPI_OBJECT *)buf.Pointer;
27918fd10880SBen Widawsky     KASSERT(obj, ("Object not allowed to be NULL\n"));
27928fd10880SBen Widawsky 
27938fd10880SBen Widawsky     /*
27948fd10880SBen Widawsky      * From ACPI 6.2 spec 9.1.1:
27958fd10880SBen Widawsky      * If Function Index = 0, a Buffer containing a function index bitfield.
27968fd10880SBen Widawsky      * Otherwise, the return value and type depends on the UUID and revision
27978fd10880SBen Widawsky      * ID (see below).
27988fd10880SBen Widawsky      */
27998fd10880SBen Widawsky     switch (obj->Type) {
28008fd10880SBen Widawsky     case ACPI_TYPE_BUFFER:
2801fe64ff3cSVladimir Kondratyev 	for (i = 0; i < MIN(obj->Buffer.Length, sizeof(ret)); i++)
2802fe64ff3cSVladimir Kondratyev 	    ret |= (((uint64_t)obj->Buffer.Pointer[i]) << (i * 8));
28038fd10880SBen Widawsky 	break;
28048fd10880SBen Widawsky     case ACPI_TYPE_INTEGER:
28058fd10880SBen Widawsky 	ACPI_BIOS_WARNING((AE_INFO,
28068fd10880SBen Widawsky 	    "Possibly buggy BIOS with ACPI_TYPE_INTEGER for function enumeration\n"));
2807fe64ff3cSVladimir Kondratyev 	ret = obj->Integer.Value;
28088fd10880SBen Widawsky 	break;
28098fd10880SBen Widawsky     default:
28108fd10880SBen Widawsky 	ACPI_WARNING((AE_INFO, "Unexpected return type %u\n", obj->Type));
28118fd10880SBen Widawsky     };
28128fd10880SBen Widawsky 
28138fd10880SBen Widawsky     AcpiOsFree(obj);
28148fd10880SBen Widawsky     return ret;
28158fd10880SBen Widawsky }
28168fd10880SBen Widawsky 
28178fd10880SBen Widawsky /*
28188fd10880SBen Widawsky  * DSM may return multiple types depending on the function. It is therefore
28198fd10880SBen Widawsky  * unsafe to use the typed evaluation. It is highly recommended that the caller
28208fd10880SBen Widawsky  * check the type of the returned object.
28218fd10880SBen Widawsky  */
28228fd10880SBen Widawsky ACPI_STATUS
2823fe64ff3cSVladimir Kondratyev acpi_EvaluateDSM(ACPI_HANDLE handle, const uint8_t *uuid, int revision,
2824fe64ff3cSVladimir Kondratyev     UINT64 function, ACPI_OBJECT *package, ACPI_BUFFER *out_buf)
2825fe64ff3cSVladimir Kondratyev {
2826fe64ff3cSVladimir Kondratyev 	return (acpi_EvaluateDSMTyped(handle, uuid, revision, function,
2827fe64ff3cSVladimir Kondratyev 	    package, out_buf, ACPI_TYPE_ANY));
2828fe64ff3cSVladimir Kondratyev }
2829fe64ff3cSVladimir Kondratyev 
2830fe64ff3cSVladimir Kondratyev ACPI_STATUS
2831fe64ff3cSVladimir Kondratyev acpi_EvaluateDSMTyped(ACPI_HANDLE handle, const uint8_t *uuid, int revision,
2832fe64ff3cSVladimir Kondratyev     UINT64 function, ACPI_OBJECT *package, ACPI_BUFFER *out_buf,
2833fe64ff3cSVladimir Kondratyev     ACPI_OBJECT_TYPE type)
28348fd10880SBen Widawsky {
28358fd10880SBen Widawsky     ACPI_OBJECT arg[4];
28368fd10880SBen Widawsky     ACPI_OBJECT_LIST arglist;
28378fd10880SBen Widawsky     ACPI_BUFFER buf;
28388fd10880SBen Widawsky     ACPI_STATUS status;
28398fd10880SBen Widawsky 
28408fd10880SBen Widawsky     if (out_buf == NULL)
28418fd10880SBen Widawsky 	return (AE_NO_MEMORY);
28428fd10880SBen Widawsky 
28438fd10880SBen Widawsky     arg[0].Type = ACPI_TYPE_BUFFER;
28448fd10880SBen Widawsky     arg[0].Buffer.Length = ACPI_UUID_LENGTH;
2845fe64ff3cSVladimir Kondratyev     arg[0].Buffer.Pointer = __DECONST(uint8_t *, uuid);
28468fd10880SBen Widawsky     arg[1].Type = ACPI_TYPE_INTEGER;
28478fd10880SBen Widawsky     arg[1].Integer.Value = revision;
28488fd10880SBen Widawsky     arg[2].Type = ACPI_TYPE_INTEGER;
28498fd10880SBen Widawsky     arg[2].Integer.Value = function;
28508fd10880SBen Widawsky     if (package) {
28518fd10880SBen Widawsky 	arg[3] = *package;
28528fd10880SBen Widawsky     } else {
28538fd10880SBen Widawsky 	arg[3].Type = ACPI_TYPE_PACKAGE;
28548fd10880SBen Widawsky 	arg[3].Package.Count = 0;
28558fd10880SBen Widawsky 	arg[3].Package.Elements = NULL;
28568fd10880SBen Widawsky     }
28578fd10880SBen Widawsky 
28588fd10880SBen Widawsky     arglist.Pointer = arg;
28598fd10880SBen Widawsky     arglist.Count = 4;
28608fd10880SBen Widawsky     buf.Pointer = NULL;
28618fd10880SBen Widawsky     buf.Length = ACPI_ALLOCATE_BUFFER;
2862fe64ff3cSVladimir Kondratyev     status = AcpiEvaluateObjectTyped(handle, "_DSM", &arglist, &buf, type);
28638fd10880SBen Widawsky     if (ACPI_FAILURE(status))
28648fd10880SBen Widawsky 	return (status);
28658fd10880SBen Widawsky 
28668fd10880SBen Widawsky     KASSERT(ACPI_SUCCESS(status), ("Unexpected status"));
28678fd10880SBen Widawsky 
28688fd10880SBen Widawsky     *out_buf = buf;
28698fd10880SBen Widawsky     return (status);
28708fd10880SBen Widawsky }
28718fd10880SBen Widawsky 
28725f3dd91aSJohn Baldwin ACPI_STATUS
28735f3dd91aSJohn Baldwin acpi_EvaluateOSC(ACPI_HANDLE handle, uint8_t *uuid, int revision, int count,
28744c26ac69SJohn Baldwin     uint32_t *caps_in, uint32_t *caps_out, bool query)
28755f3dd91aSJohn Baldwin {
28764c26ac69SJohn Baldwin 	ACPI_OBJECT arg[4], *ret;
28775f3dd91aSJohn Baldwin 	ACPI_OBJECT_LIST arglist;
28784c26ac69SJohn Baldwin 	ACPI_BUFFER buf;
28794c26ac69SJohn Baldwin 	ACPI_STATUS status;
28805f3dd91aSJohn Baldwin 
28815f3dd91aSJohn Baldwin 	arglist.Pointer = arg;
28825f3dd91aSJohn Baldwin 	arglist.Count = 4;
28835f3dd91aSJohn Baldwin 	arg[0].Type = ACPI_TYPE_BUFFER;
28845f3dd91aSJohn Baldwin 	arg[0].Buffer.Length = ACPI_UUID_LENGTH;
28855f3dd91aSJohn Baldwin 	arg[0].Buffer.Pointer = uuid;
28865f3dd91aSJohn Baldwin 	arg[1].Type = ACPI_TYPE_INTEGER;
28875f3dd91aSJohn Baldwin 	arg[1].Integer.Value = revision;
28885f3dd91aSJohn Baldwin 	arg[2].Type = ACPI_TYPE_INTEGER;
28895f3dd91aSJohn Baldwin 	arg[2].Integer.Value = count;
28905f3dd91aSJohn Baldwin 	arg[3].Type = ACPI_TYPE_BUFFER;
28914c26ac69SJohn Baldwin 	arg[3].Buffer.Length = count * sizeof(*caps_in);
28924c26ac69SJohn Baldwin 	arg[3].Buffer.Pointer = (uint8_t *)caps_in;
28934c26ac69SJohn Baldwin 	caps_in[0] = query ? 1 : 0;
28944c26ac69SJohn Baldwin 	buf.Pointer = NULL;
28954c26ac69SJohn Baldwin 	buf.Length = ACPI_ALLOCATE_BUFFER;
28964c26ac69SJohn Baldwin 	status = AcpiEvaluateObjectTyped(handle, "_OSC", &arglist, &buf,
28974c26ac69SJohn Baldwin 	    ACPI_TYPE_BUFFER);
28984c26ac69SJohn Baldwin 	if (ACPI_FAILURE(status))
28994c26ac69SJohn Baldwin 		return (status);
29004c26ac69SJohn Baldwin 	if (caps_out != NULL) {
29014c26ac69SJohn Baldwin 		ret = buf.Pointer;
29024c26ac69SJohn Baldwin 		if (ret->Buffer.Length != count * sizeof(*caps_out)) {
29034c26ac69SJohn Baldwin 			AcpiOsFree(buf.Pointer);
29044c26ac69SJohn Baldwin 			return (AE_BUFFER_OVERFLOW);
29054c26ac69SJohn Baldwin 		}
29064c26ac69SJohn Baldwin 		bcopy(ret->Buffer.Pointer, caps_out, ret->Buffer.Length);
29074c26ac69SJohn Baldwin 	}
29084c26ac69SJohn Baldwin 	AcpiOsFree(buf.Pointer);
29094c26ac69SJohn Baldwin 	return (status);
29105f3dd91aSJohn Baldwin }
29115f3dd91aSJohn Baldwin 
2912da14ac9fSJohn Baldwin /*
2913da14ac9fSJohn Baldwin  * Set interrupt model.
2914da14ac9fSJohn Baldwin  */
2915da14ac9fSJohn Baldwin ACPI_STATUS
2916da14ac9fSJohn Baldwin acpi_SetIntrModel(int model)
2917da14ac9fSJohn Baldwin {
2918da14ac9fSJohn Baldwin 
2919c310653eSNate Lawson     return (acpi_SetInteger(ACPI_ROOT_OBJECT, "_PIC", model));
2920da14ac9fSJohn Baldwin }
2921da14ac9fSJohn Baldwin 
292200a30448SNate Lawson /*
2923d95e7f5aSJohn Baldwin  * Walk subtables of a table and call a callback routine for each
2924d95e7f5aSJohn Baldwin  * subtable.  The caller should provide the first subtable and a
2925d95e7f5aSJohn Baldwin  * pointer to the end of the table.  This can be used to walk tables
2926d95e7f5aSJohn Baldwin  * such as MADT and SRAT that use subtable entries.
2927d95e7f5aSJohn Baldwin  */
2928d95e7f5aSJohn Baldwin void
2929d95e7f5aSJohn Baldwin acpi_walk_subtables(void *first, void *end, acpi_subtable_handler *handler,
2930d95e7f5aSJohn Baldwin     void *arg)
2931d95e7f5aSJohn Baldwin {
2932d95e7f5aSJohn Baldwin     ACPI_SUBTABLE_HEADER *entry;
2933d95e7f5aSJohn Baldwin 
2934d95e7f5aSJohn Baldwin     for (entry = first; (void *)entry < end; ) {
2935d95e7f5aSJohn Baldwin 	/* Avoid an infinite loop if we hit a bogus entry. */
2936d95e7f5aSJohn Baldwin 	if (entry->Length < sizeof(ACPI_SUBTABLE_HEADER))
2937d95e7f5aSJohn Baldwin 	    return;
2938d95e7f5aSJohn Baldwin 
2939d95e7f5aSJohn Baldwin 	handler(entry, arg);
2940d95e7f5aSJohn Baldwin 	entry = ACPI_ADD_PTR(ACPI_SUBTABLE_HEADER, entry, entry->Length);
2941d95e7f5aSJohn Baldwin     }
2942d95e7f5aSJohn Baldwin }
2943d95e7f5aSJohn Baldwin 
2944d95e7f5aSJohn Baldwin /*
294500a30448SNate Lawson  * DEPRECATED.  This interface has serious deficiencies and will be
294600a30448SNate Lawson  * removed.
294700a30448SNate Lawson  *
294800a30448SNate Lawson  * Immediately enter the sleep state.  In the old model, acpiconf(8) ran
294900a30448SNate Lawson  * rc.suspend and rc.resume so we don't have to notify devd(8) to do this.
295000a30448SNate Lawson  */
295100a30448SNate Lawson ACPI_STATUS
295200a30448SNate Lawson acpi_SetSleepState(struct acpi_softc *sc, int state)
295300a30448SNate Lawson {
295400a30448SNate Lawson     static int once;
295500a30448SNate Lawson 
295600a30448SNate Lawson     if (!once) {
29572d0c82e8SJung-uk Kim 	device_printf(sc->acpi_dev,
295800a30448SNate Lawson "warning: acpi_SetSleepState() deprecated, need to update your software\n");
295900a30448SNate Lawson 	once = 1;
296000a30448SNate Lawson     }
296100a30448SNate Lawson     return (acpi_EnterSleepState(sc, state));
296200a30448SNate Lawson }
296300a30448SNate Lawson 
2964c66d2b38SJung-uk Kim #if defined(__amd64__) || defined(__i386__)
296500a30448SNate Lawson static void
2966ffe3f1f8SMitsuru IWASAKI acpi_sleep_force_task(void *context)
2967ffe3f1f8SMitsuru IWASAKI {
2968ffe3f1f8SMitsuru IWASAKI     struct acpi_softc *sc = (struct acpi_softc *)context;
2969ffe3f1f8SMitsuru IWASAKI 
2970ffe3f1f8SMitsuru IWASAKI     if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_sstate)))
2971ffe3f1f8SMitsuru IWASAKI 	device_printf(sc->acpi_dev, "force sleep state S%d failed\n",
2972ffe3f1f8SMitsuru IWASAKI 	    sc->acpi_next_sstate);
2973ffe3f1f8SMitsuru IWASAKI }
2974ffe3f1f8SMitsuru IWASAKI 
2975ffe3f1f8SMitsuru IWASAKI static void
297600a30448SNate Lawson acpi_sleep_force(void *arg)
297700a30448SNate Lawson {
29782d0c82e8SJung-uk Kim     struct acpi_softc *sc = (struct acpi_softc *)arg;
297900a30448SNate Lawson 
29802d0c82e8SJung-uk Kim     device_printf(sc->acpi_dev,
29812d0c82e8SJung-uk Kim 	"suspend request timed out, forcing sleep now\n");
2982ffe3f1f8SMitsuru IWASAKI     /*
2983fadf3fb9SJohn Baldwin      * XXX Suspending from callout causes freezes in DEVICE_SUSPEND().
2984ffe3f1f8SMitsuru IWASAKI      * Suspend from acpi_task thread instead.
2985ffe3f1f8SMitsuru IWASAKI      */
2986ffe3f1f8SMitsuru IWASAKI     if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER,
2987ffe3f1f8SMitsuru IWASAKI 	acpi_sleep_force_task, sc)))
2988ffe3f1f8SMitsuru IWASAKI 	device_printf(sc->acpi_dev, "AcpiOsExecute() for sleeping failed\n");
298900a30448SNate Lawson }
2990c66d2b38SJung-uk Kim #endif
299100a30448SNate Lawson 
299200a30448SNate Lawson /*
299300a30448SNate Lawson  * Request that the system enter the given suspend state.  All /dev/apm
299400a30448SNate Lawson  * devices and devd(8) will be notified.  Userland then has a chance to
299500a30448SNate Lawson  * save state and acknowledge the request.  The system sleeps once all
299600a30448SNate Lawson  * acks are in.
299700a30448SNate Lawson  */
299800a30448SNate Lawson int
299900a30448SNate Lawson acpi_ReqSleepState(struct acpi_softc *sc, int state)
300000a30448SNate Lawson {
300171f99e63SJung-uk Kim #if defined(__amd64__) || defined(__i386__)
300200a30448SNate Lawson     struct apm_clone_data *clone;
3003337744d9SJung-uk Kim     ACPI_STATUS status;
300400a30448SNate Lawson 
3005a0e73a12SJung-uk Kim     if (state < ACPI_STATE_S1 || state > ACPI_S_STATES_MAX)
300600a30448SNate Lawson 	return (EINVAL);
3007a0e73a12SJung-uk Kim     if (!acpi_sleep_states[state])
3008a0e73a12SJung-uk Kim 	return (EOPNOTSUPP);
300900a30448SNate Lawson 
30102eb0015aSColin Percival     /*
30112eb0015aSColin Percival      * If a reboot/shutdown/suspend request is already in progress or
30122eb0015aSColin Percival      * suspend is blocked due to an upcoming shutdown, just return.
30132eb0015aSColin Percival      */
30142eb0015aSColin Percival     if (rebooting || sc->acpi_next_sstate != 0 || suspend_blocked) {
3015b12bc99fSMitsuru IWASAKI 	return (0);
3016b12bc99fSMitsuru IWASAKI     }
3017b12bc99fSMitsuru IWASAKI 
3018f22377a8SMitsuru IWASAKI     /* Wait until sleep is enabled. */
3019f22377a8SMitsuru IWASAKI     while (sc->acpi_sleep_disabled) {
3020f22377a8SMitsuru IWASAKI 	AcpiOsSleep(1000);
3021f22377a8SMitsuru IWASAKI     }
3022f22377a8SMitsuru IWASAKI 
3023337744d9SJung-uk Kim     ACPI_LOCK(acpi);
302400a30448SNate Lawson 
3025f22377a8SMitsuru IWASAKI     sc->acpi_next_sstate = state;
302600a30448SNate Lawson 
3027337744d9SJung-uk Kim     /* S5 (soft-off) should be entered directly with no waiting. */
3028337744d9SJung-uk Kim     if (state == ACPI_STATE_S5) {
3029337744d9SJung-uk Kim     	ACPI_UNLOCK(acpi);
3030337744d9SJung-uk Kim 	status = acpi_EnterSleepState(sc, state);
3031337744d9SJung-uk Kim 	return (ACPI_SUCCESS(status) ? 0 : ENXIO);
3032337744d9SJung-uk Kim     }
3033337744d9SJung-uk Kim 
303400a30448SNate Lawson     /* Record the pending state and notify all apm devices. */
303500a30448SNate Lawson     STAILQ_FOREACH(clone, &sc->apm_cdevs, entries) {
303600a30448SNate Lawson 	clone->notify_status = APM_EV_NONE;
303700a30448SNate Lawson 	if ((clone->flags & ACPI_EVF_DEVD) == 0) {
303800a30448SNate Lawson 	    selwakeuppri(&clone->sel_read, PZERO);
3039374d9c4dSJohn Baldwin 	    KNOTE_LOCKED(&clone->sel_read.si_note, 0);
304000a30448SNate Lawson 	}
304100a30448SNate Lawson     }
304200a30448SNate Lawson 
30430c26519eSMitsuru IWASAKI     /* If devd(8) is not running, immediately enter the sleep state. */
3044d42f0ad8SJung-uk Kim     if (!devctl_process_running()) {
30450c26519eSMitsuru IWASAKI 	ACPI_UNLOCK(acpi);
3046337744d9SJung-uk Kim 	status = acpi_EnterSleepState(sc, state);
3047337744d9SJung-uk Kim 	return (ACPI_SUCCESS(status) ? 0 : ENXIO);
30480c26519eSMitsuru IWASAKI     }
30490c26519eSMitsuru IWASAKI 
305000a30448SNate Lawson     /*
305100a30448SNate Lawson      * Set a timeout to fire if userland doesn't ack the suspend request
305200a30448SNate Lawson      * in time.  This way we still eventually go to sleep if we were
305300a30448SNate Lawson      * overheating or running low on battery, even if userland is hung.
305400a30448SNate Lawson      * We cancel this timeout once all userland acks are in or the
305500a30448SNate Lawson      * suspend request is aborted.
305600a30448SNate Lawson      */
305700a30448SNate Lawson     callout_reset(&sc->susp_force_to, 10 * hz, acpi_sleep_force, sc);
305800a30448SNate Lawson     ACPI_UNLOCK(acpi);
3059d42f0ad8SJung-uk Kim 
3060d42f0ad8SJung-uk Kim     /* Now notify devd(8) also. */
3061d42f0ad8SJung-uk Kim     acpi_UserNotify("Suspend", ACPI_ROOT_OBJECT, state);
3062d42f0ad8SJung-uk Kim 
306300a30448SNate Lawson     return (0);
3064c66d2b38SJung-uk Kim #else
3065c66d2b38SJung-uk Kim     /* This platform does not support acpi suspend/resume. */
3066c66d2b38SJung-uk Kim     return (EOPNOTSUPP);
3067c66d2b38SJung-uk Kim #endif
306800a30448SNate Lawson }
306900a30448SNate Lawson 
307000a30448SNate Lawson /*
307100a30448SNate Lawson  * Acknowledge (or reject) a pending sleep state.  The caller has
307200a30448SNate Lawson  * prepared for suspend and is now ready for it to proceed.  If the
307300a30448SNate Lawson  * error argument is non-zero, it indicates suspend should be cancelled
307400a30448SNate Lawson  * and gives an errno value describing why.  Once all votes are in,
307500a30448SNate Lawson  * we suspend the system.
307600a30448SNate Lawson  */
307700a30448SNate Lawson int
307800a30448SNate Lawson acpi_AckSleepState(struct apm_clone_data *clone, int error)
307900a30448SNate Lawson {
3080c66d2b38SJung-uk Kim #if defined(__amd64__) || defined(__i386__)
308100a30448SNate Lawson     struct acpi_softc *sc;
308200a30448SNate Lawson     int ret, sleeping;
308300a30448SNate Lawson 
308400a30448SNate Lawson     /* If no pending sleep state, return an error. */
308500a30448SNate Lawson     ACPI_LOCK(acpi);
308600a30448SNate Lawson     sc = clone->acpi_sc;
308700a30448SNate Lawson     if (sc->acpi_next_sstate == 0) {
308800a30448SNate Lawson     	ACPI_UNLOCK(acpi);
308900a30448SNate Lawson 	return (ENXIO);
309000a30448SNate Lawson     }
309100a30448SNate Lawson 
309200a30448SNate Lawson     /* Caller wants to abort suspend process. */
309300a30448SNate Lawson     if (error) {
309400a30448SNate Lawson 	sc->acpi_next_sstate = 0;
309500a30448SNate Lawson 	callout_stop(&sc->susp_force_to);
30962d0c82e8SJung-uk Kim 	device_printf(sc->acpi_dev,
30972d0c82e8SJung-uk Kim 	    "listener on %s cancelled the pending suspend\n",
309800a30448SNate Lawson 	    devtoname(clone->cdev));
309900a30448SNate Lawson     	ACPI_UNLOCK(acpi);
310000a30448SNate Lawson 	return (0);
310100a30448SNate Lawson     }
310200a30448SNate Lawson 
310300a30448SNate Lawson     /*
310400a30448SNate Lawson      * Mark this device as acking the suspend request.  Then, walk through
310500a30448SNate Lawson      * all devices, seeing if they agree yet.  We only count devices that
310600a30448SNate Lawson      * are writable since read-only devices couldn't ack the request.
310700a30448SNate Lawson      */
310800a30448SNate Lawson     sleeping = TRUE;
3109c66d2b38SJung-uk Kim     clone->notify_status = APM_EV_ACKED;
311000a30448SNate Lawson     STAILQ_FOREACH(clone, &sc->apm_cdevs, entries) {
311100a30448SNate Lawson 	if ((clone->flags & ACPI_EVF_WRITE) != 0 &&
311200a30448SNate Lawson 	    clone->notify_status != APM_EV_ACKED) {
311300a30448SNate Lawson 	    sleeping = FALSE;
311400a30448SNate Lawson 	    break;
311500a30448SNate Lawson 	}
311600a30448SNate Lawson     }
311700a30448SNate Lawson 
311800a30448SNate Lawson     /* If all devices have voted "yes", we will suspend now. */
311900a30448SNate Lawson     if (sleeping)
312000a30448SNate Lawson 	callout_stop(&sc->susp_force_to);
312100a30448SNate Lawson     ACPI_UNLOCK(acpi);
312200a30448SNate Lawson     ret = 0;
312300a30448SNate Lawson     if (sleeping) {
312400a30448SNate Lawson 	if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_sstate)))
312500a30448SNate Lawson 		ret = ENODEV;
312600a30448SNate Lawson     }
312700a30448SNate Lawson     return (ret);
3128c66d2b38SJung-uk Kim #else
3129c66d2b38SJung-uk Kim     /* This platform does not support acpi suspend/resume. */
3130c66d2b38SJung-uk Kim     return (EOPNOTSUPP);
3131c66d2b38SJung-uk Kim #endif
313200a30448SNate Lawson }
313300a30448SNate Lawson 
3134ece50487SMitsuru IWASAKI static void
3135ece50487SMitsuru IWASAKI acpi_sleep_enable(void *arg)
3136ece50487SMitsuru IWASAKI {
3137d42f0ad8SJung-uk Kim     struct acpi_softc	*sc = (struct acpi_softc *)arg;
3138bee4aa4aSNate Lawson 
3139fadf3fb9SJohn Baldwin     ACPI_LOCK_ASSERT(acpi);
3140fadf3fb9SJohn Baldwin 
3141a0e73a12SJung-uk Kim     /* Reschedule if the system is not fully up and running. */
3142a0e73a12SJung-uk Kim     if (!AcpiGbl_SystemAwakeAndRunning) {
3143fadf3fb9SJohn Baldwin 	callout_schedule(&acpi_sleep_timer, hz * ACPI_MINIMUM_AWAKETIME);
3144a0e73a12SJung-uk Kim 	return;
3145a0e73a12SJung-uk Kim     }
3146a0e73a12SJung-uk Kim 
3147a0e73a12SJung-uk Kim     sc->acpi_sleep_disabled = FALSE;
3148d42f0ad8SJung-uk Kim }
3149d42f0ad8SJung-uk Kim 
3150d42f0ad8SJung-uk Kim static ACPI_STATUS
3151d42f0ad8SJung-uk Kim acpi_sleep_disable(struct acpi_softc *sc)
3152d42f0ad8SJung-uk Kim {
3153d42f0ad8SJung-uk Kim     ACPI_STATUS		status;
3154d42f0ad8SJung-uk Kim 
3155a0e73a12SJung-uk Kim     /* Fail if the system is not fully up and running. */
3156a0e73a12SJung-uk Kim     if (!AcpiGbl_SystemAwakeAndRunning)
3157a0e73a12SJung-uk Kim 	return (AE_ERROR);
3158a0e73a12SJung-uk Kim 
3159d42f0ad8SJung-uk Kim     ACPI_LOCK(acpi);
3160d42f0ad8SJung-uk Kim     status = sc->acpi_sleep_disabled ? AE_ERROR : AE_OK;
3161a0e73a12SJung-uk Kim     sc->acpi_sleep_disabled = TRUE;
3162d42f0ad8SJung-uk Kim     ACPI_UNLOCK(acpi);
3163d42f0ad8SJung-uk Kim 
3164d42f0ad8SJung-uk Kim     return (status);
3165ece50487SMitsuru IWASAKI }
3166c30382dfSMitsuru IWASAKI 
316715e2f34fSNate Lawson enum acpi_sleep_state {
316815e2f34fSNate Lawson     ACPI_SS_NONE,
316915e2f34fSNate Lawson     ACPI_SS_GPE_SET,
317015e2f34fSNate Lawson     ACPI_SS_DEV_SUSPEND,
317115e2f34fSNate Lawson     ACPI_SS_SLP_PREP,
317215e2f34fSNate Lawson     ACPI_SS_SLEPT,
317315e2f34fSNate Lawson };
317415e2f34fSNate Lawson 
317515e32d5dSMike Smith /*
317600a30448SNate Lawson  * Enter the desired system sleep state.
317715e32d5dSMike Smith  *
3178be2b1797SNate Lawson  * Currently we support S1-S5 but S4 is only S4BIOS
317915e32d5dSMike Smith  */
318000a30448SNate Lawson static ACPI_STATUS
318100a30448SNate Lawson acpi_EnterSleepState(struct acpi_softc *sc, int state)
318215e32d5dSMike Smith {
318371804adcSJung-uk Kim     register_t intr;
318415e2f34fSNate Lawson     ACPI_STATUS status;
3185b913a7d5SAndriy Gapon     ACPI_EVENT_STATUS power_button_status;
318615e2f34fSNate Lawson     enum acpi_sleep_state slp_state;
3187f0a101b7SMitsuru IWASAKI     int sleep_result;
318815e32d5dSMike Smith 
3189b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
31900ae55423SMike Smith 
3191a0e73a12SJung-uk Kim     if (state < ACPI_STATE_S1 || state > ACPI_S_STATES_MAX)
319233c70d41SAndriy Gapon 	return_ACPI_STATUS (AE_BAD_PARAMETER);
3193a0e73a12SJung-uk Kim     if (!acpi_sleep_states[state]) {
3194a0e73a12SJung-uk Kim 	device_printf(sc->acpi_dev, "Sleep state S%d not supported by BIOS\n",
3195a0e73a12SJung-uk Kim 	    state);
3196a0e73a12SJung-uk Kim 	return (AE_SUPPORT);
3197a0e73a12SJung-uk Kim     }
3198a0e73a12SJung-uk Kim 
3199a0e73a12SJung-uk Kim     /* Re-entry once we're suspending is not allowed. */
3200a0e73a12SJung-uk Kim     status = acpi_sleep_disable(sc);
3201a0e73a12SJung-uk Kim     if (ACPI_FAILURE(status)) {
3202a0e73a12SJung-uk Kim 	device_printf(sc->acpi_dev,
3203a0e73a12SJung-uk Kim 	    "suspend request ignored (not ready yet)\n");
3204a0e73a12SJung-uk Kim 	return (status);
3205a0e73a12SJung-uk Kim     }
320633c70d41SAndriy Gapon 
320733c70d41SAndriy Gapon     if (state == ACPI_STATE_S5) {
320833c70d41SAndriy Gapon 	/*
320933c70d41SAndriy Gapon 	 * Shut down cleanly and power off.  This will call us back through the
321033c70d41SAndriy Gapon 	 * shutdown handlers.
321133c70d41SAndriy Gapon 	 */
321233c70d41SAndriy Gapon 	shutdown_nice(RB_POWEROFF);
321333c70d41SAndriy Gapon 	return_ACPI_STATUS (AE_OK);
321433c70d41SAndriy Gapon     }
321533c70d41SAndriy Gapon 
321685f95fffSAndriy Gapon     EVENTHANDLER_INVOKE(power_suspend_early);
321785f95fffSAndriy Gapon     stop_all_proc();
3218f1084587SKonstantin Belousov     suspend_all_fs();
32194a8fa6feSJung-uk Kim     EVENTHANDLER_INVOKE(power_suspend);
32204a8fa6feSJung-uk Kim 
3221fdce57a0SJohn Baldwin #ifdef EARLY_AP_STARTUP
3222fdce57a0SJohn Baldwin     MPASS(mp_ncpus == 1 || smp_started);
3223fdce57a0SJohn Baldwin     thread_lock(curthread);
3224fdce57a0SJohn Baldwin     sched_bind(curthread, 0);
3225fdce57a0SJohn Baldwin     thread_unlock(curthread);
3226fdce57a0SJohn Baldwin #else
322736a483bbSJung-uk Kim     if (smp_started) {
3228c66d2b38SJung-uk Kim 	thread_lock(curthread);
3229c66d2b38SJung-uk Kim 	sched_bind(curthread, 0);
3230c66d2b38SJung-uk Kim 	thread_unlock(curthread);
323136a483bbSJung-uk Kim     }
3232fdce57a0SJohn Baldwin #endif
3233c66d2b38SJung-uk Kim 
3234a56fe095SJohn Baldwin     /*
3235a56fe095SJohn Baldwin      * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE
3236a56fe095SJohn Baldwin      * drivers need this.
3237a56fe095SJohn Baldwin      */
3238a56fe095SJohn Baldwin     mtx_lock(&Giant);
3239c66d2b38SJung-uk Kim 
324015e2f34fSNate Lawson     slp_state = ACPI_SS_NONE;
324156d8cb57SMitsuru IWASAKI 
3242a1fccb47SMitsuru IWASAKI     sc->acpi_sstate = state;
3243a1fccb47SMitsuru IWASAKI 
3244d4b9ff91SNate Lawson     /* Enable any GPEs as appropriate and requested by the user. */
3245d4b9ff91SNate Lawson     acpi_wake_prep_walk(state);
324615e2f34fSNate Lawson     slp_state = ACPI_SS_GPE_SET;
3247e8b4d56eSNate Lawson 
324815e32d5dSMike Smith     /*
3249c7f88fc3SNate Lawson      * Inform all devices that we are going to sleep.  If at least one
3250c7f88fc3SNate Lawson      * device fails, DEVICE_SUSPEND() automatically resumes the tree.
325115e32d5dSMike Smith      *
3252c7f88fc3SNate Lawson      * XXX Note that a better two-pass approach with a 'veto' pass
3253c7f88fc3SNate Lawson      * followed by a "real thing" pass would be better, but the current
3254c7f88fc3SNate Lawson      * bus interface does not provide for this.
325515e32d5dSMike Smith      */
325615e2f34fSNate Lawson     if (DEVICE_SUSPEND(root_bus) != 0) {
325715e2f34fSNate Lawson 	device_printf(sc->acpi_dev, "device_suspend failed\n");
325833c70d41SAndriy Gapon 	goto backout;
325915e2f34fSNate Lawson     }
326015e2f34fSNate Lawson     slp_state = ACPI_SS_DEV_SUSPEND;
3261b9c780d6SMitsuru IWASAKI 
3262be2b1797SNate Lawson     status = AcpiEnterSleepStatePrep(state);
3263be2b1797SNate Lawson     if (ACPI_FAILURE(status)) {
3264b9c780d6SMitsuru IWASAKI 	device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n",
3265b9c780d6SMitsuru IWASAKI 		      AcpiFormatException(status));
326633c70d41SAndriy Gapon 	goto backout;
3267b9c780d6SMitsuru IWASAKI     }
326815e2f34fSNate Lawson     slp_state = ACPI_SS_SLP_PREP;
3269b9c780d6SMitsuru IWASAKI 
3270be2b1797SNate Lawson     if (sc->acpi_sleep_delay > 0)
3271ff01efb5SMitsuru IWASAKI 	DELAY(sc->acpi_sleep_delay * 1000000);
3272ff01efb5SMitsuru IWASAKI 
327327dca831SAndriy Gapon     suspendclock();
3274f0a101b7SMitsuru IWASAKI     intr = intr_disable();
32754d46ef51SJung-uk Kim     if (state != ACPI_STATE_S1) {
3276f0a101b7SMitsuru IWASAKI 	sleep_result = acpi_sleep_machdep(sc, state);
3277f0a101b7SMitsuru IWASAKI 	acpi_wakeup_machdep(sc, state, sleep_result, 0);
3278b1a5c017SAndriy Gapon 
3279b1a5c017SAndriy Gapon 	/*
3280b1a5c017SAndriy Gapon 	 * XXX According to ACPI specification SCI_EN bit should be restored
3281b1a5c017SAndriy Gapon 	 * by ACPI platform (BIOS, firmware) to its pre-sleep state.
3282b1a5c017SAndriy Gapon 	 * Unfortunately some BIOSes fail to do that and that leads to
3283b1a5c017SAndriy Gapon 	 * unexpected and serious consequences during wake up like a system
3284b1a5c017SAndriy Gapon 	 * getting stuck in SMI handlers.
3285b1a5c017SAndriy Gapon 	 * This hack is picked up from Linux, which claims that it follows
3286b1a5c017SAndriy Gapon 	 * Windows behavior.
3287b1a5c017SAndriy Gapon 	 */
3288b1a5c017SAndriy Gapon 	if (sleep_result == 1 && state != ACPI_STATE_S4)
3289b1a5c017SAndriy Gapon 	    AcpiWriteBitRegister(ACPI_BITREG_SCI_ENABLE, ACPI_ENABLE_EVENT);
3290b1a5c017SAndriy Gapon 
3291b913a7d5SAndriy Gapon 	if (sleep_result == 1 && state == ACPI_STATE_S3) {
3292b913a7d5SAndriy Gapon 	    /*
3293b913a7d5SAndriy Gapon 	     * Prevent mis-interpretation of the wakeup by power button
3294b913a7d5SAndriy Gapon 	     * as a request for power off.
3295b913a7d5SAndriy Gapon 	     * Ideally we should post an appropriate wakeup event,
3296b913a7d5SAndriy Gapon 	     * perhaps using acpi_event_power_button_wake or alike.
3297b913a7d5SAndriy Gapon 	     *
3298b913a7d5SAndriy Gapon 	     * Clearing of power button status after wakeup is mandated
3299b913a7d5SAndriy Gapon 	     * by ACPI specification in section "Fixed Power Button".
3300b913a7d5SAndriy Gapon 	     *
3301b913a7d5SAndriy Gapon 	     * XXX As of ACPICA 20121114 AcpiGetEventStatus provides
3302b913a7d5SAndriy Gapon 	     * status as 0/1 corressponding to inactive/active despite
3303b913a7d5SAndriy Gapon 	     * its type being ACPI_EVENT_STATUS.  In other words,
3304b913a7d5SAndriy Gapon 	     * we should not test for ACPI_EVENT_FLAG_SET for time being.
3305b913a7d5SAndriy Gapon 	     */
3306b913a7d5SAndriy Gapon 	    if (ACPI_SUCCESS(AcpiGetEventStatus(ACPI_EVENT_POWER_BUTTON,
3307b913a7d5SAndriy Gapon 		&power_button_status)) && power_button_status != 0) {
3308b913a7d5SAndriy Gapon 		AcpiClearEvent(ACPI_EVENT_POWER_BUTTON);
3309b913a7d5SAndriy Gapon 		device_printf(sc->acpi_dev,
3310b913a7d5SAndriy Gapon 		    "cleared fixed power button status\n");
3311b913a7d5SAndriy Gapon 	    }
3312b913a7d5SAndriy Gapon 	}
3313b913a7d5SAndriy Gapon 
3314f0a101b7SMitsuru IWASAKI 	intr_restore(intr);
3315f0a101b7SMitsuru IWASAKI 
3316f0a101b7SMitsuru IWASAKI 	/* call acpi_wakeup_machdep() again with interrupt enabled */
3317f0a101b7SMitsuru IWASAKI 	acpi_wakeup_machdep(sc, state, sleep_result, 1);
3318f0a101b7SMitsuru IWASAKI 
33190a15ff37SAndriy Gapon 	AcpiLeaveSleepStatePrep(state);
33200a15ff37SAndriy Gapon 
3321f0a101b7SMitsuru IWASAKI 	if (sleep_result == -1)
3322a159c266SJung-uk Kim 		goto backout;
33236161544cSTakanori Watanabe 
33246161544cSTakanori Watanabe 	/* Re-enable ACPI hardware on wakeup from sleep state 4. */
3325be2b1797SNate Lawson 	if (state == ACPI_STATE_S4)
3326964679ceSMitsuru IWASAKI 	    AcpiEnable();
33276161544cSTakanori Watanabe     } else {
33281df130f1SJung-uk Kim 	status = AcpiEnterSleepState(state);
332971804adcSJung-uk Kim 	intr_restore(intr);
33300a15ff37SAndriy Gapon 	AcpiLeaveSleepStatePrep(state);
3331be2b1797SNate Lawson 	if (ACPI_FAILURE(status)) {
3332be2b1797SNate Lawson 	    device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n",
3333be2b1797SNate Lawson 			  AcpiFormatException(status));
333433c70d41SAndriy Gapon 	    goto backout;
333515e32d5dSMike Smith 	}
33366161544cSTakanori Watanabe     }
333715e2f34fSNate Lawson     slp_state = ACPI_SS_SLEPT;
3338ece50487SMitsuru IWASAKI 
333915e2f34fSNate Lawson     /*
334015e2f34fSNate Lawson      * Back out state according to how far along we got in the suspend
334115e2f34fSNate Lawson      * process.  This handles both the error and success cases.
334215e2f34fSNate Lawson      */
334333c70d41SAndriy Gapon backout:
334427dca831SAndriy Gapon     if (slp_state >= ACPI_SS_SLP_PREP)
334527dca831SAndriy Gapon 	resumeclock();
334615e2f34fSNate Lawson     if (slp_state >= ACPI_SS_GPE_SET) {
334715e2f34fSNate Lawson 	acpi_wake_prep_walk(state);
334815e2f34fSNate Lawson 	sc->acpi_sstate = ACPI_STATE_S0;
334915e2f34fSNate Lawson     }
3350e3b56b66SMitsuru IWASAKI     if (slp_state >= ACPI_SS_DEV_SUSPEND)
3351e3b56b66SMitsuru IWASAKI 	DEVICE_RESUME(root_bus);
3352f0a101b7SMitsuru IWASAKI     if (slp_state >= ACPI_SS_SLP_PREP)
335315e2f34fSNate Lawson 	AcpiLeaveSleepState(state);
3354a0a15716SJung-uk Kim     if (slp_state >= ACPI_SS_SLEPT) {
3355279be68bSAndriy Gapon #if defined(__i386__) || defined(__amd64__)
3356279be68bSAndriy Gapon 	/* NB: we are still using ACPI timecounter at this point. */
3357279be68bSAndriy Gapon 	resume_TSC();
3358279be68bSAndriy Gapon #endif
3359a0a15716SJung-uk Kim 	acpi_resync_clock(sc);
336015e2f34fSNate Lawson 	acpi_enable_fixed_events(sc);
3361a0a15716SJung-uk Kim     }
3362337744d9SJung-uk Kim     sc->acpi_next_sstate = 0;
336315e2f34fSNate Lawson 
3364a56fe095SJohn Baldwin     mtx_unlock(&Giant);
3365c66d2b38SJung-uk Kim 
3366fdce57a0SJohn Baldwin #ifdef EARLY_AP_STARTUP
3367fdce57a0SJohn Baldwin     thread_lock(curthread);
3368fdce57a0SJohn Baldwin     sched_unbind(curthread);
3369fdce57a0SJohn Baldwin     thread_unlock(curthread);
3370fdce57a0SJohn Baldwin #else
337136a483bbSJung-uk Kim     if (smp_started) {
3372c66d2b38SJung-uk Kim 	thread_lock(curthread);
3373c66d2b38SJung-uk Kim 	sched_unbind(curthread);
3374c66d2b38SJung-uk Kim 	thread_unlock(curthread);
337536a483bbSJung-uk Kim     }
3376fdce57a0SJohn Baldwin #endif
3377c66d2b38SJung-uk Kim 
3378f1084587SKonstantin Belousov     resume_all_fs();
337985f95fffSAndriy Gapon     resume_all_proc();
338085f95fffSAndriy Gapon 
33814a8fa6feSJung-uk Kim     EVENTHANDLER_INVOKE(power_resume);
33824a8fa6feSJung-uk Kim 
3383d42f0ad8SJung-uk Kim     /* Allow another sleep request after a while. */
3384fadf3fb9SJohn Baldwin     callout_schedule(&acpi_sleep_timer, hz * ACPI_MINIMUM_AWAKETIME);
3385d42f0ad8SJung-uk Kim 
3386d42f0ad8SJung-uk Kim     /* Run /etc/rc.resume after we are back. */
3387d42f0ad8SJung-uk Kim     if (devctl_process_running())
3388d42f0ad8SJung-uk Kim 	acpi_UserNotify("Resume", ACPI_ROOT_OBJECT, state);
3389d42f0ad8SJung-uk Kim 
33900ae55423SMike Smith     return_ACPI_STATUS (status);
339115e32d5dSMike Smith }
339215e32d5dSMike Smith 
3393a0a15716SJung-uk Kim static void
33940755473bSJung-uk Kim acpi_resync_clock(struct acpi_softc *sc)
33950755473bSJung-uk Kim {
33960755473bSJung-uk Kim 
33970755473bSJung-uk Kim     /*
33980755473bSJung-uk Kim      * Warm up timecounter again and reset system clock.
33990755473bSJung-uk Kim      */
34000755473bSJung-uk Kim     (void)timecounter->tc_get_timecount(timecounter);
34010755473bSJung-uk Kim     inittodr(time_second + sc->acpi_sleep_delay);
34020755473bSJung-uk Kim }
34030755473bSJung-uk Kim 
3404e8b4d56eSNate Lawson /* Enable or disable the device's wake GPE. */
3405e8b4d56eSNate Lawson int
3406e8b4d56eSNate Lawson acpi_wake_set_enable(device_t dev, int enable)
3407e8b4d56eSNate Lawson {
3408e8b4d56eSNate Lawson     struct acpi_prw_data prw;
3409e8b4d56eSNate Lawson     ACPI_STATUS status;
3410e8b4d56eSNate Lawson     int flags;
3411e8b4d56eSNate Lawson 
3412d4b9ff91SNate Lawson     /* Make sure the device supports waking the system and get the GPE. */
34132be4e471SJung-uk Kim     if (acpi_parse_prw(acpi_get_handle(dev), &prw) != 0)
3414e8b4d56eSNate Lawson 	return (ENXIO);
3415e8b4d56eSNate Lawson 
3416d4b9ff91SNate Lawson     flags = acpi_get_flags(dev);
3417e8b4d56eSNate Lawson     if (enable) {
34185a77b11bSJung-uk Kim 	status = AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit,
34195a77b11bSJung-uk Kim 	    ACPI_GPE_ENABLE);
3420e8b4d56eSNate Lawson 	if (ACPI_FAILURE(status)) {
3421e8b4d56eSNate Lawson 	    device_printf(dev, "enable wake failed\n");
3422e8b4d56eSNate Lawson 	    return (ENXIO);
3423e8b4d56eSNate Lawson 	}
3424d4b9ff91SNate Lawson 	acpi_set_flags(dev, flags | ACPI_FLAG_WAKE_ENABLED);
3425e8b4d56eSNate Lawson     } else {
34265a77b11bSJung-uk Kim 	status = AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit,
34275a77b11bSJung-uk Kim 	    ACPI_GPE_DISABLE);
3428e8b4d56eSNate Lawson 	if (ACPI_FAILURE(status)) {
3429e8b4d56eSNate Lawson 	    device_printf(dev, "disable wake failed\n");
3430e8b4d56eSNate Lawson 	    return (ENXIO);
3431e8b4d56eSNate Lawson 	}
3432d4b9ff91SNate Lawson 	acpi_set_flags(dev, flags & ~ACPI_FLAG_WAKE_ENABLED);
3433e8b4d56eSNate Lawson     }
3434e8b4d56eSNate Lawson 
3435e8b4d56eSNate Lawson     return (0);
3436e8b4d56eSNate Lawson }
3437e8b4d56eSNate Lawson 
3438d4b9ff91SNate Lawson static int
3439d4b9ff91SNate Lawson acpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate)
3440e8b4d56eSNate Lawson {
3441e8b4d56eSNate Lawson     struct acpi_prw_data prw;
3442d4b9ff91SNate Lawson     device_t dev;
3443e8b4d56eSNate Lawson 
3444d4b9ff91SNate Lawson     /* Check that this is a wake-capable device and get its GPE. */
3445e8b4d56eSNate Lawson     if (acpi_parse_prw(handle, &prw) != 0)
3446e8b4d56eSNate Lawson 	return (ENXIO);
3447d4b9ff91SNate Lawson     dev = acpi_get_device(handle);
3448e8b4d56eSNate Lawson 
3449e8b4d56eSNate Lawson     /*
3450d4b9ff91SNate Lawson      * The destination sleep state must be less than (i.e., higher power)
3451d4b9ff91SNate Lawson      * or equal to the value specified by _PRW.  If this GPE cannot be
3452d4b9ff91SNate Lawson      * enabled for the next sleep state, then disable it.  If it can and
3453d4b9ff91SNate Lawson      * the user requested it be enabled, turn on any required power resources
3454d4b9ff91SNate Lawson      * and set _PSW.
3455e8b4d56eSNate Lawson      */
3456d4b9ff91SNate Lawson     if (sstate > prw.lowest_wake) {
34575a77b11bSJung-uk Kim 	AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit, ACPI_GPE_DISABLE);
3458e8b4d56eSNate Lawson 	if (bootverbose)
3459d4b9ff91SNate Lawson 	    device_printf(dev, "wake_prep disabled wake for %s (S%d)\n",
3460d4b9ff91SNate Lawson 		acpi_name(handle), sstate);
3461d4b9ff91SNate Lawson     } else if (dev && (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) != 0) {
3462d4b9ff91SNate Lawson 	acpi_pwr_wake_enable(handle, 1);
3463d4b9ff91SNate Lawson 	acpi_SetInteger(handle, "_PSW", 1);
3464d4b9ff91SNate Lawson 	if (bootverbose)
3465d4b9ff91SNate Lawson 	    device_printf(dev, "wake_prep enabled for %s (S%d)\n",
3466d4b9ff91SNate Lawson 		acpi_name(handle), sstate);
3467d4b9ff91SNate Lawson     }
3468cc85c78cSNate Lawson 
3469cc85c78cSNate Lawson     return (0);
3470e8b4d56eSNate Lawson }
3471e8b4d56eSNate Lawson 
3472d4b9ff91SNate Lawson static int
3473d4b9ff91SNate Lawson acpi_wake_run_prep(ACPI_HANDLE handle, int sstate)
3474cc85c78cSNate Lawson {
3475cc85c78cSNate Lawson     struct acpi_prw_data prw;
3476d4b9ff91SNate Lawson     device_t dev;
3477cc85c78cSNate Lawson 
3478cc85c78cSNate Lawson     /*
3479d4b9ff91SNate Lawson      * Check that this is a wake-capable device and get its GPE.  Return
3480d4b9ff91SNate Lawson      * now if the user didn't enable this device for wake.
3481cc85c78cSNate Lawson      */
3482d4b9ff91SNate Lawson     if (acpi_parse_prw(handle, &prw) != 0)
3483d4b9ff91SNate Lawson 	return (ENXIO);
3484d4b9ff91SNate Lawson     dev = acpi_get_device(handle);
3485d4b9ff91SNate Lawson     if (dev == NULL || (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) == 0)
3486d4b9ff91SNate Lawson 	return (0);
3487cc85c78cSNate Lawson 
3488d4b9ff91SNate Lawson     /*
3489d4b9ff91SNate Lawson      * If this GPE couldn't be enabled for the previous sleep state, it was
3490d4b9ff91SNate Lawson      * disabled before going to sleep so re-enable it.  If it was enabled,
3491d4b9ff91SNate Lawson      * clear _PSW and turn off any power resources it used.
3492d4b9ff91SNate Lawson      */
3493d4b9ff91SNate Lawson     if (sstate > prw.lowest_wake) {
34945a77b11bSJung-uk Kim 	AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit, ACPI_GPE_ENABLE);
3495d4b9ff91SNate Lawson 	if (bootverbose)
3496d4b9ff91SNate Lawson 	    device_printf(dev, "run_prep re-enabled %s\n", acpi_name(handle));
3497d4b9ff91SNate Lawson     } else {
3498d4b9ff91SNate Lawson 	acpi_SetInteger(handle, "_PSW", 0);
3499d4b9ff91SNate Lawson 	acpi_pwr_wake_enable(handle, 0);
3500d4b9ff91SNate Lawson 	if (bootverbose)
3501d4b9ff91SNate Lawson 	    device_printf(dev, "run_prep cleaned up for %s\n",
3502d4b9ff91SNate Lawson 		acpi_name(handle));
3503d4b9ff91SNate Lawson     }
3504d4b9ff91SNate Lawson 
3505e8b4d56eSNate Lawson     return (0);
3506e8b4d56eSNate Lawson }
3507e8b4d56eSNate Lawson 
3508e8b4d56eSNate Lawson static ACPI_STATUS
3509d4b9ff91SNate Lawson acpi_wake_prep(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
3510e8b4d56eSNate Lawson {
3511d4b9ff91SNate Lawson     int sstate;
3512e8b4d56eSNate Lawson 
3513d4b9ff91SNate Lawson     /* If suspending, run the sleep prep function, otherwise wake. */
3514d4b9ff91SNate Lawson     sstate = *(int *)context;
3515d4b9ff91SNate Lawson     if (AcpiGbl_SystemAwakeAndRunning)
3516d4b9ff91SNate Lawson 	acpi_wake_sleep_prep(handle, sstate);
3517d4b9ff91SNate Lawson     else
3518d4b9ff91SNate Lawson 	acpi_wake_run_prep(handle, sstate);
3519e8b4d56eSNate Lawson     return (AE_OK);
3520e8b4d56eSNate Lawson }
3521e8b4d56eSNate Lawson 
3522d4b9ff91SNate Lawson /* Walk the tree rooted at acpi0 to prep devices for suspend/resume. */
3523e8b4d56eSNate Lawson static int
3524d4b9ff91SNate Lawson acpi_wake_prep_walk(int sstate)
3525e8b4d56eSNate Lawson {
3526e8b4d56eSNate Lawson     ACPI_HANDLE sb_handle;
3527e8b4d56eSNate Lawson 
3528e8b4d56eSNate Lawson     if (ACPI_SUCCESS(AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle)))
3529d4b9ff91SNate Lawson 	AcpiWalkNamespace(ACPI_TYPE_DEVICE, sb_handle, 100,
35302272d050SJung-uk Kim 	    acpi_wake_prep, NULL, &sstate, NULL);
3531e8b4d56eSNate Lawson     return (0);
3532e8b4d56eSNate Lawson }
3533e8b4d56eSNate Lawson 
353488a79fc0SNate Lawson /* Walk the tree rooted at acpi0 to attach per-device wake sysctls. */
353588a79fc0SNate Lawson static int
353688a79fc0SNate Lawson acpi_wake_sysctl_walk(device_t dev)
353788a79fc0SNate Lawson {
353888a79fc0SNate Lawson     int error, i, numdevs;
353988a79fc0SNate Lawson     device_t *devlist;
354088a79fc0SNate Lawson     device_t child;
3541d4b9ff91SNate Lawson     ACPI_STATUS status;
354288a79fc0SNate Lawson 
354388a79fc0SNate Lawson     error = device_get_children(dev, &devlist, &numdevs);
35441c9ec538SNate Lawson     if (error != 0 || numdevs == 0) {
35451c9ec538SNate Lawson 	if (numdevs == 0)
35461c9ec538SNate Lawson 	    free(devlist, M_TEMP);
354788a79fc0SNate Lawson 	return (error);
35481c9ec538SNate Lawson     }
354988a79fc0SNate Lawson     for (i = 0; i < numdevs; i++) {
355088a79fc0SNate Lawson 	child = devlist[i];
3551d4b9ff91SNate Lawson 	acpi_wake_sysctl_walk(child);
355288a79fc0SNate Lawson 	if (!device_is_attached(child))
355388a79fc0SNate Lawson 	    continue;
3554d4b9ff91SNate Lawson 	status = AcpiEvaluateObject(acpi_get_handle(child), "_PRW", NULL, NULL);
3555d4b9ff91SNate Lawson 	if (ACPI_SUCCESS(status)) {
355688a79fc0SNate Lawson 	    SYSCTL_ADD_PROC(device_get_sysctl_ctx(child),
355788a79fc0SNate Lawson 		SYSCTL_CHILDREN(device_get_sysctl_tree(child)), OID_AUTO,
35587029da5cSPawel Biernacki 		"wake", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, child, 0,
355988a79fc0SNate Lawson 		acpi_wake_set_sysctl, "I", "Device set to wake the system");
356088a79fc0SNate Lawson 	}
356188a79fc0SNate Lawson     }
356288a79fc0SNate Lawson     free(devlist, M_TEMP);
356388a79fc0SNate Lawson 
356488a79fc0SNate Lawson     return (0);
356588a79fc0SNate Lawson }
356688a79fc0SNate Lawson 
356788a79fc0SNate Lawson /* Enable or disable wake from userland. */
356888a79fc0SNate Lawson static int
356988a79fc0SNate Lawson acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS)
357088a79fc0SNate Lawson {
357188a79fc0SNate Lawson     int enable, error;
357288a79fc0SNate Lawson     device_t dev;
357388a79fc0SNate Lawson 
357488a79fc0SNate Lawson     dev = (device_t)arg1;
3575d4b9ff91SNate Lawson     enable = (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) ? 1 : 0;
357688a79fc0SNate Lawson 
357788a79fc0SNate Lawson     error = sysctl_handle_int(oidp, &enable, 0, req);
357888a79fc0SNate Lawson     if (error != 0 || req->newptr == NULL)
357988a79fc0SNate Lawson 	return (error);
358088a79fc0SNate Lawson     if (enable != 0 && enable != 1)
358188a79fc0SNate Lawson 	return (EINVAL);
358288a79fc0SNate Lawson 
358388a79fc0SNate Lawson     return (acpi_wake_set_enable(dev, enable));
358488a79fc0SNate Lawson }
358588a79fc0SNate Lawson 
3586e8b4d56eSNate Lawson /* Parse a device's _PRW into a structure. */
3587d4b9ff91SNate Lawson int
3588e8b4d56eSNate Lawson acpi_parse_prw(ACPI_HANDLE h, struct acpi_prw_data *prw)
3589e8b4d56eSNate Lawson {
3590e8b4d56eSNate Lawson     ACPI_STATUS			status;
3591e8b4d56eSNate Lawson     ACPI_BUFFER			prw_buffer;
3592e8b4d56eSNate Lawson     ACPI_OBJECT			*res, *res2;
3593d4b9ff91SNate Lawson     int				error, i, power_count;
3594e8b4d56eSNate Lawson 
3595e8b4d56eSNate Lawson     if (h == NULL || prw == NULL)
3596e8b4d56eSNate Lawson 	return (EINVAL);
3597e8b4d56eSNate Lawson 
3598e8b4d56eSNate Lawson     /*
3599e8b4d56eSNate Lawson      * The _PRW object (7.2.9) is only required for devices that have the
3600e8b4d56eSNate Lawson      * ability to wake the system from a sleeping state.
3601e8b4d56eSNate Lawson      */
3602e8b4d56eSNate Lawson     error = EINVAL;
3603e8b4d56eSNate Lawson     prw_buffer.Pointer = NULL;
3604e8b4d56eSNate Lawson     prw_buffer.Length = ACPI_ALLOCATE_BUFFER;
3605e8b4d56eSNate Lawson     status = AcpiEvaluateObject(h, "_PRW", NULL, &prw_buffer);
3606e8b4d56eSNate Lawson     if (ACPI_FAILURE(status))
3607e8b4d56eSNate Lawson 	return (ENOENT);
3608e8b4d56eSNate Lawson     res = (ACPI_OBJECT *)prw_buffer.Pointer;
3609e8b4d56eSNate Lawson     if (res == NULL)
3610e8b4d56eSNate Lawson 	return (ENOENT);
3611e8b4d56eSNate Lawson     if (!ACPI_PKG_VALID(res, 2))
3612e8b4d56eSNate Lawson 	goto out;
3613e8b4d56eSNate Lawson 
3614e8b4d56eSNate Lawson     /*
3615e8b4d56eSNate Lawson      * Element 1 of the _PRW object:
3616e8b4d56eSNate Lawson      * The lowest power system sleeping state that can be entered while still
3617e8b4d56eSNate Lawson      * providing wake functionality.  The sleeping state being entered must
3618e8b4d56eSNate Lawson      * be less than (i.e., higher power) or equal to this value.
3619e8b4d56eSNate Lawson      */
3620e8b4d56eSNate Lawson     if (acpi_PkgInt32(res, 1, &prw->lowest_wake) != 0)
3621e8b4d56eSNate Lawson 	goto out;
3622e8b4d56eSNate Lawson 
3623e8b4d56eSNate Lawson     /*
3624e8b4d56eSNate Lawson      * Element 0 of the _PRW object:
3625e8b4d56eSNate Lawson      */
3626e8b4d56eSNate Lawson     switch (res->Package.Elements[0].Type) {
3627e8b4d56eSNate Lawson     case ACPI_TYPE_INTEGER:
3628e8b4d56eSNate Lawson 	/*
3629e8b4d56eSNate Lawson 	 * If the data type of this package element is numeric, then this
3630e8b4d56eSNate Lawson 	 * _PRW package element is the bit index in the GPEx_EN, in the
3631e8b4d56eSNate Lawson 	 * GPE blocks described in the FADT, of the enable bit that is
3632e8b4d56eSNate Lawson 	 * enabled for the wake event.
3633e8b4d56eSNate Lawson 	 */
3634e8b4d56eSNate Lawson 	prw->gpe_handle = NULL;
3635e8b4d56eSNate Lawson 	prw->gpe_bit = res->Package.Elements[0].Integer.Value;
3636e8b4d56eSNate Lawson 	error = 0;
3637e8b4d56eSNate Lawson 	break;
3638e8b4d56eSNate Lawson     case ACPI_TYPE_PACKAGE:
3639e8b4d56eSNate Lawson 	/*
3640e8b4d56eSNate Lawson 	 * If the data type of this package element is a package, then this
3641e8b4d56eSNate Lawson 	 * _PRW package element is itself a package containing two
3642e8b4d56eSNate Lawson 	 * elements.  The first is an object reference to the GPE Block
3643e8b4d56eSNate Lawson 	 * device that contains the GPE that will be triggered by the wake
3644e8b4d56eSNate Lawson 	 * event.  The second element is numeric and it contains the bit
3645e8b4d56eSNate Lawson 	 * index in the GPEx_EN, in the GPE Block referenced by the
3646e8b4d56eSNate Lawson 	 * first element in the package, of the enable bit that is enabled for
3647e8b4d56eSNate Lawson 	 * the wake event.
3648e8b4d56eSNate Lawson 	 *
3649e8b4d56eSNate Lawson 	 * For example, if this field is a package then it is of the form:
3650e8b4d56eSNate Lawson 	 * Package() {\_SB.PCI0.ISA.GPE, 2}
3651e8b4d56eSNate Lawson 	 */
3652e8b4d56eSNate Lawson 	res2 = &res->Package.Elements[0];
3653e8b4d56eSNate Lawson 	if (!ACPI_PKG_VALID(res2, 2))
3654e8b4d56eSNate Lawson 	    goto out;
3655e8b4d56eSNate Lawson 	prw->gpe_handle = acpi_GetReference(NULL, &res2->Package.Elements[0]);
3656e8b4d56eSNate Lawson 	if (prw->gpe_handle == NULL)
3657e8b4d56eSNate Lawson 	    goto out;
3658e8b4d56eSNate Lawson 	if (acpi_PkgInt32(res2, 1, &prw->gpe_bit) != 0)
3659e8b4d56eSNate Lawson 	    goto out;
3660e8b4d56eSNate Lawson 	error = 0;
3661e8b4d56eSNate Lawson 	break;
3662e8b4d56eSNate Lawson     default:
3663e8b4d56eSNate Lawson 	goto out;
3664e8b4d56eSNate Lawson     }
3665e8b4d56eSNate Lawson 
3666d4b9ff91SNate Lawson     /* Elements 2 to N of the _PRW object are power resources. */
3667d4b9ff91SNate Lawson     power_count = res->Package.Count - 2;
3668d4b9ff91SNate Lawson     if (power_count > ACPI_PRW_MAX_POWERRES) {
3669d4b9ff91SNate Lawson 	printf("ACPI device %s has too many power resources\n", acpi_name(h));
3670d4b9ff91SNate Lawson 	power_count = 0;
3671d4b9ff91SNate Lawson     }
3672d4b9ff91SNate Lawson     prw->power_res_count = power_count;
3673d4b9ff91SNate Lawson     for (i = 0; i < power_count; i++)
3674d4b9ff91SNate Lawson 	prw->power_res[i] = res->Package.Elements[i];
3675e8b4d56eSNate Lawson 
3676e8b4d56eSNate Lawson out:
3677e8b4d56eSNate Lawson     if (prw_buffer.Pointer != NULL)
3678e8b4d56eSNate Lawson 	AcpiOsFree(prw_buffer.Pointer);
3679e8b4d56eSNate Lawson     return (error);
3680e8b4d56eSNate Lawson }
3681e8b4d56eSNate Lawson 
368215e32d5dSMike Smith /*
368315e32d5dSMike Smith  * ACPI Event Handlers
368415e32d5dSMike Smith  */
368515e32d5dSMike Smith 
368615e32d5dSMike Smith /* System Event Handlers (registered by EVENTHANDLER_REGISTER) */
368715e32d5dSMike Smith 
368815e32d5dSMike Smith static void
368915e32d5dSMike Smith acpi_system_eventhandler_sleep(void *arg, int state)
369015e32d5dSMike Smith {
36912d0c82e8SJung-uk Kim     struct acpi_softc *sc = (struct acpi_softc *)arg;
369200a30448SNate Lawson     int ret;
3693bee4aa4aSNate Lawson 
3694b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
369515e32d5dSMike Smith 
3696a0e73a12SJung-uk Kim     /* Check if button action is disabled or unknown. */
3697a0e73a12SJung-uk Kim     if (state == ACPI_STATE_UNKNOWN)
3698813d6dcaSNate Lawson 	return;
3699813d6dcaSNate Lawson 
370000a30448SNate Lawson     /* Request that the system prepare to enter the given suspend state. */
37012d0c82e8SJung-uk Kim     ret = acpi_ReqSleepState(sc, state);
370200a30448SNate Lawson     if (ret != 0)
37032d0c82e8SJung-uk Kim 	device_printf(sc->acpi_dev,
37042d0c82e8SJung-uk Kim 	    "request to enter state S%d failed (err %d)\n", state, ret);
3705bee4aa4aSNate Lawson 
37060ae55423SMike Smith     return_VOID;
370715e32d5dSMike Smith }
370815e32d5dSMike Smith 
370915e32d5dSMike Smith static void
371015e32d5dSMike Smith acpi_system_eventhandler_wakeup(void *arg, int state)
371115e32d5dSMike Smith {
3712bee4aa4aSNate Lawson 
3713b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
37140ae55423SMike Smith 
3715bee4aa4aSNate Lawson     /* Currently, nothing to do for wakeup. */
3716cb9b0d80SMike Smith 
37170ae55423SMike Smith     return_VOID;
371815e32d5dSMike Smith }
371915e32d5dSMike Smith 
372015e32d5dSMike Smith /*
372115e32d5dSMike Smith  * ACPICA Event Handlers (FixedEvent, also called from button notify handler)
372215e32d5dSMike Smith  */
3723b5854f5fSJung-uk Kim static void
3724b5854f5fSJung-uk Kim acpi_invoke_sleep_eventhandler(void *context)
3725b5854f5fSJung-uk Kim {
3726b5854f5fSJung-uk Kim 
3727b5854f5fSJung-uk Kim     EVENTHANDLER_INVOKE(acpi_sleep_event, *(int *)context);
3728b5854f5fSJung-uk Kim }
3729b5854f5fSJung-uk Kim 
3730b5854f5fSJung-uk Kim static void
3731b5854f5fSJung-uk Kim acpi_invoke_wake_eventhandler(void *context)
3732b5854f5fSJung-uk Kim {
3733b5854f5fSJung-uk Kim 
3734b5854f5fSJung-uk Kim     EVENTHANDLER_INVOKE(acpi_wakeup_event, *(int *)context);
3735b5854f5fSJung-uk Kim }
3736b5854f5fSJung-uk Kim 
373715e32d5dSMike Smith UINT32
373833febf93SNate Lawson acpi_event_power_button_sleep(void *context)
373915e32d5dSMike Smith {
374015e32d5dSMike Smith     struct acpi_softc	*sc = (struct acpi_softc *)context;
374115e32d5dSMike Smith 
3742b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
37430ae55423SMike Smith 
3744b5854f5fSJung-uk Kim     if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER,
3745b5854f5fSJung-uk Kim 	acpi_invoke_sleep_eventhandler, &sc->acpi_power_button_sx)))
3746b5854f5fSJung-uk Kim 	return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
3747b53f2771SMike Smith     return_VALUE (ACPI_INTERRUPT_HANDLED);
374815e32d5dSMike Smith }
374915e32d5dSMike Smith 
375015e32d5dSMike Smith UINT32
375133febf93SNate Lawson acpi_event_power_button_wake(void *context)
375215e32d5dSMike Smith {
375315e32d5dSMike Smith     struct acpi_softc	*sc = (struct acpi_softc *)context;
375415e32d5dSMike Smith 
3755b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
37560ae55423SMike Smith 
3757b5854f5fSJung-uk Kim     if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER,
3758b5854f5fSJung-uk Kim 	acpi_invoke_wake_eventhandler, &sc->acpi_power_button_sx)))
3759b5854f5fSJung-uk Kim 	return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
3760b53f2771SMike Smith     return_VALUE (ACPI_INTERRUPT_HANDLED);
376115e32d5dSMike Smith }
376215e32d5dSMike Smith 
376315e32d5dSMike Smith UINT32
376433febf93SNate Lawson acpi_event_sleep_button_sleep(void *context)
376515e32d5dSMike Smith {
376615e32d5dSMike Smith     struct acpi_softc	*sc = (struct acpi_softc *)context;
376715e32d5dSMike Smith 
3768b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
37690ae55423SMike Smith 
3770b5854f5fSJung-uk Kim     if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER,
3771b5854f5fSJung-uk Kim 	acpi_invoke_sleep_eventhandler, &sc->acpi_sleep_button_sx)))
3772b5854f5fSJung-uk Kim 	return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
3773b53f2771SMike Smith     return_VALUE (ACPI_INTERRUPT_HANDLED);
377415e32d5dSMike Smith }
377515e32d5dSMike Smith 
377615e32d5dSMike Smith UINT32
377733febf93SNate Lawson acpi_event_sleep_button_wake(void *context)
377815e32d5dSMike Smith {
377915e32d5dSMike Smith     struct acpi_softc	*sc = (struct acpi_softc *)context;
378015e32d5dSMike Smith 
3781b4a05238SPeter Wemm     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
37820ae55423SMike Smith 
3783b5854f5fSJung-uk Kim     if (ACPI_FAILURE(AcpiOsExecute(OSL_NOTIFY_HANDLER,
3784b5854f5fSJung-uk Kim 	acpi_invoke_wake_eventhandler, &sc->acpi_sleep_button_sx)))
3785b5854f5fSJung-uk Kim 	return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
3786b53f2771SMike Smith     return_VALUE (ACPI_INTERRUPT_HANDLED);
378715e32d5dSMike Smith }
378815e32d5dSMike Smith 
378915e32d5dSMike Smith /*
3790bee4aa4aSNate Lawson  * XXX This static buffer is suboptimal.  There is no locking so only
3791bee4aa4aSNate Lawson  * use this for single-threaded callers.
379215e32d5dSMike Smith  */
379315e32d5dSMike Smith char *
379415e32d5dSMike Smith acpi_name(ACPI_HANDLE handle)
379515e32d5dSMike Smith {
3796bee4aa4aSNate Lawson     ACPI_BUFFER buf;
3797bee4aa4aSNate Lawson     static char data[256];
379815e32d5dSMike Smith 
3799bee4aa4aSNate Lawson     buf.Length = sizeof(data);
3800bee4aa4aSNate Lawson     buf.Pointer = data;
3801cb9b0d80SMike Smith 
38020a9a1f44SNate Lawson     if (handle && ACPI_SUCCESS(AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf)))
3803bee4aa4aSNate Lawson 	return (data);
3804bee4aa4aSNate Lawson     return ("(unknown)");
380515e32d5dSMike Smith }
380615e32d5dSMike Smith 
380715e32d5dSMike Smith /*
380815e32d5dSMike Smith  * Debugging/bug-avoidance.  Avoid trying to fetch info on various
380915e32d5dSMike Smith  * parts of the namespace.
381015e32d5dSMike Smith  */
381115e32d5dSMike Smith int
381215e32d5dSMike Smith acpi_avoid(ACPI_HANDLE handle)
381315e32d5dSMike Smith {
38143c600cfbSJohn Baldwin     char	*cp, *env, *np;
381515e32d5dSMike Smith     int		len;
381615e32d5dSMike Smith 
381715e32d5dSMike Smith     np = acpi_name(handle);
381815e32d5dSMike Smith     if (*np == '\\')
381915e32d5dSMike Smith 	np++;
38202be111bfSDavide Italiano     if ((env = kern_getenv("debug.acpi.avoid")) == NULL)
382115e32d5dSMike Smith 	return (0);
382215e32d5dSMike Smith 
3823be2b1797SNate Lawson     /* Scan the avoid list checking for a match */
38243c600cfbSJohn Baldwin     cp = env;
382515e32d5dSMike Smith     for (;;) {
3826bee4aa4aSNate Lawson 	while (*cp != 0 && isspace(*cp))
382715e32d5dSMike Smith 	    cp++;
382815e32d5dSMike Smith 	if (*cp == 0)
382915e32d5dSMike Smith 	    break;
383015e32d5dSMike Smith 	len = 0;
3831bee4aa4aSNate Lawson 	while (cp[len] != 0 && !isspace(cp[len]))
383215e32d5dSMike Smith 	    len++;
3833d786139cSMaxime Henrion 	if (!strncmp(cp, np, len)) {
38343c600cfbSJohn Baldwin 	    freeenv(env);
38350ae55423SMike Smith 	    return(1);
3836d786139cSMaxime Henrion 	}
38370ae55423SMike Smith 	cp += len;
38380ae55423SMike Smith     }
38393c600cfbSJohn Baldwin     freeenv(env);
3840be2b1797SNate Lawson 
38410ae55423SMike Smith     return (0);
38420ae55423SMike Smith }
38430ae55423SMike Smith 
38440ae55423SMike Smith /*
38450ae55423SMike Smith  * Debugging/bug-avoidance.  Disable ACPI subsystem components.
38460ae55423SMike Smith  */
38470ae55423SMike Smith int
38480ae55423SMike Smith acpi_disabled(char *subsys)
38490ae55423SMike Smith {
385078689b15SMaxime Henrion     char	*cp, *env;
38510ae55423SMike Smith     int		len;
38520ae55423SMike Smith 
38532be111bfSDavide Italiano     if ((env = kern_getenv("debug.acpi.disabled")) == NULL)
38540ae55423SMike Smith 	return (0);
38553184cf5aSNate Lawson     if (strcmp(env, "all") == 0) {
385678689b15SMaxime Henrion 	freeenv(env);
38570ae55423SMike Smith 	return (1);
3858d786139cSMaxime Henrion     }
38590ae55423SMike Smith 
38603184cf5aSNate Lawson     /* Scan the disable list, checking for a match. */
386178689b15SMaxime Henrion     cp = env;
38620ae55423SMike Smith     for (;;) {
38633184cf5aSNate Lawson 	while (*cp != '\0' && isspace(*cp))
38640ae55423SMike Smith 	    cp++;
38653184cf5aSNate Lawson 	if (*cp == '\0')
38660ae55423SMike Smith 	    break;
38670ae55423SMike Smith 	len = 0;
38683184cf5aSNate Lawson 	while (cp[len] != '\0' && !isspace(cp[len]))
38690ae55423SMike Smith 	    len++;
38703184cf5aSNate Lawson 	if (strncmp(cp, subsys, len) == 0) {
387178689b15SMaxime Henrion 	    freeenv(env);
387215e32d5dSMike Smith 	    return (1);
3873d786139cSMaxime Henrion 	}
387415e32d5dSMike Smith 	cp += len;
387515e32d5dSMike Smith     }
387678689b15SMaxime Henrion     freeenv(env);
3877be2b1797SNate Lawson 
387815e32d5dSMike Smith     return (0);
387915e32d5dSMike Smith }
388015e32d5dSMike Smith 
388164de8019SJohn Baldwin static void
388264de8019SJohn Baldwin acpi_lookup(void *arg, const char *name, device_t *dev)
388364de8019SJohn Baldwin {
388464de8019SJohn Baldwin     ACPI_HANDLE handle;
388564de8019SJohn Baldwin 
388664de8019SJohn Baldwin     if (*dev != NULL)
388764de8019SJohn Baldwin 	return;
388864de8019SJohn Baldwin 
388964de8019SJohn Baldwin     /*
389064de8019SJohn Baldwin      * Allow any handle name that is specified as an absolute path and
389164de8019SJohn Baldwin      * starts with '\'.  We could restrict this to \_SB and friends,
389264de8019SJohn Baldwin      * but see acpi_probe_children() for notes on why we scan the entire
389364de8019SJohn Baldwin      * namespace for devices.
389464de8019SJohn Baldwin      *
389564de8019SJohn Baldwin      * XXX: The pathname argument to AcpiGetHandle() should be fixed to
389664de8019SJohn Baldwin      * be const.
389764de8019SJohn Baldwin      */
389864de8019SJohn Baldwin     if (name[0] != '\\')
389964de8019SJohn Baldwin 	return;
390064de8019SJohn Baldwin     if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, __DECONST(char *, name),
390164de8019SJohn Baldwin 	&handle)))
390264de8019SJohn Baldwin 	return;
390364de8019SJohn Baldwin     *dev = acpi_get_device(handle);
390464de8019SJohn Baldwin }
390564de8019SJohn Baldwin 
390615e32d5dSMike Smith /*
390715e32d5dSMike Smith  * Control interface.
390815e32d5dSMike Smith  *
39090ae55423SMike Smith  * We multiplex ioctls for all participating ACPI devices here.  Individual
3910be2b1797SNate Lawson  * drivers wanting to be accessible via /dev/acpi should use the
3911be2b1797SNate Lawson  * register/deregister interface to make their handlers visible.
391215e32d5dSMike Smith  */
39130ae55423SMike Smith struct acpi_ioctl_hook
39140ae55423SMike Smith {
39150ae55423SMike Smith     TAILQ_ENTRY(acpi_ioctl_hook) link;
39160ae55423SMike Smith     u_long			 cmd;
3917be2b1797SNate Lawson     acpi_ioctl_fn		 fn;
39180ae55423SMike Smith     void			 *arg;
39190ae55423SMike Smith };
39200ae55423SMike Smith 
39210ae55423SMike Smith static TAILQ_HEAD(,acpi_ioctl_hook)	acpi_ioctl_hooks;
39220ae55423SMike Smith static int				acpi_ioctl_hooks_initted;
39230ae55423SMike Smith 
39240ae55423SMike Smith int
3925be2b1797SNate Lawson acpi_register_ioctl(u_long cmd, acpi_ioctl_fn fn, void *arg)
39260ae55423SMike Smith {
39270ae55423SMike Smith     struct acpi_ioctl_hook	*hp;
39280ae55423SMike Smith 
39290ae55423SMike Smith     if ((hp = malloc(sizeof(*hp), M_ACPIDEV, M_NOWAIT)) == NULL)
39300ae55423SMike Smith 	return (ENOMEM);
39310ae55423SMike Smith     hp->cmd = cmd;
39320ae55423SMike Smith     hp->fn = fn;
39330ae55423SMike Smith     hp->arg = arg;
393415e2f34fSNate Lawson 
393515e2f34fSNate Lawson     ACPI_LOCK(acpi);
39360ae55423SMike Smith     if (acpi_ioctl_hooks_initted == 0) {
39370ae55423SMike Smith 	TAILQ_INIT(&acpi_ioctl_hooks);
39380ae55423SMike Smith 	acpi_ioctl_hooks_initted = 1;
39390ae55423SMike Smith     }
39400ae55423SMike Smith     TAILQ_INSERT_TAIL(&acpi_ioctl_hooks, hp, link);
394115e2f34fSNate Lawson     ACPI_UNLOCK(acpi);
394215e2f34fSNate Lawson 
39430ae55423SMike Smith     return (0);
39440ae55423SMike Smith }
39450ae55423SMike Smith 
39460ae55423SMike Smith void
3947be2b1797SNate Lawson acpi_deregister_ioctl(u_long cmd, acpi_ioctl_fn fn)
39480ae55423SMike Smith {
39490ae55423SMike Smith     struct acpi_ioctl_hook	*hp;
39500ae55423SMike Smith 
395115e2f34fSNate Lawson     ACPI_LOCK(acpi);
39520ae55423SMike Smith     TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link)
395315e2f34fSNate Lawson 	if (hp->cmd == cmd && hp->fn == fn)
39540ae55423SMike Smith 	    break;
39550ae55423SMike Smith 
39560ae55423SMike Smith     if (hp != NULL) {
39570ae55423SMike Smith 	TAILQ_REMOVE(&acpi_ioctl_hooks, hp, link);
39580ae55423SMike Smith 	free(hp, M_ACPIDEV);
39590ae55423SMike Smith     }
396015e2f34fSNate Lawson     ACPI_UNLOCK(acpi);
39610ae55423SMike Smith }
39620ae55423SMike Smith 
396315e32d5dSMike Smith static int
396400b4e54aSWarner Losh acpiopen(struct cdev *dev, int flag, int fmt, struct thread *td)
396515e32d5dSMike Smith {
396615e32d5dSMike Smith     return (0);
396715e32d5dSMike Smith }
396815e32d5dSMike Smith 
396915e32d5dSMike Smith static int
397000b4e54aSWarner Losh acpiclose(struct cdev *dev, int flag, int fmt, struct thread *td)
397115e32d5dSMike Smith {
397215e32d5dSMike Smith     return (0);
397315e32d5dSMike Smith }
397415e32d5dSMike Smith 
397515e32d5dSMike Smith static int
397600b4e54aSWarner Losh acpiioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td)
397715e32d5dSMike Smith {
397815e32d5dSMike Smith     struct acpi_softc		*sc;
39790ae55423SMike Smith     struct acpi_ioctl_hook	*hp;
3980bee4aa4aSNate Lawson     int				error, state;
398115e32d5dSMike Smith 
3982a2e35898SDavid E. O'Brien     error = 0;
3983a2e35898SDavid E. O'Brien     hp = NULL;
398415e32d5dSMike Smith     sc = dev->si_drv1;
398515e32d5dSMike Smith 
39860ae55423SMike Smith     /*
39870ae55423SMike Smith      * Scan the list of registered ioctls, looking for handlers.
39880ae55423SMike Smith      */
398915e2f34fSNate Lawson     ACPI_LOCK(acpi);
3990bee4aa4aSNate Lawson     if (acpi_ioctl_hooks_initted)
39910ae55423SMike Smith 	TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link) {
3992bee4aa4aSNate Lawson 	    if (hp->cmd == cmd)
3993bee4aa4aSNate Lawson 		break;
39940ae55423SMike Smith 	}
399515e2f34fSNate Lawson     ACPI_UNLOCK(acpi);
3996bee4aa4aSNate Lawson     if (hp)
3997bee4aa4aSNate Lawson 	return (hp->fn(cmd, addr, hp->arg));
39980ae55423SMike Smith 
39990ae55423SMike Smith     /*
4000a89fcf28STakanori Watanabe      * Core ioctls are not permitted for non-writable user.
4001a89fcf28STakanori Watanabe      * Currently, other ioctls just fetch information.
4002a89fcf28STakanori Watanabe      * Not changing system behavior.
4003a89fcf28STakanori Watanabe      */
4004be2b1797SNate Lawson     if ((flag & FWRITE) == 0)
4005be2b1797SNate Lawson 	return (EPERM);
4006a89fcf28STakanori Watanabe 
4007be2b1797SNate Lawson     /* Core system ioctls. */
400815e32d5dSMike Smith     switch (cmd) {
400900a30448SNate Lawson     case ACPIIO_REQSLPSTATE:
401000a30448SNate Lawson 	state = *(int *)addr;
401100a30448SNate Lawson 	if (state != ACPI_STATE_S5)
4012a0e73a12SJung-uk Kim 	    return (acpi_ReqSleepState(sc, state));
4013a0e73a12SJung-uk Kim 	device_printf(sc->acpi_dev, "power off via acpi ioctl not supported\n");
4014a0e73a12SJung-uk Kim 	error = EOPNOTSUPP;
401500a30448SNate Lawson 	break;
401600a30448SNate Lawson     case ACPIIO_ACKSLPSTATE:
401700a30448SNate Lawson 	error = *(int *)addr;
401800a30448SNate Lawson 	error = acpi_AckSleepState(sc->acpi_clone, error);
401900a30448SNate Lawson 	break;
402000a30448SNate Lawson     case ACPIIO_SETSLPSTATE:	/* DEPRECATED */
402115e32d5dSMike Smith 	state = *(int *)addr;
4022a0e73a12SJung-uk Kim 	if (state < ACPI_STATE_S0 || state > ACPI_S_STATES_MAX)
4023a0e73a12SJung-uk Kim 	    return (EINVAL);
4024a0e73a12SJung-uk Kim 	if (!acpi_sleep_states[state])
4025a0e73a12SJung-uk Kim 	    return (EOPNOTSUPP);
4026a0e73a12SJung-uk Kim 	if (ACPI_FAILURE(acpi_SetSleepState(sc, state)))
4027a0e73a12SJung-uk Kim 	    error = ENXIO;
402815e32d5dSMike Smith 	break;
402915e32d5dSMike Smith     default:
4030bee4aa4aSNate Lawson 	error = ENXIO;
403115e32d5dSMike Smith 	break;
403215e32d5dSMike Smith     }
4033917d44c8SMitsuru IWASAKI 
403415e32d5dSMike Smith     return (error);
403515e32d5dSMike Smith }
403615e32d5dSMike Smith 
40371d073b1dSJohn Baldwin static int
4038a0e73a12SJung-uk Kim acpi_sname2sstate(const char *sname)
4039a0e73a12SJung-uk Kim {
4040a0e73a12SJung-uk Kim     int sstate;
4041a0e73a12SJung-uk Kim 
4042a0e73a12SJung-uk Kim     if (toupper(sname[0]) == 'S') {
4043a0e73a12SJung-uk Kim 	sstate = sname[1] - '0';
4044a0e73a12SJung-uk Kim 	if (sstate >= ACPI_STATE_S0 && sstate <= ACPI_STATE_S5 &&
4045a0e73a12SJung-uk Kim 	    sname[2] == '\0')
4046a0e73a12SJung-uk Kim 	    return (sstate);
4047a0e73a12SJung-uk Kim     } else if (strcasecmp(sname, "NONE") == 0)
4048a0e73a12SJung-uk Kim 	return (ACPI_STATE_UNKNOWN);
4049a0e73a12SJung-uk Kim     return (-1);
4050a0e73a12SJung-uk Kim }
4051a0e73a12SJung-uk Kim 
4052a0e73a12SJung-uk Kim static const char *
4053a0e73a12SJung-uk Kim acpi_sstate2sname(int sstate)
4054a0e73a12SJung-uk Kim {
4055a0e73a12SJung-uk Kim     static const char *snames[] = { "S0", "S1", "S2", "S3", "S4", "S5" };
4056a0e73a12SJung-uk Kim 
4057a0e73a12SJung-uk Kim     if (sstate >= ACPI_STATE_S0 && sstate <= ACPI_STATE_S5)
4058a0e73a12SJung-uk Kim 	return (snames[sstate]);
4059a0e73a12SJung-uk Kim     else if (sstate == ACPI_STATE_UNKNOWN)
4060a0e73a12SJung-uk Kim 	return ("NONE");
4061a0e73a12SJung-uk Kim     return (NULL);
4062a0e73a12SJung-uk Kim }
4063a0e73a12SJung-uk Kim 
4064a0e73a12SJung-uk Kim static int
4065d75de536SMitsuru IWASAKI acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS)
4066d75de536SMitsuru IWASAKI {
4067d75de536SMitsuru IWASAKI     int error;
4068bee4aa4aSNate Lawson     struct sbuf sb;
4069a0e73a12SJung-uk Kim     UINT8 state;
4070d75de536SMitsuru IWASAKI 
4071bee4aa4aSNate Lawson     sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND);
4072a0e73a12SJung-uk Kim     for (state = ACPI_STATE_S1; state < ACPI_S_STATE_COUNT; state++)
4073a0e73a12SJung-uk Kim 	if (acpi_sleep_states[state])
4074a0e73a12SJung-uk Kim 	    sbuf_printf(&sb, "%s ", acpi_sstate2sname(state));
4075bee4aa4aSNate Lawson     sbuf_trim(&sb);
4076bee4aa4aSNate Lawson     sbuf_finish(&sb);
4077bee4aa4aSNate Lawson     error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
4078bee4aa4aSNate Lawson     sbuf_delete(&sb);
4079d75de536SMitsuru IWASAKI     return (error);
4080d75de536SMitsuru IWASAKI }
4081d75de536SMitsuru IWASAKI 
4082d75de536SMitsuru IWASAKI static int
40831d073b1dSJohn Baldwin acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS)
40841d073b1dSJohn Baldwin {
40851d073b1dSJohn Baldwin     char sleep_state[10];
4086a0e73a12SJung-uk Kim     int error, new_state, old_state;
40871d073b1dSJohn Baldwin 
4088a0e73a12SJung-uk Kim     old_state = *(int *)oidp->oid_arg1;
4089a0e73a12SJung-uk Kim     strlcpy(sleep_state, acpi_sstate2sname(old_state), sizeof(sleep_state));
40901d073b1dSJohn Baldwin     error = sysctl_handle_string(oidp, sleep_state, sizeof(sleep_state), req);
40911d073b1dSJohn Baldwin     if (error == 0 && req->newptr != NULL) {
4092a0e73a12SJung-uk Kim 	new_state = acpi_sname2sstate(sleep_state);
4093a0e73a12SJung-uk Kim 	if (new_state < ACPI_STATE_S1)
4094a0e73a12SJung-uk Kim 	    return (EINVAL);
409554b43614SJung-uk Kim 	if (new_state < ACPI_S_STATE_COUNT && !acpi_sleep_states[new_state])
4096a0e73a12SJung-uk Kim 	    return (EOPNOTSUPP);
4097be2b1797SNate Lawson 	if (new_state != old_state)
4098a0e73a12SJung-uk Kim 	    *(int *)oidp->oid_arg1 = new_state;
40991d073b1dSJohn Baldwin     }
41001d073b1dSJohn Baldwin     return (error);
41011d073b1dSJohn Baldwin }
41021d073b1dSJohn Baldwin 
41039b937d48SNate Lawson /* Inform devctl(4) when we receive a Notify. */
41049b937d48SNate Lawson void
41059b937d48SNate Lawson acpi_UserNotify(const char *subsystem, ACPI_HANDLE h, uint8_t notify)
41069b937d48SNate Lawson {
41079b937d48SNate Lawson     char		notify_buf[16];
41089b937d48SNate Lawson     ACPI_BUFFER		handle_buf;
41099b937d48SNate Lawson     ACPI_STATUS		status;
41109b937d48SNate Lawson 
41119b937d48SNate Lawson     if (subsystem == NULL)
41129b937d48SNate Lawson 	return;
41139b937d48SNate Lawson 
41149b937d48SNate Lawson     handle_buf.Pointer = NULL;
41159b937d48SNate Lawson     handle_buf.Length = ACPI_ALLOCATE_BUFFER;
41160594dadeSJung-uk Kim     status = AcpiNsHandleToPathname(h, &handle_buf, FALSE);
41179b937d48SNate Lawson     if (ACPI_FAILURE(status))
41189b937d48SNate Lawson 	return;
41199b937d48SNate Lawson     snprintf(notify_buf, sizeof(notify_buf), "notify=0x%02x", notify);
41209b937d48SNate Lawson     devctl_notify("ACPI", subsystem, handle_buf.Pointer, notify_buf);
41219b937d48SNate Lawson     AcpiOsFree(handle_buf.Pointer);
41229b937d48SNate Lawson }
41239b937d48SNate Lawson 
412415e32d5dSMike Smith #ifdef ACPI_DEBUG
41250ae55423SMike Smith /*
41260ae55423SMike Smith  * Support for parsing debug options from the kernel environment.
41270ae55423SMike Smith  *
41280ae55423SMike Smith  * Bits may be set in the AcpiDbgLayer and AcpiDbgLevel debug registers
41290ae55423SMike Smith  * by specifying the names of the bits in the debug.acpi.layer and
41300ae55423SMike Smith  * debug.acpi.level environment variables.  Bits may be unset by
41310ae55423SMike Smith  * prefixing the bit name with !.
41320ae55423SMike Smith  */
413315e32d5dSMike Smith struct debugtag
413415e32d5dSMike Smith {
413515e32d5dSMike Smith     char	*name;
413615e32d5dSMike Smith     UINT32	value;
413715e32d5dSMike Smith };
413815e32d5dSMike Smith 
413915e32d5dSMike Smith static struct debugtag	dbg_layer[] = {
4140c5ba0be4SMike Smith     {"ACPI_UTILITIES",		ACPI_UTILITIES},
4141c5ba0be4SMike Smith     {"ACPI_HARDWARE",		ACPI_HARDWARE},
4142c5ba0be4SMike Smith     {"ACPI_EVENTS",		ACPI_EVENTS},
4143c5ba0be4SMike Smith     {"ACPI_TABLES",		ACPI_TABLES},
4144c5ba0be4SMike Smith     {"ACPI_NAMESPACE",		ACPI_NAMESPACE},
4145c5ba0be4SMike Smith     {"ACPI_PARSER",		ACPI_PARSER},
4146c5ba0be4SMike Smith     {"ACPI_DISPATCHER",		ACPI_DISPATCHER},
4147c5ba0be4SMike Smith     {"ACPI_EXECUTER",		ACPI_EXECUTER},
4148c5ba0be4SMike Smith     {"ACPI_RESOURCES",		ACPI_RESOURCES},
4149d62ab2f4SMitsuru IWASAKI     {"ACPI_CA_DEBUGGER",	ACPI_CA_DEBUGGER},
41504c1cdee6SMike Smith     {"ACPI_OS_SERVICES",	ACPI_OS_SERVICES},
4151d62ab2f4SMitsuru IWASAKI     {"ACPI_CA_DISASSEMBLER",	ACPI_CA_DISASSEMBLER},
4152297835bcSNate Lawson     {"ACPI_ALL_COMPONENTS",	ACPI_ALL_COMPONENTS},
41534c1cdee6SMike Smith 
4154c5ba0be4SMike Smith     {"ACPI_AC_ADAPTER",		ACPI_AC_ADAPTER},
4155c5ba0be4SMike Smith     {"ACPI_BATTERY",		ACPI_BATTERY},
41563184cf5aSNate Lawson     {"ACPI_BUS",		ACPI_BUS},
4157c5ba0be4SMike Smith     {"ACPI_BUTTON",		ACPI_BUTTON},
41583184cf5aSNate Lawson     {"ACPI_EC", 		ACPI_EC},
41593184cf5aSNate Lawson     {"ACPI_FAN",		ACPI_FAN},
41603184cf5aSNate Lawson     {"ACPI_POWERRES",		ACPI_POWERRES},
41614c1cdee6SMike Smith     {"ACPI_PROCESSOR",		ACPI_PROCESSOR},
4162cb9b0d80SMike Smith     {"ACPI_THERMAL",		ACPI_THERMAL},
41633184cf5aSNate Lawson     {"ACPI_TIMER",		ACPI_TIMER},
4164b53f2771SMike Smith     {"ACPI_ALL_DRIVERS",	ACPI_ALL_DRIVERS},
416515e32d5dSMike Smith     {NULL, 0}
416615e32d5dSMike Smith };
416715e32d5dSMike Smith 
416815e32d5dSMike Smith static struct debugtag dbg_level[] = {
41699501b603SJohn Baldwin     {"ACPI_LV_INIT",		ACPI_LV_INIT},
41704c1cdee6SMike Smith     {"ACPI_LV_DEBUG_OBJECT",	ACPI_LV_DEBUG_OBJECT},
41719501b603SJohn Baldwin     {"ACPI_LV_INFO",		ACPI_LV_INFO},
4172cc6455afSJung-uk Kim     {"ACPI_LV_REPAIR",		ACPI_LV_REPAIR},
41734c1cdee6SMike Smith     {"ACPI_LV_ALL_EXCEPTIONS",	ACPI_LV_ALL_EXCEPTIONS},
4174d62ab2f4SMitsuru IWASAKI 
4175d62ab2f4SMitsuru IWASAKI     /* Trace verbosity level 1 [Standard Trace Level] */
4176297835bcSNate Lawson     {"ACPI_LV_INIT_NAMES",	ACPI_LV_INIT_NAMES},
41774c1cdee6SMike Smith     {"ACPI_LV_PARSE",		ACPI_LV_PARSE},
41784c1cdee6SMike Smith     {"ACPI_LV_LOAD",		ACPI_LV_LOAD},
4179d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_DISPATCH",	ACPI_LV_DISPATCH},
41804c1cdee6SMike Smith     {"ACPI_LV_EXEC",		ACPI_LV_EXEC},
41814c1cdee6SMike Smith     {"ACPI_LV_NAMES",		ACPI_LV_NAMES},
41824c1cdee6SMike Smith     {"ACPI_LV_OPREGION",	ACPI_LV_OPREGION},
41834c1cdee6SMike Smith     {"ACPI_LV_BFIELD",		ACPI_LV_BFIELD},
41844c1cdee6SMike Smith     {"ACPI_LV_TABLES",		ACPI_LV_TABLES},
41854c1cdee6SMike Smith     {"ACPI_LV_VALUES",		ACPI_LV_VALUES},
41864c1cdee6SMike Smith     {"ACPI_LV_OBJECTS",		ACPI_LV_OBJECTS},
41874c1cdee6SMike Smith     {"ACPI_LV_RESOURCES",	ACPI_LV_RESOURCES},
41884c1cdee6SMike Smith     {"ACPI_LV_USER_REQUESTS",	ACPI_LV_USER_REQUESTS},
41894c1cdee6SMike Smith     {"ACPI_LV_PACKAGE",		ACPI_LV_PACKAGE},
4190d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_VERBOSITY1",	ACPI_LV_VERBOSITY1},
4191d62ab2f4SMitsuru IWASAKI 
4192d62ab2f4SMitsuru IWASAKI     /* Trace verbosity level 2 [Function tracing and memory allocation] */
4193d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_ALLOCATIONS",	ACPI_LV_ALLOCATIONS},
4194d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_FUNCTIONS",	ACPI_LV_FUNCTIONS},
4195d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_OPTIMIZATIONS",	ACPI_LV_OPTIMIZATIONS},
4196d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_VERBOSITY2",	ACPI_LV_VERBOSITY2},
41974c1cdee6SMike Smith     {"ACPI_LV_ALL",		ACPI_LV_ALL},
4198d62ab2f4SMitsuru IWASAKI 
4199d62ab2f4SMitsuru IWASAKI     /* Trace verbosity level 3 [Threading, I/O, and Interrupts] */
4200d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_MUTEX",		ACPI_LV_MUTEX},
4201d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_THREADS",		ACPI_LV_THREADS},
4202d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_IO",		ACPI_LV_IO},
4203d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_INTERRUPTS",	ACPI_LV_INTERRUPTS},
4204d62ab2f4SMitsuru IWASAKI     {"ACPI_LV_VERBOSITY3",	ACPI_LV_VERBOSITY3},
4205d62ab2f4SMitsuru IWASAKI 
4206d62ab2f4SMitsuru IWASAKI     /* Exceptionally verbose output -- also used in the global "DebugLevel"  */
420798479b04SMitsuru IWASAKI     {"ACPI_LV_AML_DISASSEMBLE",	ACPI_LV_AML_DISASSEMBLE},
420898479b04SMitsuru IWASAKI     {"ACPI_LV_VERBOSE_INFO",	ACPI_LV_VERBOSE_INFO},
420998479b04SMitsuru IWASAKI     {"ACPI_LV_FULL_TABLES",	ACPI_LV_FULL_TABLES},
421098479b04SMitsuru IWASAKI     {"ACPI_LV_EVENTS",		ACPI_LV_EVENTS},
421198479b04SMitsuru IWASAKI     {"ACPI_LV_VERBOSE",		ACPI_LV_VERBOSE},
421215e32d5dSMike Smith     {NULL, 0}
421315e32d5dSMike Smith };
421415e32d5dSMike Smith 
421515e32d5dSMike Smith static void
421615e32d5dSMike Smith acpi_parse_debug(char *cp, struct debugtag *tag, UINT32 *flag)
421715e32d5dSMike Smith {
421815e32d5dSMike Smith     char	*ep;
421915e32d5dSMike Smith     int		i, l;
42200ae55423SMike Smith     int		set;
422115e32d5dSMike Smith 
422215e32d5dSMike Smith     while (*cp) {
422315e32d5dSMike Smith 	if (isspace(*cp)) {
422415e32d5dSMike Smith 	    cp++;
422515e32d5dSMike Smith 	    continue;
422615e32d5dSMike Smith 	}
422715e32d5dSMike Smith 	ep = cp;
422815e32d5dSMike Smith 	while (*ep && !isspace(*ep))
422915e32d5dSMike Smith 	    ep++;
42300ae55423SMike Smith 	if (*cp == '!') {
42310ae55423SMike Smith 	    set = 0;
42320ae55423SMike Smith 	    cp++;
42330ae55423SMike Smith 	    if (cp == ep)
42340ae55423SMike Smith 		continue;
42350ae55423SMike Smith 	} else {
42360ae55423SMike Smith 	    set = 1;
42370ae55423SMike Smith 	}
423815e32d5dSMike Smith 	l = ep - cp;
423915e32d5dSMike Smith 	for (i = 0; tag[i].name != NULL; i++) {
424015e32d5dSMike Smith 	    if (!strncmp(cp, tag[i].name, l)) {
4241be2b1797SNate Lawson 		if (set)
424215e32d5dSMike Smith 		    *flag |= tag[i].value;
4243be2b1797SNate Lawson 		else
42440ae55423SMike Smith 		    *flag &= ~tag[i].value;
424515e32d5dSMike Smith 	    }
424615e32d5dSMike Smith 	}
424715e32d5dSMike Smith 	cp = ep;
424815e32d5dSMike Smith     }
424915e32d5dSMike Smith }
425015e32d5dSMike Smith 
425115e32d5dSMike Smith static void
42522a4ac806SMike Smith acpi_set_debugging(void *junk)
425315e32d5dSMike Smith {
42547e639165SNate Lawson     char	*layer, *level;
425515e32d5dSMike Smith 
42561d7b121cSNate Lawson     if (cold) {
42570ae55423SMike Smith 	AcpiDbgLayer = 0;
42580ae55423SMike Smith 	AcpiDbgLevel = 0;
42591d7b121cSNate Lawson     }
42601d7b121cSNate Lawson 
42612be111bfSDavide Italiano     layer = kern_getenv("debug.acpi.layer");
42622be111bfSDavide Italiano     level = kern_getenv("debug.acpi.level");
42637e639165SNate Lawson     if (layer == NULL && level == NULL)
42647e639165SNate Lawson 	return;
42650ae55423SMike Smith 
42667e639165SNate Lawson     printf("ACPI set debug");
42677e639165SNate Lawson     if (layer != NULL) {
42687e639165SNate Lawson 	if (strcmp("NONE", layer) != 0)
42697e639165SNate Lawson 	    printf(" layer '%s'", layer);
42707e639165SNate Lawson 	acpi_parse_debug(layer, &dbg_layer[0], &AcpiDbgLayer);
42717e639165SNate Lawson 	freeenv(layer);
42721d7b121cSNate Lawson     }
42737e639165SNate Lawson     if (level != NULL) {
42747e639165SNate Lawson 	if (strcmp("NONE", level) != 0)
42757e639165SNate Lawson 	    printf(" level '%s'", level);
42767e639165SNate Lawson 	acpi_parse_debug(level, &dbg_level[0], &AcpiDbgLevel);
42777e639165SNate Lawson 	freeenv(level);
42787e639165SNate Lawson     }
42797e639165SNate Lawson     printf("\n");
428015e32d5dSMike Smith }
4281bee4aa4aSNate Lawson 
4282be2b1797SNate Lawson SYSINIT(acpi_debugging, SI_SUB_TUNABLES, SI_ORDER_ANY, acpi_set_debugging,
4283be2b1797SNate Lawson 	NULL);
42841d7b121cSNate Lawson 
42851d7b121cSNate Lawson static int
42861d7b121cSNate Lawson acpi_debug_sysctl(SYSCTL_HANDLER_ARGS)
42871d7b121cSNate Lawson {
428854f6bca0SNate Lawson     int		 error, *dbg;
42891d7b121cSNate Lawson     struct	 debugtag *tag;
429054f6bca0SNate Lawson     struct	 sbuf sb;
42910e1152fcSHans Petter Selasky     char	 temp[128];
42921d7b121cSNate Lawson 
429354f6bca0SNate Lawson     if (sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND) == NULL)
429454f6bca0SNate Lawson 	return (ENOMEM);
42951d7b121cSNate Lawson     if (strcmp(oidp->oid_arg1, "debug.acpi.layer") == 0) {
42961d7b121cSNate Lawson 	tag = &dbg_layer[0];
42971d7b121cSNate Lawson 	dbg = &AcpiDbgLayer;
42981d7b121cSNate Lawson     } else {
42991d7b121cSNate Lawson 	tag = &dbg_level[0];
43001d7b121cSNate Lawson 	dbg = &AcpiDbgLevel;
43011d7b121cSNate Lawson     }
43021d7b121cSNate Lawson 
43031d7b121cSNate Lawson     /* Get old values if this is a get request. */
430415e2f34fSNate Lawson     ACPI_SERIAL_BEGIN(acpi);
43051d7b121cSNate Lawson     if (*dbg == 0) {
430654f6bca0SNate Lawson 	sbuf_cpy(&sb, "NONE");
43071d7b121cSNate Lawson     } else if (req->newptr == NULL) {
43081d7b121cSNate Lawson 	for (; tag->name != NULL; tag++) {
430954f6bca0SNate Lawson 	    if ((*dbg & tag->value) == tag->value)
431054f6bca0SNate Lawson 		sbuf_printf(&sb, "%s ", tag->name);
43111d7b121cSNate Lawson 	}
43121d7b121cSNate Lawson     }
431354f6bca0SNate Lawson     sbuf_trim(&sb);
431454f6bca0SNate Lawson     sbuf_finish(&sb);
43150e1152fcSHans Petter Selasky     strlcpy(temp, sbuf_data(&sb), sizeof(temp));
431654f6bca0SNate Lawson     sbuf_delete(&sb);
43171d7b121cSNate Lawson 
43180e1152fcSHans Petter Selasky     error = sysctl_handle_string(oidp, temp, sizeof(temp), req);
43190e1152fcSHans Petter Selasky 
43200e1152fcSHans Petter Selasky     /* Check for error or no change */
43211d7b121cSNate Lawson     if (error == 0 && req->newptr != NULL) {
43221d7b121cSNate Lawson 	*dbg = 0;
43230e1152fcSHans Petter Selasky 	kern_setenv((char *)oidp->oid_arg1, temp);
43241d7b121cSNate Lawson 	acpi_set_debugging(NULL);
43251d7b121cSNate Lawson     }
432615e2f34fSNate Lawson     ACPI_SERIAL_END(acpi);
43271d7b121cSNate Lawson 
43281d7b121cSNate Lawson     return (error);
43291d7b121cSNate Lawson }
4330bee4aa4aSNate Lawson 
43317029da5cSPawel Biernacki SYSCTL_PROC(_debug_acpi, OID_AUTO, layer,
43327029da5cSPawel Biernacki     CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_NEEDGIANT, "debug.acpi.layer", 0,
43337029da5cSPawel Biernacki     acpi_debug_sysctl, "A",
43347029da5cSPawel Biernacki     "");
43357029da5cSPawel Biernacki SYSCTL_PROC(_debug_acpi, OID_AUTO, level,
43367029da5cSPawel Biernacki     CTLFLAG_RW | CTLTYPE_STRING | CTLFLAG_NEEDGIANT, "debug.acpi.level", 0,
43377029da5cSPawel Biernacki     acpi_debug_sysctl, "A",
43387029da5cSPawel Biernacki     "");
4339bee4aa4aSNate Lawson #endif /* ACPI_DEBUG */
4340f9390180SMitsuru IWASAKI 
4341f9390180SMitsuru IWASAKI static int
43422a18c71dSJung-uk Kim acpi_debug_objects_sysctl(SYSCTL_HANDLER_ARGS)
43432a18c71dSJung-uk Kim {
43442a18c71dSJung-uk Kim 	int	error;
43452a18c71dSJung-uk Kim 	int	old;
43462a18c71dSJung-uk Kim 
43472a18c71dSJung-uk Kim 	old = acpi_debug_objects;
43482a18c71dSJung-uk Kim 	error = sysctl_handle_int(oidp, &acpi_debug_objects, 0, req);
43492a18c71dSJung-uk Kim 	if (error != 0 || req->newptr == NULL)
43502a18c71dSJung-uk Kim 		return (error);
43512a18c71dSJung-uk Kim 	if (old == acpi_debug_objects || (old && acpi_debug_objects))
43522a18c71dSJung-uk Kim 		return (0);
43532a18c71dSJung-uk Kim 
43542a18c71dSJung-uk Kim 	ACPI_SERIAL_BEGIN(acpi);
43552a18c71dSJung-uk Kim 	AcpiGbl_EnableAmlDebugObject = acpi_debug_objects ? TRUE : FALSE;
43562a18c71dSJung-uk Kim 	ACPI_SERIAL_END(acpi);
43572a18c71dSJung-uk Kim 
43582a18c71dSJung-uk Kim 	return (0);
43592a18c71dSJung-uk Kim }
43602a18c71dSJung-uk Kim 
43612a18c71dSJung-uk Kim static int
4362ae19af49SJung-uk Kim acpi_parse_interfaces(char *str, struct acpi_interface *iface)
4363ae19af49SJung-uk Kim {
4364ae19af49SJung-uk Kim 	char *p;
4365ae19af49SJung-uk Kim 	size_t len;
4366ae19af49SJung-uk Kim 	int i, j;
4367ae19af49SJung-uk Kim 
4368ae19af49SJung-uk Kim 	p = str;
4369ae19af49SJung-uk Kim 	while (isspace(*p) || *p == ',')
4370ae19af49SJung-uk Kim 		p++;
4371ae19af49SJung-uk Kim 	len = strlen(p);
4372ae19af49SJung-uk Kim 	if (len == 0)
4373ae19af49SJung-uk Kim 		return (0);
4374ae19af49SJung-uk Kim 	p = strdup(p, M_TEMP);
4375ae19af49SJung-uk Kim 	for (i = 0; i < len; i++)
4376ae19af49SJung-uk Kim 		if (p[i] == ',')
4377ae19af49SJung-uk Kim 			p[i] = '\0';
4378ae19af49SJung-uk Kim 	i = j = 0;
4379ae19af49SJung-uk Kim 	while (i < len)
4380ae19af49SJung-uk Kim 		if (isspace(p[i]) || p[i] == '\0')
4381ae19af49SJung-uk Kim 			i++;
4382ae19af49SJung-uk Kim 		else {
4383ae19af49SJung-uk Kim 			i += strlen(p + i) + 1;
4384ae19af49SJung-uk Kim 			j++;
4385ae19af49SJung-uk Kim 		}
4386ae19af49SJung-uk Kim 	if (j == 0) {
4387ae19af49SJung-uk Kim 		free(p, M_TEMP);
4388ae19af49SJung-uk Kim 		return (0);
4389ae19af49SJung-uk Kim 	}
4390ae19af49SJung-uk Kim 	iface->data = malloc(sizeof(*iface->data) * j, M_TEMP, M_WAITOK);
4391ae19af49SJung-uk Kim 	iface->num = j;
4392ae19af49SJung-uk Kim 	i = j = 0;
4393ae19af49SJung-uk Kim 	while (i < len)
4394ae19af49SJung-uk Kim 		if (isspace(p[i]) || p[i] == '\0')
4395ae19af49SJung-uk Kim 			i++;
4396ae19af49SJung-uk Kim 		else {
4397ae19af49SJung-uk Kim 			iface->data[j] = p + i;
4398ae19af49SJung-uk Kim 			i += strlen(p + i) + 1;
4399ae19af49SJung-uk Kim 			j++;
4400ae19af49SJung-uk Kim 		}
4401ae19af49SJung-uk Kim 
4402ae19af49SJung-uk Kim 	return (j);
4403ae19af49SJung-uk Kim }
4404ae19af49SJung-uk Kim 
4405ae19af49SJung-uk Kim static void
4406ae19af49SJung-uk Kim acpi_free_interfaces(struct acpi_interface *iface)
4407ae19af49SJung-uk Kim {
4408ae19af49SJung-uk Kim 
4409ae19af49SJung-uk Kim 	free(iface->data[0], M_TEMP);
4410ae19af49SJung-uk Kim 	free(iface->data, M_TEMP);
4411ae19af49SJung-uk Kim }
4412ae19af49SJung-uk Kim 
4413ae19af49SJung-uk Kim static void
4414ae19af49SJung-uk Kim acpi_reset_interfaces(device_t dev)
4415ae19af49SJung-uk Kim {
4416ae19af49SJung-uk Kim 	struct acpi_interface list;
4417ae19af49SJung-uk Kim 	ACPI_STATUS status;
4418ae19af49SJung-uk Kim 	int i;
4419ae19af49SJung-uk Kim 
4420ae19af49SJung-uk Kim 	if (acpi_parse_interfaces(acpi_install_interface, &list) > 0) {
4421ae19af49SJung-uk Kim 		for (i = 0; i < list.num; i++) {
4422ae19af49SJung-uk Kim 			status = AcpiInstallInterface(list.data[i]);
4423ae19af49SJung-uk Kim 			if (ACPI_FAILURE(status))
4424ae19af49SJung-uk Kim 				device_printf(dev,
4425ae19af49SJung-uk Kim 				    "failed to install _OSI(\"%s\"): %s\n",
4426ae19af49SJung-uk Kim 				    list.data[i], AcpiFormatException(status));
4427ae19af49SJung-uk Kim 			else if (bootverbose)
4428ae19af49SJung-uk Kim 				device_printf(dev, "installed _OSI(\"%s\")\n",
4429ae19af49SJung-uk Kim 				    list.data[i]);
4430ae19af49SJung-uk Kim 		}
4431ae19af49SJung-uk Kim 		acpi_free_interfaces(&list);
4432ae19af49SJung-uk Kim 	}
4433ae19af49SJung-uk Kim 	if (acpi_parse_interfaces(acpi_remove_interface, &list) > 0) {
4434ae19af49SJung-uk Kim 		for (i = 0; i < list.num; i++) {
4435ae19af49SJung-uk Kim 			status = AcpiRemoveInterface(list.data[i]);
4436ae19af49SJung-uk Kim 			if (ACPI_FAILURE(status))
4437ae19af49SJung-uk Kim 				device_printf(dev,
4438ae19af49SJung-uk Kim 				    "failed to remove _OSI(\"%s\"): %s\n",
4439ae19af49SJung-uk Kim 				    list.data[i], AcpiFormatException(status));
4440ae19af49SJung-uk Kim 			else if (bootverbose)
4441ae19af49SJung-uk Kim 				device_printf(dev, "removed _OSI(\"%s\")\n",
4442ae19af49SJung-uk Kim 				    list.data[i]);
4443ae19af49SJung-uk Kim 		}
4444ae19af49SJung-uk Kim 		acpi_free_interfaces(&list);
4445ae19af49SJung-uk Kim 	}
4446ae19af49SJung-uk Kim }
4447ae19af49SJung-uk Kim 
4448ae19af49SJung-uk Kim static int
4449f9390180SMitsuru IWASAKI acpi_pm_func(u_long cmd, void *arg, ...)
4450f9390180SMitsuru IWASAKI {
4451f9390180SMitsuru IWASAKI 	int	state, acpi_state;
4452f9390180SMitsuru IWASAKI 	int	error;
4453f9390180SMitsuru IWASAKI 	struct	acpi_softc *sc;
4454f9390180SMitsuru IWASAKI 	va_list	ap;
4455f9390180SMitsuru IWASAKI 
4456f9390180SMitsuru IWASAKI 	error = 0;
4457f9390180SMitsuru IWASAKI 	switch (cmd) {
4458f9390180SMitsuru IWASAKI 	case POWER_CMD_SUSPEND:
4459f9390180SMitsuru IWASAKI 		sc = (struct acpi_softc *)arg;
4460f9390180SMitsuru IWASAKI 		if (sc == NULL) {
4461f9390180SMitsuru IWASAKI 			error = EINVAL;
4462f9390180SMitsuru IWASAKI 			goto out;
4463f9390180SMitsuru IWASAKI 		}
4464f9390180SMitsuru IWASAKI 
4465f9390180SMitsuru IWASAKI 		va_start(ap, arg);
4466f9390180SMitsuru IWASAKI 		state = va_arg(ap, int);
4467f9390180SMitsuru IWASAKI 		va_end(ap);
4468f9390180SMitsuru IWASAKI 
4469f9390180SMitsuru IWASAKI 		switch (state) {
4470f9390180SMitsuru IWASAKI 		case POWER_SLEEP_STATE_STANDBY:
4471f9390180SMitsuru IWASAKI 			acpi_state = sc->acpi_standby_sx;
4472f9390180SMitsuru IWASAKI 			break;
4473f9390180SMitsuru IWASAKI 		case POWER_SLEEP_STATE_SUSPEND:
4474f9390180SMitsuru IWASAKI 			acpi_state = sc->acpi_suspend_sx;
4475f9390180SMitsuru IWASAKI 			break;
4476f9390180SMitsuru IWASAKI 		case POWER_SLEEP_STATE_HIBERNATE:
4477f9390180SMitsuru IWASAKI 			acpi_state = ACPI_STATE_S4;
4478f9390180SMitsuru IWASAKI 			break;
4479f9390180SMitsuru IWASAKI 		default:
4480f9390180SMitsuru IWASAKI 			error = EINVAL;
4481f9390180SMitsuru IWASAKI 			goto out;
4482f9390180SMitsuru IWASAKI 		}
4483f9390180SMitsuru IWASAKI 
448400a30448SNate Lawson 		if (ACPI_FAILURE(acpi_EnterSleepState(sc, acpi_state)))
448500a30448SNate Lawson 			error = ENXIO;
4486f9390180SMitsuru IWASAKI 		break;
4487f9390180SMitsuru IWASAKI 	default:
4488f9390180SMitsuru IWASAKI 		error = EINVAL;
4489f9390180SMitsuru IWASAKI 		goto out;
4490f9390180SMitsuru IWASAKI 	}
4491f9390180SMitsuru IWASAKI 
4492f9390180SMitsuru IWASAKI out:
4493f9390180SMitsuru IWASAKI 	return (error);
4494f9390180SMitsuru IWASAKI }
4495f9390180SMitsuru IWASAKI 
4496f9390180SMitsuru IWASAKI static void
4497f9390180SMitsuru IWASAKI acpi_pm_register(void *arg)
4498f9390180SMitsuru IWASAKI {
4499be2b1797SNate Lawson     if (!cold || resource_disabled("acpi", 0))
45006c407052SMitsuru IWASAKI 	return;
4501f9390180SMitsuru IWASAKI 
4502f9390180SMitsuru IWASAKI     power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, NULL);
4503f9390180SMitsuru IWASAKI }
4504f9390180SMitsuru IWASAKI 
4505891cf3edSEd Maste SYSINIT(power, SI_SUB_KLD, SI_ORDER_ANY, acpi_pm_register, NULL);
4506