xref: /dragonfly/sys/dev/acpica/acpi.c (revision 0994aedb)
15db2f26eSSascha Wildner /*-
25db2f26eSSascha Wildner  * Copyright (c) 2000 Takanori Watanabe <takawata@jp.kfreebsd.org>
35db2f26eSSascha Wildner  * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@jp.kfreebsd.org>
45db2f26eSSascha Wildner  * Copyright (c) 2000, 2001 Michael Smith
55db2f26eSSascha Wildner  * Copyright (c) 2000 BSDi
65db2f26eSSascha Wildner  * All rights reserved.
75db2f26eSSascha Wildner  *
85db2f26eSSascha Wildner  * Redistribution and use in source and binary forms, with or without
95db2f26eSSascha Wildner  * modification, are permitted provided that the following conditions
105db2f26eSSascha Wildner  * are met:
115db2f26eSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
125db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
135db2f26eSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
145db2f26eSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
155db2f26eSSascha Wildner  *    documentation and/or other materials provided with the distribution.
165db2f26eSSascha Wildner  *
175db2f26eSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
185db2f26eSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
195db2f26eSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
205db2f26eSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
215db2f26eSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
225db2f26eSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
235db2f26eSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
245db2f26eSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
255db2f26eSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
265db2f26eSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
275db2f26eSSascha Wildner  * SUCH DAMAGE.
285db2f26eSSascha Wildner  *
295db2f26eSSascha Wildner  * $FreeBSD: src/sys/dev/acpica/acpi.c,v 1.243.2.4.4.1 2009/04/15 03:14:26 kensmith Exp $
305db2f26eSSascha Wildner  */
315db2f26eSSascha Wildner 
325db2f26eSSascha Wildner #include "opt_acpi.h"
335db2f26eSSascha Wildner #include <sys/param.h>
345db2f26eSSascha Wildner #include <sys/kernel.h>
355db2f26eSSascha Wildner #include <sys/proc.h>
365db2f26eSSascha Wildner #include <sys/fcntl.h>
375db2f26eSSascha Wildner #include <sys/malloc.h>
385db2f26eSSascha Wildner #include <sys/module.h>
395db2f26eSSascha Wildner #include <sys/bus.h>
405db2f26eSSascha Wildner #include <sys/conf.h>
415db2f26eSSascha Wildner #include <sys/reboot.h>
425db2f26eSSascha Wildner #include <sys/sysctl.h>
435db2f26eSSascha Wildner #include <sys/ctype.h>
445db2f26eSSascha Wildner #include <sys/linker.h>
455db2f26eSSascha Wildner #include <sys/power.h>
465db2f26eSSascha Wildner #include <sys/sbuf.h>
475db2f26eSSascha Wildner #include <sys/device.h>
485db2f26eSSascha Wildner #include <sys/spinlock.h>
495db2f26eSSascha Wildner #include <sys/spinlock2.h>
505ca62c87SSascha Wildner #include <sys/uuid.h>
515db2f26eSSascha Wildner 
525db2f26eSSascha Wildner #include <sys/rman.h>
535db2f26eSSascha Wildner #include <bus/isa/isavar.h>
545db2f26eSSascha Wildner #include <bus/isa/pnpvar.h>
555db2f26eSSascha Wildner 
565db2f26eSSascha Wildner #include "acpi.h"
575db2f26eSSascha Wildner #include <dev/acpica/acpivar.h>
585db2f26eSSascha Wildner #include <dev/acpica/acpiio.h>
59279dd846SSascha Wildner #include <dev/acpica/acpiio_mcall.h>
605db2f26eSSascha Wildner #include "achware.h"
615db2f26eSSascha Wildner #include "acnamesp.h"
625db2f26eSSascha Wildner #include "acglobal.h"
635db2f26eSSascha Wildner 
645db2f26eSSascha Wildner #include "pci_if.h"
655db2f26eSSascha Wildner #include <bus/pci/pci_cfgreg.h>
665db2f26eSSascha Wildner #include <bus/pci/pcivar.h>
675db2f26eSSascha Wildner #include <bus/pci/pci_private.h>
685db2f26eSSascha Wildner 
695db2f26eSSascha Wildner #include <vm/vm_param.h>
705db2f26eSSascha Wildner 
715db2f26eSSascha Wildner MALLOC_DEFINE(M_ACPIDEV, "acpidev", "ACPI devices");
725db2f26eSSascha Wildner 
735db2f26eSSascha Wildner /* Hooks for the ACPICA debugging infrastructure */
745db2f26eSSascha Wildner #define _COMPONENT	ACPI_BUS
758d9e85c8SSascha Wildner ACPI_MODULE_NAME("ACPI");
765db2f26eSSascha Wildner 
775db2f26eSSascha Wildner static d_open_t		acpiopen;
785db2f26eSSascha Wildner static d_close_t	acpiclose;
795db2f26eSSascha Wildner static d_ioctl_t	acpiioctl;
805db2f26eSSascha Wildner 
815db2f26eSSascha Wildner static struct dev_ops acpi_ops = {
82a639f788SMatthew Dillon         { "acpi", 0, D_MPSAFE },
835db2f26eSSascha Wildner         .d_open = acpiopen,
845db2f26eSSascha Wildner         .d_close = acpiclose,
855db2f26eSSascha Wildner         .d_ioctl = acpiioctl
865db2f26eSSascha Wildner };
875db2f26eSSascha Wildner 
88fa21302bSSascha Wildner struct acpi_interface {
89fa21302bSSascha Wildner 	ACPI_STRING	*data;
90fa21302bSSascha Wildner 	int		num;
91fa21302bSSascha Wildner };
92fa21302bSSascha Wildner 
935db2f26eSSascha Wildner /* Global mutex for locking access to the ACPI subsystem. */
945db2f26eSSascha Wildner struct lock acpi_lock;
95a639f788SMatthew Dillon struct lwkt_token acpi_token = LWKT_TOKEN_INITIALIZER(acpi_token);
96d2fa5f95SSascha Wildner 
975db2f26eSSascha Wildner /* Bitmap of device quirks. */
985db2f26eSSascha Wildner int		acpi_quirks;
995db2f26eSSascha Wildner 
1005db2f26eSSascha Wildner static int	acpi_modevent(struct module *mod, int event, void *junk);
1015db2f26eSSascha Wildner static void	acpi_identify(driver_t *driver, device_t parent);
1025db2f26eSSascha Wildner static int	acpi_probe(device_t dev);
1035db2f26eSSascha Wildner static int	acpi_attach(device_t dev);
1045db2f26eSSascha Wildner static int	acpi_suspend(device_t dev);
1055db2f26eSSascha Wildner static int	acpi_resume(device_t dev);
1065db2f26eSSascha Wildner static int	acpi_shutdown(device_t dev);
1075db2f26eSSascha Wildner static device_t	acpi_add_child(device_t bus, device_t parent, int order, const char *name,
1085db2f26eSSascha Wildner 			int unit);
1095db2f26eSSascha Wildner static int	acpi_print_child(device_t bus, device_t child);
1105db2f26eSSascha Wildner static void	acpi_probe_nomatch(device_t bus, device_t child);
1115db2f26eSSascha Wildner static void	acpi_driver_added(device_t dev, driver_t *driver);
1125db2f26eSSascha Wildner static int	acpi_read_ivar(device_t dev, device_t child, int index,
1135db2f26eSSascha Wildner 			uintptr_t *result);
1145db2f26eSSascha Wildner static int	acpi_write_ivar(device_t dev, device_t child, int index,
1155db2f26eSSascha Wildner 			uintptr_t value);
1165db2f26eSSascha Wildner static struct resource_list *acpi_get_rlist(device_t dev, device_t child);
1175db2f26eSSascha Wildner static int	acpi_sysres_alloc(device_t dev);
1185db2f26eSSascha Wildner static struct resource *acpi_alloc_resource(device_t bus, device_t child,
1195db2f26eSSascha Wildner 			int type, int *rid, u_long start, u_long end,
1205db2f26eSSascha Wildner 			u_long count, u_int flags, int cpuid);
1215db2f26eSSascha Wildner static int	acpi_release_resource(device_t bus, device_t child, int type,
1225db2f26eSSascha Wildner 			int rid, struct resource *r);
1235db2f26eSSascha Wildner static void	acpi_delete_resource(device_t bus, device_t child, int type,
1245db2f26eSSascha Wildner 		    int rid);
1255db2f26eSSascha Wildner static uint32_t	acpi_isa_get_logicalid(device_t dev);
1265db2f26eSSascha Wildner static int	acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count);
1275db2f26eSSascha Wildner static char	*acpi_device_id_probe(device_t bus, device_t dev, char **ids);
1285db2f26eSSascha Wildner static ACPI_STATUS acpi_device_eval_obj(device_t bus, device_t dev,
1295db2f26eSSascha Wildner 		    ACPI_STRING pathname, ACPI_OBJECT_LIST *parameters,
1305db2f26eSSascha Wildner 		    ACPI_BUFFER *ret);
1315db2f26eSSascha Wildner static int	acpi_device_pwr_for_sleep(device_t bus, device_t dev,
1325db2f26eSSascha Wildner 		    int *dstate);
1335db2f26eSSascha Wildner static ACPI_STATUS acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level,
1345db2f26eSSascha Wildner 		    void *context, void **retval);
1355db2f26eSSascha Wildner static ACPI_STATUS acpi_device_scan_children(device_t bus, device_t dev,
1365db2f26eSSascha Wildner 		    int max_depth, acpi_scan_cb_t user_fn, void *arg);
1375db2f26eSSascha Wildner static int	acpi_set_powerstate_method(device_t bus, device_t child,
1385db2f26eSSascha Wildner 		    int state);
1395db2f26eSSascha Wildner static int	acpi_isa_pnp_probe(device_t bus, device_t child,
1405db2f26eSSascha Wildner 		    struct isa_pnp_id *ids);
1415db2f26eSSascha Wildner static void	acpi_probe_children(device_t bus);
1425db2f26eSSascha Wildner static void	acpi_probe_order(ACPI_HANDLE handle, int *order);
143ebb7869eSImre Vadász static void	acpi_disable_not_present(device_t child);
144ebb7869eSImre Vadász static void	acpi_reprobe_children(device_t bus, device_t *children,
145ebb7869eSImre Vadász 		    int cnt);
1465db2f26eSSascha Wildner static ACPI_STATUS acpi_probe_child(ACPI_HANDLE handle, UINT32 level,
1475db2f26eSSascha Wildner 		    void *context, void **status);
1485db2f26eSSascha Wildner static ACPI_STATUS acpi_EnterSleepState(struct acpi_softc *sc, int state);
1495db2f26eSSascha Wildner static void	acpi_shutdown_final(void *arg, int howto);
1505db2f26eSSascha Wildner static void	acpi_enable_fixed_events(struct acpi_softc *sc);
1515db2f26eSSascha Wildner static int	acpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate);
1525db2f26eSSascha Wildner static int	acpi_wake_run_prep(ACPI_HANDLE handle, int sstate);
1535db2f26eSSascha Wildner static int	acpi_wake_prep_walk(int sstate);
1545db2f26eSSascha Wildner static int	acpi_wake_sysctl_walk(device_t dev);
1555db2f26eSSascha Wildner #ifdef notyet
1565db2f26eSSascha Wildner static int	acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS);
1575db2f26eSSascha Wildner #endif
1585db2f26eSSascha Wildner static void	acpi_system_eventhandler_sleep(void *arg, int state);
1595db2f26eSSascha Wildner static void	acpi_system_eventhandler_wakeup(void *arg, int state);
1605db2f26eSSascha Wildner static int	acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS);
1615db2f26eSSascha Wildner static int	acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS);
162586fced2SSascha Wildner static int	acpi_debug_objects_sysctl(SYSCTL_HANDLER_ARGS);
1635db2f26eSSascha Wildner static int	acpi_pm_func(u_long cmd, void *arg, ...);
1645db2f26eSSascha Wildner static int	acpi_child_location_str_method(device_t acdev, device_t child,
1655db2f26eSSascha Wildner 					       char *buf, size_t buflen);
1665db2f26eSSascha Wildner static int	acpi_child_pnpinfo_str_method(device_t acdev, device_t child,
1675db2f26eSSascha Wildner 					      char *buf, size_t buflen);
1685db2f26eSSascha Wildner static void	acpi_enable_pcie(void);
169fa21302bSSascha Wildner static void	acpi_reset_interfaces(device_t dev);
170529b0458SSascha Wildner static void	acpi_call_fixup_pointers(ACPI_OBJECT *p, UINT8 *orig);
171529b0458SSascha Wildner static int	acpi_call_ioctl(caddr_t addr);
172529b0458SSascha Wildner static ACPI_OBJECT_LIST *acpi_copyin_object_list(ACPI_OBJECT_LIST *src);
173529b0458SSascha Wildner static void	acpi_free_object_list(ACPI_OBJECT_LIST *list);
1745db2f26eSSascha Wildner 
1755db2f26eSSascha Wildner static device_method_t acpi_methods[] = {
1765db2f26eSSascha Wildner     /* Device interface */
1775db2f26eSSascha Wildner     DEVMETHOD(device_identify,		acpi_identify),
1785db2f26eSSascha Wildner     DEVMETHOD(device_probe,		acpi_probe),
1795db2f26eSSascha Wildner     DEVMETHOD(device_attach,		acpi_attach),
1805db2f26eSSascha Wildner     DEVMETHOD(device_shutdown,		acpi_shutdown),
1815db2f26eSSascha Wildner     DEVMETHOD(device_detach,		bus_generic_detach),
1825db2f26eSSascha Wildner     DEVMETHOD(device_suspend,		acpi_suspend),
1835db2f26eSSascha Wildner     DEVMETHOD(device_resume,		acpi_resume),
1845db2f26eSSascha Wildner 
1855db2f26eSSascha Wildner     /* Bus interface */
1865db2f26eSSascha Wildner     DEVMETHOD(bus_add_child,		acpi_add_child),
1875db2f26eSSascha Wildner     DEVMETHOD(bus_print_child,		acpi_print_child),
1885db2f26eSSascha Wildner     DEVMETHOD(bus_probe_nomatch,	acpi_probe_nomatch),
1895db2f26eSSascha Wildner     DEVMETHOD(bus_driver_added,		acpi_driver_added),
1905db2f26eSSascha Wildner     DEVMETHOD(bus_read_ivar,		acpi_read_ivar),
1915db2f26eSSascha Wildner     DEVMETHOD(bus_write_ivar,		acpi_write_ivar),
1925db2f26eSSascha Wildner     DEVMETHOD(bus_get_resource_list,	acpi_get_rlist),
1935db2f26eSSascha Wildner     DEVMETHOD(bus_set_resource,		bus_generic_rl_set_resource),
1945db2f26eSSascha Wildner     DEVMETHOD(bus_get_resource,		bus_generic_rl_get_resource),
1955db2f26eSSascha Wildner     DEVMETHOD(bus_alloc_resource,	acpi_alloc_resource),
1965db2f26eSSascha Wildner     DEVMETHOD(bus_release_resource,	acpi_release_resource),
1975db2f26eSSascha Wildner     DEVMETHOD(bus_delete_resource,	acpi_delete_resource),
1985db2f26eSSascha Wildner     DEVMETHOD(bus_child_pnpinfo_str,	acpi_child_pnpinfo_str_method),
1995db2f26eSSascha Wildner     DEVMETHOD(bus_child_location_str,	acpi_child_location_str_method),
2005db2f26eSSascha Wildner     DEVMETHOD(bus_activate_resource,	bus_generic_activate_resource),
2015db2f26eSSascha Wildner     DEVMETHOD(bus_deactivate_resource,	bus_generic_deactivate_resource),
2025db2f26eSSascha Wildner     DEVMETHOD(bus_setup_intr,		bus_generic_setup_intr),
2035db2f26eSSascha Wildner     DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
2045db2f26eSSascha Wildner 
2055db2f26eSSascha Wildner     /* ACPI bus */
2065db2f26eSSascha Wildner     DEVMETHOD(acpi_id_probe,		acpi_device_id_probe),
2075db2f26eSSascha Wildner     DEVMETHOD(acpi_evaluate_object,	acpi_device_eval_obj),
2085db2f26eSSascha Wildner     DEVMETHOD(acpi_pwr_for_sleep,	acpi_device_pwr_for_sleep),
2095db2f26eSSascha Wildner     DEVMETHOD(acpi_scan_children,	acpi_device_scan_children),
2105db2f26eSSascha Wildner 
2115db2f26eSSascha Wildner     /* PCI emulation */
2125db2f26eSSascha Wildner     DEVMETHOD(pci_set_powerstate,	acpi_set_powerstate_method),
2135db2f26eSSascha Wildner 
2145db2f26eSSascha Wildner     /* ISA emulation */
2155db2f26eSSascha Wildner     DEVMETHOD(isa_pnp_probe,		acpi_isa_pnp_probe),
2165db2f26eSSascha Wildner 
217d3c9c58eSSascha Wildner     DEVMETHOD_END
2185db2f26eSSascha Wildner };
2195db2f26eSSascha Wildner 
2205db2f26eSSascha Wildner static driver_t acpi_driver = {
2215db2f26eSSascha Wildner     "acpi",
2225db2f26eSSascha Wildner     acpi_methods,
2235db2f26eSSascha Wildner     sizeof(struct acpi_softc),
224df21e16dSImre Vadász     .gpri = KOBJ_GPRI_ACPI+2
2255db2f26eSSascha Wildner };
2265db2f26eSSascha Wildner 
2275db2f26eSSascha Wildner static devclass_t acpi_devclass;
2285db2f26eSSascha Wildner DRIVER_MODULE(acpi, nexus, acpi_driver, acpi_devclass, acpi_modevent, NULL);
2295db2f26eSSascha Wildner MODULE_VERSION(acpi, 1);
2305db2f26eSSascha Wildner 
2318d9e85c8SSascha Wildner ACPI_SERIAL_DECL(acpi, "ACPI serializer");
2325db2f26eSSascha Wildner 
2335db2f26eSSascha Wildner /* Local pools for managing system resources for ACPI child devices. */
2345db2f26eSSascha Wildner static struct rman acpi_rman_io, acpi_rman_mem;
2355db2f26eSSascha Wildner 
2365db2f26eSSascha Wildner #define ACPI_MINIMUM_AWAKETIME	5
2375db2f26eSSascha Wildner 
2385db2f26eSSascha Wildner static const char* sleep_state_names[] = {
2395db2f26eSSascha Wildner     "S0", "S1", "S2", "S3", "S4", "S5", "NONE"};
2405db2f26eSSascha Wildner 
2415db2f26eSSascha Wildner SYSCTL_NODE(_debug, OID_AUTO, acpi, CTLFLAG_RD, NULL, "ACPI debugging");
2425db2f26eSSascha Wildner static char acpi_ca_version[12];
2435db2f26eSSascha Wildner SYSCTL_STRING(_debug_acpi, OID_AUTO, acpi_ca_version, CTLFLAG_RD,
244026a4538SSascha Wildner 	      acpi_ca_version, 0, "Version of Intel ACPICA");
2455db2f26eSSascha Wildner 
2465db2f26eSSascha Wildner /*
247fa21302bSSascha Wildner  * Allow overriding _OSI methods.
248fa21302bSSascha Wildner  */
249fa21302bSSascha Wildner static char acpi_install_interface[256];
250fa21302bSSascha Wildner TUNABLE_STR("hw.acpi.install_interface", acpi_install_interface,
251fa21302bSSascha Wildner     sizeof(acpi_install_interface));
252fa21302bSSascha Wildner static char acpi_remove_interface[256];
253fa21302bSSascha Wildner TUNABLE_STR("hw.acpi.remove_interface", acpi_remove_interface,
254fa21302bSSascha Wildner     sizeof(acpi_remove_interface));
255fa21302bSSascha Wildner 
256fa21302bSSascha Wildner /*
25769eedf55SSascha Wildner  * Use this tunable to disable the control method auto-serialization
25869eedf55SSascha Wildner  * mechanism that was added in 20140214 and superseded the previous
25969eedf55SSascha Wildner  * AcpiGbl_SerializeAllMethods global.
2605db2f26eSSascha Wildner  */
2616a0135c2SSascha Wildner static int acpi_auto_serialize_methods = 1;
2626a0135c2SSascha Wildner TUNABLE_INT("hw.acpi.auto_serialize_methods", &acpi_auto_serialize_methods);
2635db2f26eSSascha Wildner 
264586fced2SSascha Wildner /* Allow users to dump Debug objects without ACPI debugger. */
265586fced2SSascha Wildner static int acpi_debug_objects;
266586fced2SSascha Wildner TUNABLE_INT("debug.acpi.enable_debug_objects", &acpi_debug_objects);
267586fced2SSascha Wildner SYSCTL_PROC(_debug_acpi, OID_AUTO, enable_debug_objects,
268586fced2SSascha Wildner     CTLFLAG_RW | CTLTYPE_INT, NULL, 0, acpi_debug_objects_sysctl, "I",
269be787952SSascha Wildner     "Enable Debug objects.");
270be787952SSascha Wildner 
271be787952SSascha Wildner /* Allow ignoring the XSDT. */
272be787952SSascha Wildner static int acpi_ignore_xsdt;
273be787952SSascha Wildner TUNABLE_INT("debug.acpi.ignore_xsdt", &acpi_ignore_xsdt);
274be787952SSascha Wildner SYSCTL_INT(_debug_acpi, OID_AUTO, ignore_xsdt, CTLFLAG_RD,
275be787952SSascha Wildner     &acpi_ignore_xsdt, 1, "Ignore the XSDT, forcing the use of the RSDT.");
276586fced2SSascha Wildner 
2778157a750SSascha Wildner /* Allow the interpreter to ignore common mistakes in BIOS. */
2788157a750SSascha Wildner static int acpi_interpreter_slack = 1;
2798157a750SSascha Wildner TUNABLE_INT("debug.acpi.interpreter_slack", &acpi_interpreter_slack);
2808157a750SSascha Wildner SYSCTL_INT(_debug_acpi, OID_AUTO, interpreter_slack, CTLFLAG_RD,
2818157a750SSascha Wildner     &acpi_interpreter_slack, 1, "Turn on interpreter slack mode.");
2828157a750SSascha Wildner 
283be787952SSascha Wildner /* Allow preferring 32-bit FADT register addresses over the 64-bit ones. */
284be787952SSascha Wildner static int acpi_fadt_addr32;
285be787952SSascha Wildner TUNABLE_INT("debug.acpi.fadt_addr32", &acpi_fadt_addr32);
286be787952SSascha Wildner SYSCTL_INT(_debug_acpi, OID_AUTO, fadt_addr32, CTLFLAG_RD,
287be787952SSascha Wildner     &acpi_fadt_addr32, 1,
288be787952SSascha Wildner     "Prefer 32-bit FADT register addresses over 64-bit ones.");
289be787952SSascha Wildner 
29025ca8c79SSascha Wildner /* Prefer 32-bit FACS table addresses over the 64-bit ones. */
29125ca8c79SSascha Wildner static int acpi_facs_addr32 = 1;
29225ca8c79SSascha Wildner TUNABLE_INT("debug.acpi.facs_addr32", &acpi_facs_addr32);
29325ca8c79SSascha Wildner SYSCTL_INT(_debug_acpi, OID_AUTO, facs_addr32, CTLFLAG_RD,
29425ca8c79SSascha Wildner     &acpi_facs_addr32, 1,
29525ca8c79SSascha Wildner     "Prefer 32-bit FACS table addresses over 64-bit ones.");
29625ca8c79SSascha Wildner 
2975db2f26eSSascha Wildner /* Power devices off and on in suspend and resume.  XXX Remove once tested. */
2985db2f26eSSascha Wildner static int acpi_do_powerstate = 1;
2995db2f26eSSascha Wildner TUNABLE_INT("debug.acpi.do_powerstate", &acpi_do_powerstate);
3005db2f26eSSascha Wildner SYSCTL_INT(_debug_acpi, OID_AUTO, do_powerstate, CTLFLAG_RW,
3015db2f26eSSascha Wildner     &acpi_do_powerstate, 1, "Turn off devices when suspending.");
3025db2f26eSSascha Wildner 
3035db2f26eSSascha Wildner /* Allow users to override quirks. */
3045db2f26eSSascha Wildner TUNABLE_INT("debug.acpi.quirks", &acpi_quirks);
3055db2f26eSSascha Wildner 
306279dd846SSascha Wildner /* Allow to call ACPI methods from userland. */
307279dd846SSascha Wildner static int acpi_allow_mcall;
308279dd846SSascha Wildner TUNABLE_INT("debug.acpi.allow_method_calls", &acpi_allow_mcall);
309279dd846SSascha Wildner 
3105db2f26eSSascha Wildner static int acpi_susp_bounce;
3115db2f26eSSascha Wildner SYSCTL_INT(_debug_acpi, OID_AUTO, suspend_bounce, CTLFLAG_RW,
3125db2f26eSSascha Wildner     &acpi_susp_bounce, 0, "Don't actually suspend, just test devices.");
3135db2f26eSSascha Wildner 
3145db2f26eSSascha Wildner /*
3155db2f26eSSascha Wildner  * ACPI can only be loaded as a module by the loader; activating it after
3165db2f26eSSascha Wildner  * system bootstrap time is not useful, and can be fatal to the system.
3175db2f26eSSascha Wildner  * It also cannot be unloaded, since the entire system bus heirarchy hangs
3185db2f26eSSascha Wildner  * off it.
3195db2f26eSSascha Wildner  */
3205db2f26eSSascha Wildner static int
acpi_modevent(struct module * mod,int event,void * junk)3215db2f26eSSascha Wildner acpi_modevent(struct module *mod, int event, void *junk)
3225db2f26eSSascha Wildner {
3235db2f26eSSascha Wildner     switch (event) {
3245db2f26eSSascha Wildner     case MOD_LOAD:
3255db2f26eSSascha Wildner 	if (!cold) {
3265db2f26eSSascha Wildner 	    kprintf("The ACPI driver cannot be loaded after boot.\n");
3275db2f26eSSascha Wildner 	    return (EPERM);
3285db2f26eSSascha Wildner 	}
3295db2f26eSSascha Wildner 	break;
3305db2f26eSSascha Wildner     case MOD_UNLOAD:
3315db2f26eSSascha Wildner 	if (!cold && power_pm_get_type() == POWER_PM_TYPE_ACPI)
3325db2f26eSSascha Wildner 	    return (EBUSY);
3335db2f26eSSascha Wildner 	break;
3345db2f26eSSascha Wildner     default:
3355db2f26eSSascha Wildner 	break;
3365db2f26eSSascha Wildner     }
3375db2f26eSSascha Wildner     return (0);
3385db2f26eSSascha Wildner }
3395db2f26eSSascha Wildner 
3405db2f26eSSascha Wildner /*
3415db2f26eSSascha Wildner  * Perform early initialization.
3425db2f26eSSascha Wildner  */
3435db2f26eSSascha Wildner ACPI_STATUS
acpi_Startup(void)3445db2f26eSSascha Wildner acpi_Startup(void)
3455db2f26eSSascha Wildner {
3465db2f26eSSascha Wildner     static int started = 0;
3475db2f26eSSascha Wildner     ACPI_STATUS status;
3485db2f26eSSascha Wildner     int val;
3495db2f26eSSascha Wildner 
3505db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
3515db2f26eSSascha Wildner 
3525db2f26eSSascha Wildner     /* Only run the startup code once.  The MADT driver also calls this. */
3535db2f26eSSascha Wildner     if (started)
3545db2f26eSSascha Wildner 	return_VALUE (AE_OK);
3555db2f26eSSascha Wildner     started = 1;
3565db2f26eSSascha Wildner 
35729edcb1cSSascha Wildner     /* Start up the ACPICA subsystem. */
35829edcb1cSSascha Wildner     status = AcpiInitializeSubsystem();
35929edcb1cSSascha Wildner     if (ACPI_FAILURE(status)) {
36029edcb1cSSascha Wildner 	kprintf("ACPI: Subsystem initialization failed: %s\n",
36129edcb1cSSascha Wildner 	    AcpiFormatException(status));
36229edcb1cSSascha Wildner 	return_VALUE (status);
36329edcb1cSSascha Wildner     }
36429edcb1cSSascha Wildner 
3655db2f26eSSascha Wildner     /*
3665db2f26eSSascha Wildner      * Pre-allocate space for RSDT/XSDT and DSDT tables and allow resizing
3675db2f26eSSascha Wildner      * if more tables exist.
3685db2f26eSSascha Wildner      */
3695db2f26eSSascha Wildner     if (ACPI_FAILURE(status = AcpiInitializeTables(NULL, 2, TRUE))) {
37029edcb1cSSascha Wildner 	kprintf("ACPI: Table initialization failed: %s\n",
3715db2f26eSSascha Wildner 	    AcpiFormatException(status));
3725db2f26eSSascha Wildner 	return_VALUE (status);
3735db2f26eSSascha Wildner     }
3745db2f26eSSascha Wildner 
3755db2f26eSSascha Wildner     /* Set up any quirks we have for this system. */
3765db2f26eSSascha Wildner     if (acpi_quirks == ACPI_Q_OK)
3775db2f26eSSascha Wildner 	acpi_table_quirks(&acpi_quirks);
3785db2f26eSSascha Wildner 
3795db2f26eSSascha Wildner     /* If the user manually set the disabled hint to 0, force-enable ACPI. */
3805db2f26eSSascha Wildner     if (resource_int_value("acpi", 0, "disabled", &val) == 0 && val == 0)
3815db2f26eSSascha Wildner 	acpi_quirks &= ~ACPI_Q_BROKEN;
3825db2f26eSSascha Wildner     if (acpi_quirks & ACPI_Q_BROKEN) {
3835db2f26eSSascha Wildner 	kprintf("ACPI disabled by blacklist.  Contact your BIOS vendor.\n");
3845db2f26eSSascha Wildner 	status = AE_SUPPORT;
3855db2f26eSSascha Wildner     }
3865db2f26eSSascha Wildner 
3875db2f26eSSascha Wildner     return_VALUE (status);
3885db2f26eSSascha Wildner }
3895db2f26eSSascha Wildner 
3905db2f26eSSascha Wildner /*
3915db2f26eSSascha Wildner  * Detect ACPI, perform early initialisation
3925db2f26eSSascha Wildner  */
3935db2f26eSSascha Wildner static void
acpi_identify(driver_t * driver,device_t parent)3945db2f26eSSascha Wildner acpi_identify(driver_t *driver, device_t parent)
3955db2f26eSSascha Wildner {
3965db2f26eSSascha Wildner     device_t	child;
3975db2f26eSSascha Wildner 
3985db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
3995db2f26eSSascha Wildner 
4005db2f26eSSascha Wildner     if (!cold)
4015db2f26eSSascha Wildner 	return_VOID;
4025db2f26eSSascha Wildner 
4035db2f26eSSascha Wildner     /* Check that we haven't been disabled with a hint. */
4045db2f26eSSascha Wildner     if (resource_disabled("acpi", 0))
4055db2f26eSSascha Wildner 	return_VOID;
4065db2f26eSSascha Wildner 
4075db2f26eSSascha Wildner     /* Make sure we're not being doubly invoked. */
4085db2f26eSSascha Wildner     if (device_find_child(parent, "acpi", 0) != NULL)
4095db2f26eSSascha Wildner 	return_VOID;
4105db2f26eSSascha Wildner 
4115db2f26eSSascha Wildner     ksnprintf(acpi_ca_version, sizeof(acpi_ca_version), "%x", ACPI_CA_VERSION);
4125db2f26eSSascha Wildner 
4135db2f26eSSascha Wildner     /* Initialize root tables. */
4145db2f26eSSascha Wildner     if (ACPI_FAILURE(acpi_Startup())) {
4155db2f26eSSascha Wildner 	kprintf("ACPI: Try disabling either ACPI or apic support.\n");
4165db2f26eSSascha Wildner 	return_VOID;
4175db2f26eSSascha Wildner     }
4185db2f26eSSascha Wildner 
4195db2f26eSSascha Wildner     /* Attach the actual ACPI device. */
4205db2f26eSSascha Wildner     if ((child = BUS_ADD_CHILD(parent, parent, 10, "acpi", 0)) == NULL) {
4215db2f26eSSascha Wildner 	device_printf(parent, "device_identify failed\n");
4225db2f26eSSascha Wildner 	return_VOID;
4235db2f26eSSascha Wildner     }
4245db2f26eSSascha Wildner }
4255db2f26eSSascha Wildner 
4265db2f26eSSascha Wildner /*
4275db2f26eSSascha Wildner  * Fetch some descriptive data from ACPI to put in our attach message.
4285db2f26eSSascha Wildner  */
4295db2f26eSSascha Wildner static int
acpi_probe(device_t dev)4305db2f26eSSascha Wildner acpi_probe(device_t dev)
4315db2f26eSSascha Wildner {
4325db2f26eSSascha Wildner     ACPI_TABLE_RSDP	*rsdp;
4335db2f26eSSascha Wildner     ACPI_TABLE_HEADER	*rsdt;
4345db2f26eSSascha Wildner     ACPI_PHYSICAL_ADDRESS paddr;
4355db2f26eSSascha Wildner     char		buf[ACPI_OEM_ID_SIZE + ACPI_OEM_TABLE_ID_SIZE + 2];
4365db2f26eSSascha Wildner     struct sbuf		sb;
4375db2f26eSSascha Wildner 
4385db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
4395db2f26eSSascha Wildner 
4405db2f26eSSascha Wildner     if (power_pm_get_type() != POWER_PM_TYPE_NONE &&
4415db2f26eSSascha Wildner 	power_pm_get_type() != POWER_PM_TYPE_ACPI) {
4425db2f26eSSascha Wildner 	device_printf(dev, "probe failed, other PM system enabled.\n");
4435db2f26eSSascha Wildner 	return_VALUE (ENXIO);
4445db2f26eSSascha Wildner     }
4455db2f26eSSascha Wildner 
4465db2f26eSSascha Wildner     if ((paddr = AcpiOsGetRootPointer()) == 0 ||
4475db2f26eSSascha Wildner 	(rsdp = AcpiOsMapMemory(paddr, sizeof(ACPI_TABLE_RSDP))) == NULL)
4485db2f26eSSascha Wildner 	return_VALUE (ENXIO);
449be787952SSascha Wildner     if (acpi_ignore_xsdt == 0 &&
450be787952SSascha Wildner 	rsdp->Revision > 1 && rsdp->XsdtPhysicalAddress != 0)
4515db2f26eSSascha Wildner 	paddr = (ACPI_PHYSICAL_ADDRESS)rsdp->XsdtPhysicalAddress;
4525db2f26eSSascha Wildner     else
4535db2f26eSSascha Wildner 	paddr = (ACPI_PHYSICAL_ADDRESS)rsdp->RsdtPhysicalAddress;
4545db2f26eSSascha Wildner     AcpiOsUnmapMemory(rsdp, sizeof(ACPI_TABLE_RSDP));
4555db2f26eSSascha Wildner 
4565db2f26eSSascha Wildner     if ((rsdt = AcpiOsMapMemory(paddr, sizeof(ACPI_TABLE_HEADER))) == NULL)
4575db2f26eSSascha Wildner 	return_VALUE (ENXIO);
4585db2f26eSSascha Wildner     sbuf_new(&sb, buf, sizeof(buf), SBUF_FIXEDLEN);
4595db2f26eSSascha Wildner     sbuf_bcat(&sb, rsdt->OemId, ACPI_OEM_ID_SIZE);
4605db2f26eSSascha Wildner     sbuf_trim(&sb);
4615db2f26eSSascha Wildner     sbuf_putc(&sb, ' ');
4625db2f26eSSascha Wildner     sbuf_bcat(&sb, rsdt->OemTableId, ACPI_OEM_TABLE_ID_SIZE);
4635db2f26eSSascha Wildner     sbuf_trim(&sb);
4645db2f26eSSascha Wildner     sbuf_finish(&sb);
4655db2f26eSSascha Wildner     device_set_desc_copy(dev, sbuf_data(&sb));
4665db2f26eSSascha Wildner     sbuf_delete(&sb);
4675db2f26eSSascha Wildner     AcpiOsUnmapMemory(rsdt, sizeof(ACPI_TABLE_HEADER));
4685db2f26eSSascha Wildner 
4695db2f26eSSascha Wildner     return_VALUE (0);
4705db2f26eSSascha Wildner }
4715db2f26eSSascha Wildner 
4725db2f26eSSascha Wildner static int
acpi_attach(device_t dev)4735db2f26eSSascha Wildner acpi_attach(device_t dev)
4745db2f26eSSascha Wildner {
4755db2f26eSSascha Wildner     struct acpi_softc	*sc;
4765db2f26eSSascha Wildner     ACPI_STATUS		status;
4775db2f26eSSascha Wildner     int			error, state;
4785db2f26eSSascha Wildner     UINT32		flags;
4795db2f26eSSascha Wildner     UINT8		TypeA, TypeB;
4805db2f26eSSascha Wildner     char		*env;
4815db2f26eSSascha Wildner 
4825db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
4835db2f26eSSascha Wildner 
4845db2f26eSSascha Wildner     sc = device_get_softc(dev);
4855db2f26eSSascha Wildner     sc->acpi_dev = dev;
4865db2f26eSSascha Wildner     callout_init(&sc->susp_force_to);
4875db2f26eSSascha Wildner 
4885db2f26eSSascha Wildner     if ((error = acpi_task_thread_init())) {
4895db2f26eSSascha Wildner         device_printf(dev, "Could not start task thread.\n");
4907252c37cSMatthew Dillon         goto out2;
4915db2f26eSSascha Wildner     }
4925db2f26eSSascha Wildner 
4935db2f26eSSascha Wildner     error = ENXIO;
4945db2f26eSSascha Wildner 
4955db2f26eSSascha Wildner     /* Initialize resource manager. */
4965db2f26eSSascha Wildner     acpi_rman_io.rm_type = RMAN_ARRAY;
4975db2f26eSSascha Wildner     acpi_rman_io.rm_start = 0;
4985db2f26eSSascha Wildner     acpi_rman_io.rm_end = 0xffff;
4995db2f26eSSascha Wildner     acpi_rman_io.rm_descr = "ACPI I/O ports";
5005db2f26eSSascha Wildner     if (rman_init(&acpi_rman_io, -1) != 0)
5015db2f26eSSascha Wildner 	panic("acpi rman_init IO ports failed");
5025db2f26eSSascha Wildner     acpi_rman_mem.rm_type = RMAN_ARRAY;
5035db2f26eSSascha Wildner     acpi_rman_mem.rm_start = 0;
5045db2f26eSSascha Wildner     acpi_rman_mem.rm_end = ~0ul;
5055db2f26eSSascha Wildner     acpi_rman_mem.rm_descr = "ACPI I/O memory addresses";
5065db2f26eSSascha Wildner     if (rman_init(&acpi_rman_mem, -1) != 0)
5075db2f26eSSascha Wildner 	panic("acpi rman_init memory failed");
5085db2f26eSSascha Wildner 
5095db2f26eSSascha Wildner     /* Initialise the ACPI mutex */
5105db2f26eSSascha Wildner     ACPI_LOCK_INIT(acpi, "acpi");
5115db2f26eSSascha Wildner     ACPI_SERIAL_INIT(acpi);
5125db2f26eSSascha Wildner 
5137252c37cSMatthew Dillon     ACPI_LOCK(acpi);
5147252c37cSMatthew Dillon 
5155db2f26eSSascha Wildner     /*
5169d1f0c52SSascha Wildner      * Set the globals from our tunables.  This is needed because ACPICA
5175db2f26eSSascha Wildner      * uses UINT8 for some values and we have no tunable_byte.
5185db2f26eSSascha Wildner      */
5198157a750SSascha Wildner     AcpiGbl_AutoSerializeMethods = acpi_auto_serialize_methods ? TRUE : FALSE;
520be787952SSascha Wildner     AcpiGbl_DoNotUseXsdt = acpi_ignore_xsdt ? TRUE : FALSE;
521586fced2SSascha Wildner     AcpiGbl_EnableAmlDebugObject = acpi_debug_objects ? TRUE : FALSE;
522be787952SSascha Wildner     AcpiGbl_EnableInterpreterSlack = acpi_interpreter_slack ? TRUE : FALSE;
523be787952SSascha Wildner     AcpiGbl_Use32BitFadtAddresses = acpi_fadt_addr32 ? TRUE : FALSE;
52425ca8c79SSascha Wildner     AcpiGbl_Use32BitFacsAddresses = acpi_facs_addr32 ? TRUE : FALSE;
525586fced2SSascha Wildner 
526586fced2SSascha Wildner #ifndef ACPI_DEBUG
527586fced2SSascha Wildner     /*
528586fced2SSascha Wildner      * Disable Debug Object output.
529586fced2SSascha Wildner      */
530586fced2SSascha Wildner     AcpiDbgLevel &= ~ACPI_LV_DEBUG_OBJECT;
531586fced2SSascha Wildner #endif
5325db2f26eSSascha Wildner 
533fa21302bSSascha Wildner     /* Override OS interfaces if the user requested. */
534fa21302bSSascha Wildner     acpi_reset_interfaces(dev);
535fa21302bSSascha Wildner 
5365db2f26eSSascha Wildner     /* Load ACPI name space. */
5375db2f26eSSascha Wildner     status = AcpiLoadTables();
5385db2f26eSSascha Wildner     if (ACPI_FAILURE(status)) {
5395db2f26eSSascha Wildner 	device_printf(dev, "Could not load Namespace: %s\n",
5405db2f26eSSascha Wildner 		      AcpiFormatException(status));
5415db2f26eSSascha Wildner 	goto out;
5425db2f26eSSascha Wildner     }
5435db2f26eSSascha Wildner 
5445db2f26eSSascha Wildner     /* Handle MCFG table if present. */
5455db2f26eSSascha Wildner     acpi_enable_pcie();
5465db2f26eSSascha Wildner 
5475db2f26eSSascha Wildner     /*
5485db2f26eSSascha Wildner      * Note that some systems (specifically, those with namespace evaluation
5495db2f26eSSascha Wildner      * issues that require the avoidance of parts of the namespace) must
5505db2f26eSSascha Wildner      * avoid running _INI and _STA on everything, as well as dodging the final
5515db2f26eSSascha Wildner      * object init pass.
5525db2f26eSSascha Wildner      *
5535db2f26eSSascha Wildner      * For these devices, we set ACPI_NO_DEVICE_INIT and ACPI_NO_OBJECT_INIT).
5545db2f26eSSascha Wildner      *
5555db2f26eSSascha Wildner      * XXX We should arrange for the object init pass after we have attached
5565db2f26eSSascha Wildner      *     all our child devices, but on many systems it works here.
5575db2f26eSSascha Wildner      */
558cd19a012SSascha Wildner     flags = ACPI_FULL_INITIALIZATION;
5595db2f26eSSascha Wildner     if (ktestenv("debug.acpi.avoid"))
5605db2f26eSSascha Wildner 	flags = ACPI_NO_DEVICE_INIT | ACPI_NO_OBJECT_INIT;
5615db2f26eSSascha Wildner 
5625db2f26eSSascha Wildner     /* Bring the hardware and basic handlers online. */
5635db2f26eSSascha Wildner     if (ACPI_FAILURE(status = AcpiEnableSubsystem(flags))) {
5645db2f26eSSascha Wildner 	device_printf(dev, "Could not enable ACPI: %s\n",
5655db2f26eSSascha Wildner 		      AcpiFormatException(status));
5665db2f26eSSascha Wildner 	goto out;
5675db2f26eSSascha Wildner     }
5685db2f26eSSascha Wildner 
5695db2f26eSSascha Wildner     /*
5705db2f26eSSascha Wildner      * Fix up the interrupt timer after enabling ACPI, so that the
5715db2f26eSSascha Wildner      * interrupt cputimer that choked by ACPI power management could
5725db2f26eSSascha Wildner      * be resurrected before probing various devices.
5735db2f26eSSascha Wildner      */
5745db2f26eSSascha Wildner     DELAY(5000);
5755db2f26eSSascha Wildner     cputimer_intr_pmfixup();
5765db2f26eSSascha Wildner 
5775db2f26eSSascha Wildner     /*
5785db2f26eSSascha Wildner      * Call the ECDT probe function to provide EC functionality before
5795db2f26eSSascha Wildner      * the namespace has been evaluated.
5805db2f26eSSascha Wildner      *
5815db2f26eSSascha Wildner      * XXX This happens before the sysresource devices have been probed and
5825db2f26eSSascha Wildner      * attached so its resources come from nexus0.  In practice, this isn't
5835db2f26eSSascha Wildner      * a problem but should be addressed eventually.
5845db2f26eSSascha Wildner      */
5855db2f26eSSascha Wildner     acpi_ec_ecdt_probe(dev);
5865db2f26eSSascha Wildner 
5875db2f26eSSascha Wildner     /* Bring device objects and regions online. */
5885db2f26eSSascha Wildner     if (ACPI_FAILURE(status = AcpiInitializeObjects(flags))) {
5895db2f26eSSascha Wildner 	device_printf(dev, "Could not initialize ACPI objects: %s\n",
5905db2f26eSSascha Wildner 		      AcpiFormatException(status));
5915db2f26eSSascha Wildner 	goto out;
5925db2f26eSSascha Wildner     }
5935db2f26eSSascha Wildner 
5945db2f26eSSascha Wildner     /*
5955db2f26eSSascha Wildner      * Setup our sysctl tree.
5965db2f26eSSascha Wildner      *
5975db2f26eSSascha Wildner      * XXX: This doesn't check to make sure that none of these fail.
5985db2f26eSSascha Wildner      */
5995db2f26eSSascha Wildner     sysctl_ctx_init(&sc->acpi_sysctl_ctx);
6005db2f26eSSascha Wildner     sc->acpi_sysctl_tree = SYSCTL_ADD_NODE(&sc->acpi_sysctl_ctx,
6015db2f26eSSascha Wildner 			       SYSCTL_STATIC_CHILDREN(_hw), OID_AUTO,
6025db2f26eSSascha Wildner 			       device_get_name(dev), CTLFLAG_RD, 0, "");
6035db2f26eSSascha Wildner     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
6045db2f26eSSascha Wildner 	OID_AUTO, "supported_sleep_state", CTLTYPE_STRING | CTLFLAG_RD,
6055db2f26eSSascha Wildner 	0, 0, acpi_supported_sleep_state_sysctl, "A", "");
6065db2f26eSSascha Wildner     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
6075db2f26eSSascha Wildner 	OID_AUTO, "power_button_state", CTLTYPE_STRING | CTLFLAG_RW,
6085db2f26eSSascha Wildner 	&sc->acpi_power_button_sx, 0, acpi_sleep_state_sysctl, "A", "");
6095db2f26eSSascha Wildner     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
6105db2f26eSSascha Wildner 	OID_AUTO, "sleep_button_state", CTLTYPE_STRING | CTLFLAG_RW,
6115db2f26eSSascha Wildner 	&sc->acpi_sleep_button_sx, 0, acpi_sleep_state_sysctl, "A", "");
6125db2f26eSSascha Wildner     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
6135db2f26eSSascha Wildner 	OID_AUTO, "lid_switch_state", CTLTYPE_STRING | CTLFLAG_RW,
6145db2f26eSSascha Wildner 	&sc->acpi_lid_switch_sx, 0, acpi_sleep_state_sysctl, "A", "");
6155db2f26eSSascha Wildner     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
6165db2f26eSSascha Wildner 	OID_AUTO, "standby_state", CTLTYPE_STRING | CTLFLAG_RW,
6175db2f26eSSascha Wildner 	&sc->acpi_standby_sx, 0, acpi_sleep_state_sysctl, "A", "");
6185db2f26eSSascha Wildner     SYSCTL_ADD_PROC(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
6195db2f26eSSascha Wildner 	OID_AUTO, "suspend_state", CTLTYPE_STRING | CTLFLAG_RW,
6205db2f26eSSascha Wildner 	&sc->acpi_suspend_sx, 0, acpi_sleep_state_sysctl, "A", "");
6215db2f26eSSascha Wildner     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
6225db2f26eSSascha Wildner 	OID_AUTO, "sleep_delay", CTLFLAG_RW, &sc->acpi_sleep_delay, 0,
6235db2f26eSSascha Wildner 	"sleep delay");
6245db2f26eSSascha Wildner     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
6255db2f26eSSascha Wildner 	OID_AUTO, "s4bios", CTLFLAG_RW, &sc->acpi_s4bios, 0, "S4BIOS mode");
6265db2f26eSSascha Wildner     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
6275db2f26eSSascha Wildner 	OID_AUTO, "verbose", CTLFLAG_RW, &sc->acpi_verbose, 0, "verbose mode");
6285db2f26eSSascha Wildner     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
6295db2f26eSSascha Wildner 	OID_AUTO, "disable_on_reboot", CTLFLAG_RW,
6305db2f26eSSascha Wildner 	&sc->acpi_do_disable, 0, "Disable ACPI when rebooting/halting system");
6315db2f26eSSascha Wildner     SYSCTL_ADD_INT(&sc->acpi_sysctl_ctx, SYSCTL_CHILDREN(sc->acpi_sysctl_tree),
6325db2f26eSSascha Wildner 	OID_AUTO, "handle_reboot", CTLFLAG_RW,
6335db2f26eSSascha Wildner 	&sc->acpi_handle_reboot, 0, "Use ACPI Reset Register to reboot");
6345db2f26eSSascha Wildner 
6355db2f26eSSascha Wildner     /*
6365db2f26eSSascha Wildner      * Default to 1 second before sleeping to give some machines time to
6375db2f26eSSascha Wildner      * stabilize.
6385db2f26eSSascha Wildner      */
6395db2f26eSSascha Wildner     sc->acpi_sleep_delay = 1;
6405db2f26eSSascha Wildner     if (bootverbose)
6415db2f26eSSascha Wildner 	sc->acpi_verbose = 1;
6425db2f26eSSascha Wildner     if ((env = kgetenv("hw.acpi.verbose")) != NULL) {
6435db2f26eSSascha Wildner 	if (strcmp(env, "0") != 0)
6445db2f26eSSascha Wildner 	    sc->acpi_verbose = 1;
6455db2f26eSSascha Wildner 	kfreeenv(env);
6465db2f26eSSascha Wildner     }
6475db2f26eSSascha Wildner 
6485db2f26eSSascha Wildner     /* Only enable reboot by default if the FADT says it is available. */
6495db2f26eSSascha Wildner     if (AcpiGbl_FADT.Flags & ACPI_FADT_RESET_REGISTER)
6505db2f26eSSascha Wildner 	sc->acpi_handle_reboot = 1;
6515db2f26eSSascha Wildner 
6525db2f26eSSascha Wildner     /* Only enable S4BIOS by default if the FACS says it is available. */
6535db2f26eSSascha Wildner     if (AcpiGbl_FACS->Flags & ACPI_FACS_S4_BIOS_PRESENT)
6545db2f26eSSascha Wildner 	sc->acpi_s4bios = 1;
6555db2f26eSSascha Wildner 
6565db2f26eSSascha Wildner     /*
6575db2f26eSSascha Wildner      * Dispatch the default sleep state to devices.  The lid switch is set
6585db2f26eSSascha Wildner      * to NONE by default to avoid surprising users.
6595db2f26eSSascha Wildner      */
6605db2f26eSSascha Wildner     sc->acpi_power_button_sx = ACPI_STATE_S5;
6615db2f26eSSascha Wildner     sc->acpi_lid_switch_sx = ACPI_S_STATES_MAX + 1;
6625db2f26eSSascha Wildner     sc->acpi_standby_sx = ACPI_STATE_S1;
6635db2f26eSSascha Wildner     sc->acpi_suspend_sx = ACPI_STATE_S3;
6645db2f26eSSascha Wildner 
6655db2f26eSSascha Wildner     /* Pick the first valid sleep state for the sleep button default. */
6665db2f26eSSascha Wildner     sc->acpi_sleep_button_sx = ACPI_S_STATES_MAX + 1;
6675db2f26eSSascha Wildner     for (state = ACPI_STATE_S1; state <= ACPI_STATE_S4; state++)
6685db2f26eSSascha Wildner 	if (ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB))) {
6695db2f26eSSascha Wildner 	    sc->acpi_sleep_button_sx = state;
6705db2f26eSSascha Wildner 	    break;
6715db2f26eSSascha Wildner 	}
6725db2f26eSSascha Wildner 
6735db2f26eSSascha Wildner     acpi_enable_fixed_events(sc);
6745db2f26eSSascha Wildner 
6755db2f26eSSascha Wildner     /*
6765db2f26eSSascha Wildner      * Scan the namespace and attach/initialise children.
6775db2f26eSSascha Wildner      */
6785db2f26eSSascha Wildner 
6795db2f26eSSascha Wildner     /* Register our shutdown handler. */
6805db2f26eSSascha Wildner     EVENTHANDLER_REGISTER(shutdown_final, acpi_shutdown_final, sc,
6815db2f26eSSascha Wildner 	SHUTDOWN_PRI_LAST);
6825db2f26eSSascha Wildner 
6835db2f26eSSascha Wildner     /*
6845db2f26eSSascha Wildner      * Register our acpi event handlers.
6855db2f26eSSascha Wildner      * XXX should be configurable eg. via userland policy manager.
6865db2f26eSSascha Wildner      */
6875db2f26eSSascha Wildner     EVENTHANDLER_REGISTER(acpi_sleep_event, acpi_system_eventhandler_sleep,
6885db2f26eSSascha Wildner 	sc, ACPI_EVENT_PRI_LAST);
6895db2f26eSSascha Wildner     EVENTHANDLER_REGISTER(acpi_wakeup_event, acpi_system_eventhandler_wakeup,
6905db2f26eSSascha Wildner 	sc, ACPI_EVENT_PRI_LAST);
6915db2f26eSSascha Wildner 
6925db2f26eSSascha Wildner     /* Flag our initial states. */
6935db2f26eSSascha Wildner     sc->acpi_enabled = 1;
6945db2f26eSSascha Wildner     sc->acpi_sstate = ACPI_STATE_S0;
6955db2f26eSSascha Wildner     sc->acpi_sleep_disabled = 0;
6965db2f26eSSascha Wildner     /* Create the control device */
6971e621377SSascha Wildner     sc->acpi_dev_t = make_dev(&acpi_ops, 0, UID_ROOT, GID_WHEEL, 0644, "acpi");
6985db2f26eSSascha Wildner     sc->acpi_dev_t->si_drv1 = sc;
6995db2f26eSSascha Wildner 
7005db2f26eSSascha Wildner     if ((error = acpi_machdep_init(dev)))
7015db2f26eSSascha Wildner 	goto out;
7025db2f26eSSascha Wildner 
7035db2f26eSSascha Wildner     /* Register ACPI again to pass the correct argument of pm_func. */
7045db2f26eSSascha Wildner     power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, sc);
7055db2f26eSSascha Wildner 
7065db2f26eSSascha Wildner     if (!acpi_disabled("bus"))
7075db2f26eSSascha Wildner 	acpi_probe_children(dev);
7085db2f26eSSascha Wildner 
7095db2f26eSSascha Wildner     /* Update all GPEs and enable runtime GPEs. */
7105db2f26eSSascha Wildner     status = AcpiUpdateAllGpes();
7115db2f26eSSascha Wildner     if (ACPI_FAILURE(status)) {
7125db2f26eSSascha Wildner 	device_printf(dev, "Could not update all GPEs: %s\n",
7135db2f26eSSascha Wildner 		      AcpiFormatException(status));
7145db2f26eSSascha Wildner     }
7155db2f26eSSascha Wildner 
7165db2f26eSSascha Wildner     /* Allow sleep request after a while. */
7175db2f26eSSascha Wildner     /* timeout(acpi_sleep_enable, sc, hz * ACPI_MINIMUM_AWAKETIME); */
7185db2f26eSSascha Wildner 
7195db2f26eSSascha Wildner     error = 0;
7205db2f26eSSascha Wildner 
7215db2f26eSSascha Wildner  out:
7227252c37cSMatthew Dillon     ACPI_UNLOCK(acpi);
7237252c37cSMatthew Dillon  out2:
7245db2f26eSSascha Wildner     cputimer_intr_pmfixup();
725bde01544SSepherosa Ziehau     acpi_task_thread_schedule();
7267252c37cSMatthew Dillon 
7275db2f26eSSascha Wildner     return_VALUE (error);
7285db2f26eSSascha Wildner }
7295db2f26eSSascha Wildner 
7305db2f26eSSascha Wildner static int
acpi_suspend(device_t dev)7315db2f26eSSascha Wildner acpi_suspend(device_t dev)
7325db2f26eSSascha Wildner {
7335db2f26eSSascha Wildner     device_t child, *devlist;
7345db2f26eSSascha Wildner     int error, i, numdevs, pstate;
7355db2f26eSSascha Wildner 
7365db2f26eSSascha Wildner     /* First give child devices a chance to suspend. */
7375db2f26eSSascha Wildner     error = bus_generic_suspend(dev);
7385db2f26eSSascha Wildner     if (error)
7395db2f26eSSascha Wildner 	return (error);
7405db2f26eSSascha Wildner 
7415db2f26eSSascha Wildner     /*
7425db2f26eSSascha Wildner      * Now, set them into the appropriate power state, usually D3.  If the
7435db2f26eSSascha Wildner      * device has an _SxD method for the next sleep state, use that power
7445db2f26eSSascha Wildner      * state instead.
7455db2f26eSSascha Wildner      */
7465db2f26eSSascha Wildner     device_get_children(dev, &devlist, &numdevs);
7475db2f26eSSascha Wildner     for (i = 0; i < numdevs; i++) {
7485db2f26eSSascha Wildner 	/* If the device is not attached, we've powered it down elsewhere. */
7495db2f26eSSascha Wildner 	child = devlist[i];
7505db2f26eSSascha Wildner 	if (!device_is_attached(child))
7515db2f26eSSascha Wildner 	    continue;
7525db2f26eSSascha Wildner 
7535db2f26eSSascha Wildner 	/*
7545db2f26eSSascha Wildner 	 * Default to D3 for all sleep states.  The _SxD method is optional
7555db2f26eSSascha Wildner 	 * so set the powerstate even if it's absent.
7565db2f26eSSascha Wildner 	 */
7575db2f26eSSascha Wildner 	pstate = PCI_POWERSTATE_D3;
7585db2f26eSSascha Wildner 	error = acpi_device_pwr_for_sleep(device_get_parent(child),
7595db2f26eSSascha Wildner 	    child, &pstate);
7605db2f26eSSascha Wildner 	if ((error == 0 || error == ESRCH) && acpi_do_powerstate)
7615db2f26eSSascha Wildner 	    pci_set_powerstate(child, pstate);
7625db2f26eSSascha Wildner     }
7635db2f26eSSascha Wildner     kfree(devlist, M_TEMP);
7645db2f26eSSascha Wildner     error = 0;
7655db2f26eSSascha Wildner 
7665db2f26eSSascha Wildner     return (error);
7675db2f26eSSascha Wildner }
7685db2f26eSSascha Wildner 
7695db2f26eSSascha Wildner static int
acpi_resume(device_t dev)7705db2f26eSSascha Wildner acpi_resume(device_t dev)
7715db2f26eSSascha Wildner {
7725db2f26eSSascha Wildner     ACPI_HANDLE handle;
7735db2f26eSSascha Wildner     int i, numdevs;
7745db2f26eSSascha Wildner     device_t child, *devlist;
7755db2f26eSSascha Wildner 
7765db2f26eSSascha Wildner     /*
7775db2f26eSSascha Wildner      * Put all devices in D0 before resuming them.  Call _S0D on each one
7785db2f26eSSascha Wildner      * since some systems expect this.
7795db2f26eSSascha Wildner      */
7805db2f26eSSascha Wildner     device_get_children(dev, &devlist, &numdevs);
7815db2f26eSSascha Wildner     for (i = 0; i < numdevs; i++) {
7825db2f26eSSascha Wildner 	child = devlist[i];
7835db2f26eSSascha Wildner 	handle = acpi_get_handle(child);
7845db2f26eSSascha Wildner 	if (handle)
7855db2f26eSSascha Wildner 	    AcpiEvaluateObject(handle, "_S0D", NULL, NULL);
7865db2f26eSSascha Wildner 	if (device_is_attached(child) && acpi_do_powerstate)
7875db2f26eSSascha Wildner 	    pci_set_powerstate(child, PCI_POWERSTATE_D0);
7885db2f26eSSascha Wildner     }
7895db2f26eSSascha Wildner     kfree(devlist, M_TEMP);
7905db2f26eSSascha Wildner 
7915db2f26eSSascha Wildner     return (bus_generic_resume(dev));
7925db2f26eSSascha Wildner }
7935db2f26eSSascha Wildner 
7945db2f26eSSascha Wildner static int
acpi_shutdown(device_t dev)7955db2f26eSSascha Wildner acpi_shutdown(device_t dev)
7965db2f26eSSascha Wildner {
7975db2f26eSSascha Wildner     /* Allow children to shutdown first. */
7985db2f26eSSascha Wildner     bus_generic_shutdown(dev);
7995db2f26eSSascha Wildner 
8005db2f26eSSascha Wildner     /*
8015db2f26eSSascha Wildner      * Enable any GPEs that are able to power-on the system (i.e., RTC).
8025db2f26eSSascha Wildner      * Also, disable any that are not valid for this state (most).
8035db2f26eSSascha Wildner      */
8045db2f26eSSascha Wildner     acpi_wake_prep_walk(ACPI_STATE_S5);
8055db2f26eSSascha Wildner 
8065db2f26eSSascha Wildner     return (0);
8075db2f26eSSascha Wildner }
8085db2f26eSSascha Wildner 
8095db2f26eSSascha Wildner /*
8105db2f26eSSascha Wildner  * Handle a new device being added
8115db2f26eSSascha Wildner  */
8125db2f26eSSascha Wildner static device_t
acpi_add_child(device_t bus,device_t parent,int order,const char * name,int unit)8135db2f26eSSascha Wildner acpi_add_child(device_t bus, device_t parent, int order, const char *name, int unit)
8145db2f26eSSascha Wildner {
8155db2f26eSSascha Wildner     struct acpi_device	*ad;
8165db2f26eSSascha Wildner     device_t		child;
8175db2f26eSSascha Wildner 
8185db2f26eSSascha Wildner     if ((ad = kmalloc(sizeof(*ad), M_ACPIDEV, M_NOWAIT | M_ZERO)) == NULL)
8195db2f26eSSascha Wildner 	return (NULL);
8205db2f26eSSascha Wildner 
8215db2f26eSSascha Wildner     resource_list_init(&ad->ad_rl);
8225db2f26eSSascha Wildner     child = device_add_child_ordered(parent, order, name, unit);
8235db2f26eSSascha Wildner     if (child != NULL)
8245db2f26eSSascha Wildner 	device_set_ivars(child, ad);
8255db2f26eSSascha Wildner     else
8265db2f26eSSascha Wildner 	kfree(ad, M_ACPIDEV);
8275db2f26eSSascha Wildner     return (child);
8285db2f26eSSascha Wildner }
8295db2f26eSSascha Wildner 
8305db2f26eSSascha Wildner static int
acpi_print_child(device_t bus,device_t child)8315db2f26eSSascha Wildner acpi_print_child(device_t bus, device_t child)
8325db2f26eSSascha Wildner {
8335db2f26eSSascha Wildner     struct acpi_device	 *adev = device_get_ivars(child);
8345db2f26eSSascha Wildner     struct resource_list *rl = &adev->ad_rl;
8355db2f26eSSascha Wildner     int retval = 0;
8365db2f26eSSascha Wildner 
8375db2f26eSSascha Wildner     retval += bus_print_child_header(bus, child);
8385db2f26eSSascha Wildner     retval += resource_list_print_type(rl, "port",  SYS_RES_IOPORT, "%#lx");
8395db2f26eSSascha Wildner     retval += resource_list_print_type(rl, "iomem", SYS_RES_MEMORY, "%#lx");
8405db2f26eSSascha Wildner     retval += resource_list_print_type(rl, "irq",   SYS_RES_IRQ,    "%ld");
8415db2f26eSSascha Wildner     retval += resource_list_print_type(rl, "drq",   SYS_RES_DRQ,    "%ld");
8425db2f26eSSascha Wildner     if (device_get_flags(child))
8435db2f26eSSascha Wildner 	retval += kprintf(" flags %#x", device_get_flags(child));
8445db2f26eSSascha Wildner     retval += bus_print_child_footer(bus, child);
8455db2f26eSSascha Wildner 
8465db2f26eSSascha Wildner     return (retval);
8475db2f26eSSascha Wildner }
8485db2f26eSSascha Wildner 
8495db2f26eSSascha Wildner /*
8505db2f26eSSascha Wildner  * If this device is an ACPI child but no one claimed it, attempt
8515db2f26eSSascha Wildner  * to power it off.  We'll power it back up when a driver is added.
8525db2f26eSSascha Wildner  *
8535db2f26eSSascha Wildner  * XXX Disabled for now since many necessary devices (like fdc and
8545db2f26eSSascha Wildner  * ATA) don't claim the devices we created for them but still expect
8555db2f26eSSascha Wildner  * them to be powered up.
8565db2f26eSSascha Wildner  */
8575db2f26eSSascha Wildner static void
acpi_probe_nomatch(device_t bus,device_t child)8585db2f26eSSascha Wildner acpi_probe_nomatch(device_t bus, device_t child)
8595db2f26eSSascha Wildner {
8605db2f26eSSascha Wildner 
8615db2f26eSSascha Wildner     /* pci_set_powerstate(child, PCI_POWERSTATE_D3); */
8625db2f26eSSascha Wildner }
8635db2f26eSSascha Wildner 
8645db2f26eSSascha Wildner /*
8655db2f26eSSascha Wildner  * If a new driver has a chance to probe a child, first power it up.
8665db2f26eSSascha Wildner  *
8675db2f26eSSascha Wildner  * XXX Disabled for now (see acpi_probe_nomatch for details).
8685db2f26eSSascha Wildner  */
8695db2f26eSSascha Wildner static void
acpi_driver_added(device_t dev,driver_t * driver)8705db2f26eSSascha Wildner acpi_driver_added(device_t dev, driver_t *driver)
8715db2f26eSSascha Wildner {
8725db2f26eSSascha Wildner     device_t child, *devlist;
8735db2f26eSSascha Wildner     int i, numdevs;
8745db2f26eSSascha Wildner 
8755db2f26eSSascha Wildner     DEVICE_IDENTIFY(driver, dev);
8765db2f26eSSascha Wildner     device_get_children(dev, &devlist, &numdevs);
8775db2f26eSSascha Wildner     for (i = 0; i < numdevs; i++) {
8785db2f26eSSascha Wildner 	child = devlist[i];
8795db2f26eSSascha Wildner 	if (device_get_state(child) == DS_NOTPRESENT) {
8805db2f26eSSascha Wildner 	    /* pci_set_powerstate(child, PCI_POWERSTATE_D0); */
881f05b19acSzrj 	    if (device_probe_and_attach(child) != 0) {
8825db2f26eSSascha Wildner 		; /* pci_set_powerstate(child, PCI_POWERSTATE_D3); */
8835db2f26eSSascha Wildner 	    }
8845db2f26eSSascha Wildner 	}
885f05b19acSzrj     }
8865db2f26eSSascha Wildner     kfree(devlist, M_TEMP);
8875db2f26eSSascha Wildner }
8885db2f26eSSascha Wildner 
8895db2f26eSSascha Wildner /* Location hint for devctl(8) */
8905db2f26eSSascha Wildner static int
acpi_child_location_str_method(device_t cbdev,device_t child,char * buf,size_t buflen)8915db2f26eSSascha Wildner acpi_child_location_str_method(device_t cbdev, device_t child, char *buf,
8925db2f26eSSascha Wildner     size_t buflen)
8935db2f26eSSascha Wildner {
8945db2f26eSSascha Wildner     struct acpi_device *dinfo = device_get_ivars(child);
8955db2f26eSSascha Wildner 
8965db2f26eSSascha Wildner     if (dinfo->ad_handle)
8975db2f26eSSascha Wildner 	ksnprintf(buf, buflen, "handle=%s", acpi_name(dinfo->ad_handle));
8985db2f26eSSascha Wildner     else
8995db2f26eSSascha Wildner 	ksnprintf(buf, buflen, "unknown");
9005db2f26eSSascha Wildner     return (0);
9015db2f26eSSascha Wildner }
9025db2f26eSSascha Wildner 
9035db2f26eSSascha Wildner /* PnP information for devctl(8) */
9045db2f26eSSascha Wildner static int
acpi_child_pnpinfo_str_method(device_t cbdev,device_t child,char * buf,size_t buflen)9055db2f26eSSascha Wildner acpi_child_pnpinfo_str_method(device_t cbdev, device_t child, char *buf,
9065db2f26eSSascha Wildner     size_t buflen)
9075db2f26eSSascha Wildner {
9085db2f26eSSascha Wildner     ACPI_DEVICE_INFO *adinfo;
9095db2f26eSSascha Wildner     struct acpi_device *dinfo = device_get_ivars(child);
9105db2f26eSSascha Wildner 
9116de2a7e6SSascha Wildner     if (ACPI_FAILURE(AcpiGetObjectInfo(dinfo->ad_handle, &adinfo))) {
9125db2f26eSSascha Wildner 	ksnprintf(buf, buflen, "unknown");
9135db2f26eSSascha Wildner     } else {
914a7542d3fSImre Vadász 	ksnprintf(buf, buflen, "_HID=%s _UID=%s",
9155db2f26eSSascha Wildner 		 (adinfo->Valid & ACPI_VALID_HID) ?
9165db2f26eSSascha Wildner 		  adinfo->HardwareId.String : "none",
9175db2f26eSSascha Wildner 		 (adinfo->Valid & ACPI_VALID_UID) ?
918a7542d3fSImre Vadász 		  adinfo->UniqueId.String : "0");
9195db2f26eSSascha Wildner 	AcpiOsFree(adinfo);
9205db2f26eSSascha Wildner     }
9215db2f26eSSascha Wildner     return (0);
9225db2f26eSSascha Wildner }
9235db2f26eSSascha Wildner 
9245db2f26eSSascha Wildner /*
9255db2f26eSSascha Wildner  * Handle per-device ivars
9265db2f26eSSascha Wildner  */
9275db2f26eSSascha Wildner static int
acpi_read_ivar(device_t dev,device_t child,int index,uintptr_t * result)9285db2f26eSSascha Wildner acpi_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
9295db2f26eSSascha Wildner {
9305db2f26eSSascha Wildner     struct acpi_device	*ad;
9315db2f26eSSascha Wildner 
9325db2f26eSSascha Wildner     if ((ad = device_get_ivars(child)) == NULL) {
933e11869f0SSascha Wildner 	device_printf(child, "device has no ivars\n");
9345db2f26eSSascha Wildner 	return (ENOENT);
9355db2f26eSSascha Wildner     }
9365db2f26eSSascha Wildner 
9375db2f26eSSascha Wildner     /* ACPI and ISA compatibility ivars */
9385db2f26eSSascha Wildner     switch(index) {
9395db2f26eSSascha Wildner     case ACPI_IVAR_HANDLE:
9405db2f26eSSascha Wildner 	*(ACPI_HANDLE *)result = ad->ad_handle;
9415db2f26eSSascha Wildner 	break;
9425db2f26eSSascha Wildner     case ACPI_IVAR_MAGIC:
9435db2f26eSSascha Wildner 	*result = ad->ad_magic;
9445db2f26eSSascha Wildner 	break;
9455db2f26eSSascha Wildner     case ACPI_IVAR_PRIVATE:
9465db2f26eSSascha Wildner 	*(void **)result = ad->ad_private;
9475db2f26eSSascha Wildner 	break;
9485db2f26eSSascha Wildner     case ACPI_IVAR_FLAGS:
9495db2f26eSSascha Wildner 	*(int *)result = ad->ad_flags;
9505db2f26eSSascha Wildner 	break;
951ebb7869eSImre Vadász     case ACPI_IVAR_RECHECK:
952ebb7869eSImre Vadász 	*(int *)result = ad->ad_recheck;
953ebb7869eSImre Vadász 	break;
9545db2f26eSSascha Wildner     case ISA_IVAR_VENDORID:
9555db2f26eSSascha Wildner     case ISA_IVAR_SERIAL:
9565db2f26eSSascha Wildner     case ISA_IVAR_COMPATID:
9575db2f26eSSascha Wildner 	*(int *)result = -1;
9585db2f26eSSascha Wildner 	break;
9595db2f26eSSascha Wildner     case ISA_IVAR_LOGICALID:
9605db2f26eSSascha Wildner 	*(int *)result = acpi_isa_get_logicalid(child);
9615db2f26eSSascha Wildner 	break;
9625db2f26eSSascha Wildner     default:
9635db2f26eSSascha Wildner 	return (ENOENT);
9645db2f26eSSascha Wildner     }
9655db2f26eSSascha Wildner 
9665db2f26eSSascha Wildner     return (0);
9675db2f26eSSascha Wildner }
9685db2f26eSSascha Wildner 
9695db2f26eSSascha Wildner static int
acpi_write_ivar(device_t dev,device_t child,int index,uintptr_t value)9705db2f26eSSascha Wildner acpi_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
9715db2f26eSSascha Wildner {
9725db2f26eSSascha Wildner     struct acpi_device	*ad;
9735db2f26eSSascha Wildner 
9745db2f26eSSascha Wildner     if ((ad = device_get_ivars(child)) == NULL) {
975e11869f0SSascha Wildner 	device_printf(child, "device has no ivars\n");
9765db2f26eSSascha Wildner 	return (ENOENT);
9775db2f26eSSascha Wildner     }
9785db2f26eSSascha Wildner 
9795db2f26eSSascha Wildner     switch(index) {
9805db2f26eSSascha Wildner     case ACPI_IVAR_HANDLE:
9815db2f26eSSascha Wildner 	ad->ad_handle = (ACPI_HANDLE)value;
9825db2f26eSSascha Wildner 	break;
9835db2f26eSSascha Wildner     case ACPI_IVAR_MAGIC:
9845db2f26eSSascha Wildner 	ad->ad_magic = value;
9855db2f26eSSascha Wildner 	break;
9865db2f26eSSascha Wildner     case ACPI_IVAR_PRIVATE:
9875db2f26eSSascha Wildner 	ad->ad_private = (void *)value;
9885db2f26eSSascha Wildner 	break;
9895db2f26eSSascha Wildner     case ACPI_IVAR_FLAGS:
9905db2f26eSSascha Wildner 	ad->ad_flags = (int)value;
9915db2f26eSSascha Wildner 	break;
992ebb7869eSImre Vadász     case ACPI_IVAR_RECHECK:
993ebb7869eSImre Vadász 	ad->ad_recheck = (int)value;
994ebb7869eSImre Vadász 	break;
9955db2f26eSSascha Wildner     default:
9965db2f26eSSascha Wildner 	panic("bad ivar write request (%d)", index);
9975db2f26eSSascha Wildner 	return (ENOENT);
9985db2f26eSSascha Wildner     }
9995db2f26eSSascha Wildner 
10005db2f26eSSascha Wildner     return (0);
10015db2f26eSSascha Wildner }
10025db2f26eSSascha Wildner 
10035db2f26eSSascha Wildner /*
10045db2f26eSSascha Wildner  * Handle child resource allocation/removal
10055db2f26eSSascha Wildner  */
10065db2f26eSSascha Wildner static struct resource_list *
acpi_get_rlist(device_t dev,device_t child)10075db2f26eSSascha Wildner acpi_get_rlist(device_t dev, device_t child)
10085db2f26eSSascha Wildner {
10095db2f26eSSascha Wildner     struct acpi_device		*ad;
10105db2f26eSSascha Wildner 
10115db2f26eSSascha Wildner     ad = device_get_ivars(child);
10125db2f26eSSascha Wildner     return (&ad->ad_rl);
10135db2f26eSSascha Wildner }
10145db2f26eSSascha Wildner 
10155db2f26eSSascha Wildner /*
10165db2f26eSSascha Wildner  * Pre-allocate/manage all memory and IO resources.  Since rman can't handle
10175db2f26eSSascha Wildner  * duplicates, we merge any in the sysresource attach routine.
10185db2f26eSSascha Wildner  */
10195db2f26eSSascha Wildner static int
acpi_sysres_alloc(device_t dev)10205db2f26eSSascha Wildner acpi_sysres_alloc(device_t dev)
10215db2f26eSSascha Wildner {
10225db2f26eSSascha Wildner     struct resource *res;
10235db2f26eSSascha Wildner     struct resource_list *rl;
10245db2f26eSSascha Wildner     struct resource_list_entry *rle;
10255db2f26eSSascha Wildner     struct rman *rm;
10265db2f26eSSascha Wildner     char *sysres_ids[] = { "PNP0C01", "PNP0C02", NULL };
10275db2f26eSSascha Wildner     device_t *children;
10285db2f26eSSascha Wildner     int child_count, i;
10295db2f26eSSascha Wildner     /*
10305db2f26eSSascha Wildner      * Probe/attach any sysresource devices.  This would be unnecessary if we
10315db2f26eSSascha Wildner      * had multi-pass probe/attach.
10325db2f26eSSascha Wildner      */
10335db2f26eSSascha Wildner     if (device_get_children(dev, &children, &child_count) != 0)
10345db2f26eSSascha Wildner 	return (ENXIO);
10355db2f26eSSascha Wildner     for (i = 0; i < child_count; i++) {
10365db2f26eSSascha Wildner 	if (ACPI_ID_PROBE(dev, children[i], sysres_ids) != NULL)
10375db2f26eSSascha Wildner 	    device_probe_and_attach(children[i]);
10385db2f26eSSascha Wildner     }
10395db2f26eSSascha Wildner     kfree(children, M_TEMP);
10405db2f26eSSascha Wildner 
10415db2f26eSSascha Wildner     rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
10425db2f26eSSascha Wildner     if(!rl)
10435db2f26eSSascha Wildner 	return 0;
10445db2f26eSSascha Wildner     SLIST_FOREACH(rle, rl, link) {
10455db2f26eSSascha Wildner 	if (rle->res != NULL) {
10465db2f26eSSascha Wildner 	    device_printf(dev, "duplicate resource for %lx\n", rle->start);
10475db2f26eSSascha Wildner 	    continue;
10485db2f26eSSascha Wildner 	}
10495db2f26eSSascha Wildner 
10505db2f26eSSascha Wildner 	/* Only memory and IO resources are valid here. */
10515db2f26eSSascha Wildner 	switch (rle->type) {
10525db2f26eSSascha Wildner 	case SYS_RES_IOPORT:
10535db2f26eSSascha Wildner 	    rm = &acpi_rman_io;
10545db2f26eSSascha Wildner 	    break;
10555db2f26eSSascha Wildner 	case SYS_RES_MEMORY:
10565db2f26eSSascha Wildner 	    rm = &acpi_rman_mem;
10575db2f26eSSascha Wildner 	    break;
10585db2f26eSSascha Wildner 	default:
10595db2f26eSSascha Wildner 	    continue;
10605db2f26eSSascha Wildner 	}
10615db2f26eSSascha Wildner 
10625db2f26eSSascha Wildner 	/* Pre-allocate resource and add to our rman pool. */
10635db2f26eSSascha Wildner 	res = BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, rle->type,
10645db2f26eSSascha Wildner 	    &rle->rid, rle->start, rle->start + rle->count - 1, rle->count,
10655db2f26eSSascha Wildner 	    0, -1);
10665db2f26eSSascha Wildner 	if (res != NULL) {
10675db2f26eSSascha Wildner 	    rman_manage_region(rm, rman_get_start(res), rman_get_end(res));
10685db2f26eSSascha Wildner 	    rle->res = res;
10695db2f26eSSascha Wildner 	} else
10705db2f26eSSascha Wildner 	    device_printf(dev, "reservation of %lx, %lx (%d) failed\n",
10715db2f26eSSascha Wildner 		rle->start, rle->count, rle->type);
10725db2f26eSSascha Wildner     }
10735db2f26eSSascha Wildner     return (0);
10745db2f26eSSascha Wildner }
10755db2f26eSSascha Wildner 
10765db2f26eSSascha Wildner static struct resource *
acpi_alloc_resource(device_t bus,device_t child,int type,int * rid,u_long start,u_long end,u_long count,u_int flags,int cpuid)10775db2f26eSSascha Wildner acpi_alloc_resource(device_t bus, device_t child, int type, int *rid,
10785db2f26eSSascha Wildner     u_long start, u_long end, u_long count, u_int flags, int cpuid)
10795db2f26eSSascha Wildner {
10805db2f26eSSascha Wildner     ACPI_RESOURCE ares;
10815db2f26eSSascha Wildner     struct acpi_device *ad = device_get_ivars(child);
10825db2f26eSSascha Wildner     struct resource_list *rl = &ad->ad_rl;
10835db2f26eSSascha Wildner     struct resource_list_entry *rle;
10845db2f26eSSascha Wildner     struct resource *res;
10855db2f26eSSascha Wildner     struct rman *rm;
10865db2f26eSSascha Wildner 
10875db2f26eSSascha Wildner     res = NULL;
10885db2f26eSSascha Wildner 
10895db2f26eSSascha Wildner     /* We only handle memory and IO resources through rman. */
10905db2f26eSSascha Wildner     switch (type) {
10915db2f26eSSascha Wildner     case SYS_RES_IOPORT:
10925db2f26eSSascha Wildner 	rm = &acpi_rman_io;
10935db2f26eSSascha Wildner 	break;
10945db2f26eSSascha Wildner     case SYS_RES_MEMORY:
10955db2f26eSSascha Wildner 	rm = &acpi_rman_mem;
10965db2f26eSSascha Wildner 	break;
10975db2f26eSSascha Wildner     default:
10985db2f26eSSascha Wildner 	rm = NULL;
10995db2f26eSSascha Wildner     }
11005db2f26eSSascha Wildner 
11015db2f26eSSascha Wildner     ACPI_SERIAL_BEGIN(acpi);
11025db2f26eSSascha Wildner 
11035db2f26eSSascha Wildner     /*
11045db2f26eSSascha Wildner      * If this is an allocation of the "default" range for a given RID, and
11055db2f26eSSascha Wildner      * we know what the resources for this device are (i.e., they're on the
11065db2f26eSSascha Wildner      * child's resource list), use those start/end values.
11075db2f26eSSascha Wildner      */
11085db2f26eSSascha Wildner     if (bus == device_get_parent(child) && start == 0UL && end == ~0UL) {
11095db2f26eSSascha Wildner 	rle = resource_list_find(rl, type, *rid);
11105db2f26eSSascha Wildner 	if (rle == NULL)
11115db2f26eSSascha Wildner 	    goto out;
11125db2f26eSSascha Wildner 	start = rle->start;
11135db2f26eSSascha Wildner 	end = rle->end;
11145db2f26eSSascha Wildner 	count = rle->count;
11155db2f26eSSascha Wildner 	cpuid = rle->cpuid;
11165db2f26eSSascha Wildner     }
11175db2f26eSSascha Wildner 
11185db2f26eSSascha Wildner     /*
11195db2f26eSSascha Wildner      * If this is an allocation of a specific range, see if we can satisfy
11205db2f26eSSascha Wildner      * the request from our system resource regions.  If we can't, pass the
11215db2f26eSSascha Wildner      * request up to the parent.
11225db2f26eSSascha Wildner      */
11235db2f26eSSascha Wildner     if (start + count - 1 == end && rm != NULL)
11245db2f26eSSascha Wildner 	res = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
11255db2f26eSSascha Wildner 	    child);
11265db2f26eSSascha Wildner     if (res == NULL) {
11275db2f26eSSascha Wildner 	res = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type, rid,
11285db2f26eSSascha Wildner 	    start, end, count, flags, cpuid);
11295db2f26eSSascha Wildner     } else {
11305db2f26eSSascha Wildner 	rman_set_rid(res, *rid);
11315db2f26eSSascha Wildner 
11325db2f26eSSascha Wildner 	/* If requested, activate the resource using the parent's method. */
11335db2f26eSSascha Wildner 	if (flags & RF_ACTIVE)
11345db2f26eSSascha Wildner 	    if (bus_activate_resource(child, type, *rid, res) != 0) {
11355db2f26eSSascha Wildner 		rman_release_resource(res);
11365db2f26eSSascha Wildner 		res = NULL;
11375db2f26eSSascha Wildner 		goto out;
11385db2f26eSSascha Wildner 	    }
11395db2f26eSSascha Wildner     }
11405db2f26eSSascha Wildner 
11415db2f26eSSascha Wildner     if (res != NULL && device_get_parent(child) == bus)
11425db2f26eSSascha Wildner 	switch (type) {
11435db2f26eSSascha Wildner 	case SYS_RES_IRQ:
11445db2f26eSSascha Wildner 	    /*
11455db2f26eSSascha Wildner 	     * Since bus_config_intr() takes immediate effect, we cannot
11465db2f26eSSascha Wildner 	     * configure the interrupt associated with a device when we
11475db2f26eSSascha Wildner 	     * parse the resources but have to defer it until a driver
11485db2f26eSSascha Wildner 	     * actually allocates the interrupt via bus_alloc_resource().
11495db2f26eSSascha Wildner 	     *
11501b726affSSepherosa Ziehau 	     * NB: Lookup failure is fine, since the device may add its
11511b726affSSepherosa Ziehau 	     * own interrupt resources, e.g. MSI or MSI-X.
11525db2f26eSSascha Wildner 	     */
11531b726affSSepherosa Ziehau 	    if (ACPI_SUCCESS(
11541b726affSSepherosa Ziehau 		    acpi_lookup_irq_resource(child, *rid, res, &ares))) {
11555db2f26eSSascha Wildner 		acpi_config_intr(child, &ares);
11561b726affSSepherosa Ziehau 	    } else {
11575db2f26eSSascha Wildner 		kprintf("irq resource not found\n");
11581b726affSSepherosa Ziehau 	    }
11595db2f26eSSascha Wildner 	    break;
11605db2f26eSSascha Wildner 	}
11615db2f26eSSascha Wildner 
11625db2f26eSSascha Wildner out:
11635db2f26eSSascha Wildner     ACPI_SERIAL_END(acpi);
11645db2f26eSSascha Wildner     return (res);
11655db2f26eSSascha Wildner }
11665db2f26eSSascha Wildner 
11675db2f26eSSascha Wildner static int
acpi_release_resource(device_t bus,device_t child,int type,int rid,struct resource * r)11685db2f26eSSascha Wildner acpi_release_resource(device_t bus, device_t child, int type, int rid,
11695db2f26eSSascha Wildner     struct resource *r)
11705db2f26eSSascha Wildner {
11715db2f26eSSascha Wildner     struct rman *rm;
11725db2f26eSSascha Wildner     int ret;
11735db2f26eSSascha Wildner 
11745db2f26eSSascha Wildner     /* We only handle memory and IO resources through rman. */
11755db2f26eSSascha Wildner     switch (type) {
11765db2f26eSSascha Wildner     case SYS_RES_IOPORT:
11775db2f26eSSascha Wildner 	rm = &acpi_rman_io;
11785db2f26eSSascha Wildner 	break;
11795db2f26eSSascha Wildner     case SYS_RES_MEMORY:
11805db2f26eSSascha Wildner 	rm = &acpi_rman_mem;
11815db2f26eSSascha Wildner 	break;
11825db2f26eSSascha Wildner     default:
11835db2f26eSSascha Wildner 	rm = NULL;
11845db2f26eSSascha Wildner     }
11855db2f26eSSascha Wildner 
11865db2f26eSSascha Wildner     ACPI_SERIAL_BEGIN(acpi);
11875db2f26eSSascha Wildner 
11885db2f26eSSascha Wildner     /*
11895db2f26eSSascha Wildner      * If this resource belongs to one of our internal managers,
11905db2f26eSSascha Wildner      * deactivate it and release it to the local pool.  If it doesn't,
11915db2f26eSSascha Wildner      * pass this request up to the parent.
11925db2f26eSSascha Wildner      */
11935db2f26eSSascha Wildner     if (rm != NULL && rman_is_region_manager(r, rm)) {
11945db2f26eSSascha Wildner 	if (rman_get_flags(r) & RF_ACTIVE) {
11955db2f26eSSascha Wildner 	    ret = bus_deactivate_resource(child, type, rid, r);
11965db2f26eSSascha Wildner 	    if (ret != 0)
11975db2f26eSSascha Wildner 		goto out;
11985db2f26eSSascha Wildner 	}
11995db2f26eSSascha Wildner 	ret = rman_release_resource(r);
12005db2f26eSSascha Wildner     } else
12015db2f26eSSascha Wildner 	ret = BUS_RELEASE_RESOURCE(device_get_parent(bus), child, type, rid, r);
12025db2f26eSSascha Wildner 
12035db2f26eSSascha Wildner out:
12045db2f26eSSascha Wildner     ACPI_SERIAL_END(acpi);
12055db2f26eSSascha Wildner     return (ret);
12065db2f26eSSascha Wildner }
12075db2f26eSSascha Wildner 
12085db2f26eSSascha Wildner static void
acpi_delete_resource(device_t bus,device_t child,int type,int rid)12095db2f26eSSascha Wildner acpi_delete_resource(device_t bus, device_t child, int type, int rid)
12105db2f26eSSascha Wildner {
12115db2f26eSSascha Wildner     struct resource_list *rl;
12125db2f26eSSascha Wildner 
12135db2f26eSSascha Wildner     rl = acpi_get_rlist(bus, child);
12145db2f26eSSascha Wildner     resource_list_delete(rl, type, rid);
12155db2f26eSSascha Wildner }
12165db2f26eSSascha Wildner 
12175db2f26eSSascha Wildner /* Allocate an IO port or memory resource, given its GAS. */
12185db2f26eSSascha Wildner int
acpi_bus_alloc_gas(device_t dev,int * type,int * rid,ACPI_GENERIC_ADDRESS * gas,struct resource ** res,u_int flags)12195db2f26eSSascha Wildner acpi_bus_alloc_gas(device_t dev, int *type, int *rid, ACPI_GENERIC_ADDRESS *gas,
12205db2f26eSSascha Wildner     struct resource **res, u_int flags)
12215db2f26eSSascha Wildner {
12225db2f26eSSascha Wildner     int error, res_type;
12235db2f26eSSascha Wildner 
12245db2f26eSSascha Wildner     error = ENOMEM;
12255db2f26eSSascha Wildner     if (type == NULL || rid == NULL || gas == NULL || res == NULL)
12265db2f26eSSascha Wildner 	return (EINVAL);
12275db2f26eSSascha Wildner 
12285db2f26eSSascha Wildner     /* We only support memory and IO spaces. */
12295db2f26eSSascha Wildner     switch (gas->SpaceId) {
12305db2f26eSSascha Wildner     case ACPI_ADR_SPACE_SYSTEM_MEMORY:
12315db2f26eSSascha Wildner 	res_type = SYS_RES_MEMORY;
12325db2f26eSSascha Wildner 	break;
12335db2f26eSSascha Wildner     case ACPI_ADR_SPACE_SYSTEM_IO:
12345db2f26eSSascha Wildner 	res_type = SYS_RES_IOPORT;
12355db2f26eSSascha Wildner 	break;
12365db2f26eSSascha Wildner     default:
12375db2f26eSSascha Wildner 	return (EOPNOTSUPP);
12385db2f26eSSascha Wildner     }
12395db2f26eSSascha Wildner 
12405db2f26eSSascha Wildner     /*
12415db2f26eSSascha Wildner      * If the register width is less than 8, assume the BIOS author means
12425db2f26eSSascha Wildner      * it is a bit field and just allocate a byte.
12435db2f26eSSascha Wildner      */
12445db2f26eSSascha Wildner     if (gas->BitWidth && gas->BitWidth < 8)
12455db2f26eSSascha Wildner 	gas->BitWidth = 8;
12465db2f26eSSascha Wildner 
12475db2f26eSSascha Wildner     /* Validate the address after we're sure we support the space. */
12485db2f26eSSascha Wildner     if (gas->Address == 0 || gas->BitWidth == 0)
12495db2f26eSSascha Wildner 	return (EINVAL);
12505db2f26eSSascha Wildner 
12515db2f26eSSascha Wildner     bus_set_resource(dev, res_type, *rid, gas->Address,
12525db2f26eSSascha Wildner 	gas->BitWidth / 8, -1);
12535db2f26eSSascha Wildner     *res = bus_alloc_resource_any(dev, res_type, rid, RF_ACTIVE | flags);
12545db2f26eSSascha Wildner     if (*res != NULL) {
12555db2f26eSSascha Wildner 	*type = res_type;
12565db2f26eSSascha Wildner 	error = 0;
12575db2f26eSSascha Wildner     } else
12585db2f26eSSascha Wildner 	bus_delete_resource(dev, res_type, *rid);
12595db2f26eSSascha Wildner 
12605db2f26eSSascha Wildner     return (error);
12615db2f26eSSascha Wildner }
12625db2f26eSSascha Wildner 
12635ca62c87SSascha Wildner ACPI_STATUS
acpi_eval_osc(device_t dev,ACPI_HANDLE handle,const char * uuidstr,int revision,uint32_t * buf,int count)12645ca62c87SSascha Wildner acpi_eval_osc(device_t dev, ACPI_HANDLE handle, const char *uuidstr,
12655ca62c87SSascha Wildner     int revision, uint32_t *buf, int count)
12665ca62c87SSascha Wildner {
12675ca62c87SSascha Wildner     ACPI_BUFFER		retbuf = { ACPI_ALLOCATE_BUFFER, NULL };
12685ca62c87SSascha Wildner     ACPI_OBJECT_LIST	arglist;
12695ca62c87SSascha Wildner     ACPI_OBJECT		arg[4];
12705ca62c87SSascha Wildner     ACPI_OBJECT		*retobj;
12715ca62c87SSascha Wildner     ACPI_STATUS		status;
12725ca62c87SSascha Wildner     struct uuid		uuid;
12735ca62c87SSascha Wildner     uint32_t		error;
127437b3e8f5SSascha Wildner     uint8_t		oscuuid[ACPI_UUID_LENGTH];
12755ca62c87SSascha Wildner     int			i;
12765ca62c87SSascha Wildner 
12775ca62c87SSascha Wildner     if (parse_uuid(uuidstr, &uuid) != 0)
12785ca62c87SSascha Wildner 	    return (AE_ERROR);
12795ca62c87SSascha Wildner     le_uuid_enc(oscuuid, &uuid);
12805ca62c87SSascha Wildner 
12815ca62c87SSascha Wildner     arglist.Pointer = arg;
12825ca62c87SSascha Wildner     arglist.Count = 4;
12835ca62c87SSascha Wildner     arg[0].Type = ACPI_TYPE_BUFFER;
1284a4cbd220SSascha Wildner     arg[0].Buffer.Length = ACPI_UUID_LENGTH;
12855ca62c87SSascha Wildner     arg[0].Buffer.Pointer = oscuuid;		/* UUID */
12865ca62c87SSascha Wildner     arg[1].Type = ACPI_TYPE_INTEGER;
12875ca62c87SSascha Wildner     arg[1].Integer.Value = revision;		/* revision */
12885ca62c87SSascha Wildner     arg[2].Type = ACPI_TYPE_INTEGER;
12895ca62c87SSascha Wildner     arg[2].Integer.Value = count;		/* # of cap integers */
12905ca62c87SSascha Wildner     arg[3].Type = ACPI_TYPE_BUFFER;
12915ca62c87SSascha Wildner     arg[3].Buffer.Length = count * sizeof(uint32_t); /* capabilities buffer */
12925ca62c87SSascha Wildner     arg[3].Buffer.Pointer = (uint8_t *)buf;
12935ca62c87SSascha Wildner 
12945ca62c87SSascha Wildner     status = AcpiEvaluateObject(handle, "_OSC", &arglist, &retbuf);
1295a528f598SSascha Wildner     if (ACPI_FAILURE(status))
12965ca62c87SSascha Wildner 	goto done;
1297a528f598SSascha Wildner     retobj = retbuf.Pointer;
1298f48d5ffcSSascha Wildner     error = ((uint32_t *)retobj->Buffer.Pointer)[0] & ACPI_OSC_ERRMASK;
1299a528f598SSascha Wildner     if (error == 0)
1300a528f598SSascha Wildner 	goto done;
1301a528f598SSascha Wildner     status = AE_ERROR;
1302f48d5ffcSSascha Wildner     if (error & ACPI_OSCERR_FAILURE)
1303a528f598SSascha Wildner 	device_printf(dev, "_OSC unable to process request\n");
1304f48d5ffcSSascha Wildner     if (error & ACPI_OSCERR_BADUUID)
1305a528f598SSascha Wildner 	device_printf(dev, "_OSC unrecognized UUID (%s)\n", uuidstr);
1306f48d5ffcSSascha Wildner     if (error & ACPI_OSCERR_BADREV)
1307a528f598SSascha Wildner 	device_printf(dev, "_OSC unrecognized revision ID (%d)\n", revision);
1308a528f598SSascha Wildner     if (error & ACPI_OSCERR_CAPSMASKED) {
1309a528f598SSascha Wildner 	if ((buf[0] & ACPI_OSC_QUERY_SUPPORT) == 0) {
1310a0d6d263SSascha Wildner 	    for (i = 1; i < count; i++) {
13115ca62c87SSascha Wildner 		device_printf(dev,
13125ca62c87SSascha Wildner 		    "_OSC capabilities have been masked: buf[%d]:%#x\n",
13135ca62c87SSascha Wildner 		    i, buf[i] & ~((uint32_t *)retobj->Buffer.Pointer)[i]);
13145ca62c87SSascha Wildner 	    }
13155ca62c87SSascha Wildner 	    status = AE_SUPPORT;
1316a528f598SSascha Wildner 	} else {
1317a528f598SSascha Wildner 	    status = AE_OK;
13185ca62c87SSascha Wildner 	}
13195ca62c87SSascha Wildner     }
1320f48d5ffcSSascha Wildner     if (buf[0] & ACPI_OSC_QUERY_SUPPORT) {
1321f48d5ffcSSascha Wildner 	for (i = 0; i < count; i++)
1322f48d5ffcSSascha Wildner 	    buf[i] = ((uint32_t *)retobj->Buffer.Pointer)[i];
1323f48d5ffcSSascha Wildner     }
13245ca62c87SSascha Wildner 
13255ca62c87SSascha Wildner done:
1326a528f598SSascha Wildner     if (retbuf.Pointer != NULL)
13275ca62c87SSascha Wildner 	AcpiOsFree(retbuf.Pointer);
13285ca62c87SSascha Wildner     return (status);
13295ca62c87SSascha Wildner }
13305ca62c87SSascha Wildner 
13315db2f26eSSascha Wildner /* Probe _HID and _CID for compatible ISA PNP ids. */
13325db2f26eSSascha Wildner static uint32_t
acpi_isa_get_logicalid(device_t dev)13335db2f26eSSascha Wildner acpi_isa_get_logicalid(device_t dev)
13345db2f26eSSascha Wildner {
13355db2f26eSSascha Wildner     ACPI_DEVICE_INFO	*devinfo;
13365db2f26eSSascha Wildner     ACPI_HANDLE		h;
13373905511eSSascha Wildner     uint32_t		pnpid;
13385db2f26eSSascha Wildner 
13395db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
13405db2f26eSSascha Wildner 
13415db2f26eSSascha Wildner     devinfo = NULL;
13425db2f26eSSascha Wildner     pnpid = 0;
13435db2f26eSSascha Wildner 
13445db2f26eSSascha Wildner     /* Fetch and validate the HID. */
13456de2a7e6SSascha Wildner     if ((h = acpi_get_handle(dev)) == NULL ||
13466de2a7e6SSascha Wildner 	ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo)))
13475db2f26eSSascha Wildner 	goto out;
13485db2f26eSSascha Wildner 
13495db2f26eSSascha Wildner     if ((devinfo->Valid & ACPI_VALID_HID) != 0)
13505db2f26eSSascha Wildner 	pnpid = PNP_EISAID(devinfo->HardwareId.String);
13515db2f26eSSascha Wildner 
13525db2f26eSSascha Wildner out:
13535db2f26eSSascha Wildner     if (devinfo)
13545db2f26eSSascha Wildner 	AcpiOsFree(devinfo);
13555db2f26eSSascha Wildner     return_VALUE (pnpid);
13565db2f26eSSascha Wildner }
13575db2f26eSSascha Wildner 
13585db2f26eSSascha Wildner static int
acpi_isa_get_compatid(device_t dev,uint32_t * cids,int count)13595db2f26eSSascha Wildner acpi_isa_get_compatid(device_t dev, uint32_t *cids, int count)
13605db2f26eSSascha Wildner {
13615db2f26eSSascha Wildner     ACPI_DEVICE_INFO	*devinfo;
13625db2f26eSSascha Wildner     ACPI_HANDLE		h;
13635db2f26eSSascha Wildner     uint32_t		*pnpid;
13645db2f26eSSascha Wildner     int			valid, i;
13655db2f26eSSascha Wildner 
13665db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
13675db2f26eSSascha Wildner 
13685db2f26eSSascha Wildner     devinfo = NULL;
13695db2f26eSSascha Wildner     pnpid = cids;
13705db2f26eSSascha Wildner     valid = 0;
13715db2f26eSSascha Wildner 
13725db2f26eSSascha Wildner     /* Fetch and validate the CID */
13736de2a7e6SSascha Wildner     if ((h = acpi_get_handle(dev)) == NULL ||
13746de2a7e6SSascha Wildner 	ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo)) ||
13756de2a7e6SSascha Wildner 	(devinfo->Valid & ACPI_VALID_CID) == 0)
13765db2f26eSSascha Wildner 	goto out;
13775db2f26eSSascha Wildner 
13785db2f26eSSascha Wildner     if (devinfo->CompatibleIdList.Count < count)
13795db2f26eSSascha Wildner 	count = devinfo->CompatibleIdList.Count;
13805db2f26eSSascha Wildner     for (i = 0; i < count; i++) {
13815db2f26eSSascha Wildner 	if (strncmp(devinfo->CompatibleIdList.Ids[i].String, "PNP", 3) != 0)
13825db2f26eSSascha Wildner 	    continue;
13835db2f26eSSascha Wildner 	*pnpid++ = PNP_EISAID(devinfo->CompatibleIdList.Ids[i].String);
13845db2f26eSSascha Wildner 	valid++;
13855db2f26eSSascha Wildner     }
13865db2f26eSSascha Wildner 
13875db2f26eSSascha Wildner out:
13885db2f26eSSascha Wildner     if (devinfo)
13895db2f26eSSascha Wildner 	AcpiOsFree(devinfo);
13905db2f26eSSascha Wildner     return_VALUE (valid);
13915db2f26eSSascha Wildner }
13925db2f26eSSascha Wildner 
13935db2f26eSSascha Wildner static char *
acpi_device_id_probe(device_t bus,device_t dev,char ** ids)13945db2f26eSSascha Wildner acpi_device_id_probe(device_t bus, device_t dev, char **ids)
13955db2f26eSSascha Wildner {
13965db2f26eSSascha Wildner     ACPI_HANDLE h;
13975db2f26eSSascha Wildner     int i;
13985db2f26eSSascha Wildner 
13995db2f26eSSascha Wildner     h = acpi_get_handle(dev);
14005db2f26eSSascha Wildner     if (ids == NULL || h == NULL || acpi_get_type(dev) != ACPI_TYPE_DEVICE)
14015db2f26eSSascha Wildner 	return (NULL);
14025db2f26eSSascha Wildner 
14035db2f26eSSascha Wildner     /* Try to match one of the array of IDs with a HID or CID. */
14045db2f26eSSascha Wildner     for (i = 0; ids[i] != NULL; i++) {
14055db2f26eSSascha Wildner 	if (acpi_MatchHid(h, ids[i]))
14065db2f26eSSascha Wildner 	    return (ids[i]);
14075db2f26eSSascha Wildner     }
14085db2f26eSSascha Wildner     return (NULL);
14095db2f26eSSascha Wildner }
14105db2f26eSSascha Wildner 
14115db2f26eSSascha Wildner static ACPI_STATUS
acpi_device_eval_obj(device_t bus,device_t dev,ACPI_STRING pathname,ACPI_OBJECT_LIST * parameters,ACPI_BUFFER * ret)14125db2f26eSSascha Wildner acpi_device_eval_obj(device_t bus, device_t dev, ACPI_STRING pathname,
14135db2f26eSSascha Wildner     ACPI_OBJECT_LIST *parameters, ACPI_BUFFER *ret)
14145db2f26eSSascha Wildner {
14155db2f26eSSascha Wildner     ACPI_HANDLE h;
14165db2f26eSSascha Wildner 
14175db2f26eSSascha Wildner     if (dev == NULL)
14185db2f26eSSascha Wildner 	h = ACPI_ROOT_OBJECT;
14195db2f26eSSascha Wildner     else if ((h = acpi_get_handle(dev)) == NULL)
14205db2f26eSSascha Wildner 	return (AE_BAD_PARAMETER);
14215db2f26eSSascha Wildner     return (AcpiEvaluateObject(h, pathname, parameters, ret));
14225db2f26eSSascha Wildner }
14235db2f26eSSascha Wildner 
14245db2f26eSSascha Wildner static int
acpi_device_pwr_for_sleep(device_t bus,device_t dev,int * dstate)14255db2f26eSSascha Wildner acpi_device_pwr_for_sleep(device_t bus, device_t dev, int *dstate)
14265db2f26eSSascha Wildner {
14275db2f26eSSascha Wildner     struct acpi_softc *sc;
14285db2f26eSSascha Wildner     ACPI_HANDLE handle;
14295db2f26eSSascha Wildner     ACPI_STATUS status;
14305db2f26eSSascha Wildner     char sxd[8];
14315db2f26eSSascha Wildner     int error;
14325db2f26eSSascha Wildner 
14335db2f26eSSascha Wildner     sc = device_get_softc(bus);
14345db2f26eSSascha Wildner     handle = acpi_get_handle(dev);
14355db2f26eSSascha Wildner 
14365db2f26eSSascha Wildner     /*
14375db2f26eSSascha Wildner      * XXX If we find these devices, don't try to power them down.
14385db2f26eSSascha Wildner      * The serial and IRDA ports on my T23 hang the system when
14395db2f26eSSascha Wildner      * set to D3 and it appears that such legacy devices may
14405db2f26eSSascha Wildner      * need special handling in their drivers.
14415db2f26eSSascha Wildner      */
14425db2f26eSSascha Wildner     if (handle == NULL ||
14435db2f26eSSascha Wildner 	acpi_MatchHid(handle, "PNP0500") ||
14445db2f26eSSascha Wildner 	acpi_MatchHid(handle, "PNP0501") ||
14455db2f26eSSascha Wildner 	acpi_MatchHid(handle, "PNP0502") ||
14465db2f26eSSascha Wildner 	acpi_MatchHid(handle, "PNP0510") ||
14475db2f26eSSascha Wildner 	acpi_MatchHid(handle, "PNP0511"))
14485db2f26eSSascha Wildner 	return (ENXIO);
14495db2f26eSSascha Wildner 
14505db2f26eSSascha Wildner     /*
14515db2f26eSSascha Wildner      * Override next state with the value from _SxD, if present.  If no
14525db2f26eSSascha Wildner      * dstate argument was provided, don't fetch the return value.
14535db2f26eSSascha Wildner      */
14545db2f26eSSascha Wildner     ksnprintf(sxd, sizeof(sxd), "_S%dD", sc->acpi_sstate);
14555db2f26eSSascha Wildner     if (dstate)
14565db2f26eSSascha Wildner 	status = acpi_GetInteger(handle, sxd, dstate);
14575db2f26eSSascha Wildner     else
14585db2f26eSSascha Wildner 	status = AcpiEvaluateObject(handle, sxd, NULL, NULL);
14595db2f26eSSascha Wildner 
14605db2f26eSSascha Wildner     switch (status) {
14615db2f26eSSascha Wildner     case AE_OK:
14625db2f26eSSascha Wildner 	error = 0;
14635db2f26eSSascha Wildner 	break;
14645db2f26eSSascha Wildner     case AE_NOT_FOUND:
14655db2f26eSSascha Wildner 	error = ESRCH;
14665db2f26eSSascha Wildner 	break;
14675db2f26eSSascha Wildner     default:
14685db2f26eSSascha Wildner 	error = ENXIO;
14695db2f26eSSascha Wildner 	break;
14705db2f26eSSascha Wildner     }
14715db2f26eSSascha Wildner 
14725db2f26eSSascha Wildner     return (error);
14735db2f26eSSascha Wildner }
14745db2f26eSSascha Wildner 
14755db2f26eSSascha Wildner /* Callback arg for our implementation of walking the namespace. */
14765db2f26eSSascha Wildner struct acpi_device_scan_ctx {
14775db2f26eSSascha Wildner     acpi_scan_cb_t	user_fn;
14785db2f26eSSascha Wildner     void		*arg;
14795db2f26eSSascha Wildner     ACPI_HANDLE		parent;
14805db2f26eSSascha Wildner };
14815db2f26eSSascha Wildner 
14825db2f26eSSascha Wildner static ACPI_STATUS
acpi_device_scan_cb(ACPI_HANDLE h,UINT32 level,void * arg,void ** retval)14835db2f26eSSascha Wildner acpi_device_scan_cb(ACPI_HANDLE h, UINT32 level, void *arg, void **retval)
14845db2f26eSSascha Wildner {
14855db2f26eSSascha Wildner     struct acpi_device_scan_ctx *ctx;
14865db2f26eSSascha Wildner     device_t dev, old_dev;
14875db2f26eSSascha Wildner     ACPI_STATUS status;
14885db2f26eSSascha Wildner     ACPI_OBJECT_TYPE type;
14895db2f26eSSascha Wildner 
14905db2f26eSSascha Wildner     /*
14915db2f26eSSascha Wildner      * Skip this device if we think we'll have trouble with it or it is
14925db2f26eSSascha Wildner      * the parent where the scan began.
14935db2f26eSSascha Wildner      */
14945db2f26eSSascha Wildner     ctx = (struct acpi_device_scan_ctx *)arg;
14955db2f26eSSascha Wildner     if (acpi_avoid(h) || h == ctx->parent)
14965db2f26eSSascha Wildner 	return (AE_OK);
14975db2f26eSSascha Wildner 
14985db2f26eSSascha Wildner     /* If this is not a valid device type (e.g., a method), skip it. */
14995db2f26eSSascha Wildner     if (ACPI_FAILURE(AcpiGetType(h, &type)))
15005db2f26eSSascha Wildner 	return (AE_OK);
15015db2f26eSSascha Wildner     if (type != ACPI_TYPE_DEVICE && type != ACPI_TYPE_PROCESSOR &&
15025db2f26eSSascha Wildner 	type != ACPI_TYPE_THERMAL && type != ACPI_TYPE_POWER)
15035db2f26eSSascha Wildner 	return (AE_OK);
15045db2f26eSSascha Wildner 
15055db2f26eSSascha Wildner     /*
15065db2f26eSSascha Wildner      * Call the user function with the current device.  If it is unchanged
15075db2f26eSSascha Wildner      * afterwards, return.  Otherwise, we update the handle to the new dev.
15085db2f26eSSascha Wildner      */
15095db2f26eSSascha Wildner     old_dev = acpi_get_device(h);
15105db2f26eSSascha Wildner     dev = old_dev;
15115db2f26eSSascha Wildner     status = ctx->user_fn(h, &dev, level, ctx->arg);
15125db2f26eSSascha Wildner     if (ACPI_FAILURE(status) || old_dev == dev)
15135db2f26eSSascha Wildner 	return (status);
15145db2f26eSSascha Wildner 
15155db2f26eSSascha Wildner     /* Remove the old child and its connection to the handle. */
15165db2f26eSSascha Wildner     if (old_dev != NULL) {
15175db2f26eSSascha Wildner 	device_delete_child(device_get_parent(old_dev), old_dev);
15185db2f26eSSascha Wildner 	AcpiDetachData(h, acpi_fake_objhandler);
15195db2f26eSSascha Wildner     }
15205db2f26eSSascha Wildner 
15215db2f26eSSascha Wildner     /* Recreate the handle association if the user created a device. */
15225db2f26eSSascha Wildner     if (dev != NULL)
15235db2f26eSSascha Wildner 	AcpiAttachData(h, acpi_fake_objhandler, dev);
15245db2f26eSSascha Wildner 
15255db2f26eSSascha Wildner     return (AE_OK);
15265db2f26eSSascha Wildner }
15275db2f26eSSascha Wildner 
15285db2f26eSSascha Wildner static ACPI_STATUS
acpi_device_scan_children(device_t bus,device_t dev,int max_depth,acpi_scan_cb_t user_fn,void * arg)15295db2f26eSSascha Wildner acpi_device_scan_children(device_t bus, device_t dev, int max_depth,
15305db2f26eSSascha Wildner     acpi_scan_cb_t user_fn, void *arg)
15315db2f26eSSascha Wildner {
15325db2f26eSSascha Wildner     ACPI_HANDLE h;
15335db2f26eSSascha Wildner     struct acpi_device_scan_ctx ctx;
15345db2f26eSSascha Wildner 
15355db2f26eSSascha Wildner     if (acpi_disabled("children"))
15365db2f26eSSascha Wildner 	return (AE_OK);
15375db2f26eSSascha Wildner 
15385db2f26eSSascha Wildner     if (dev == NULL)
15395db2f26eSSascha Wildner 	h = ACPI_ROOT_OBJECT;
15405db2f26eSSascha Wildner     else if ((h = acpi_get_handle(dev)) == NULL)
15415db2f26eSSascha Wildner 	return (AE_BAD_PARAMETER);
15425db2f26eSSascha Wildner     ctx.user_fn = user_fn;
15435db2f26eSSascha Wildner     ctx.arg = arg;
15445db2f26eSSascha Wildner     ctx.parent = h;
15455db2f26eSSascha Wildner     return (AcpiWalkNamespace(ACPI_TYPE_ANY, h, max_depth,
15465db2f26eSSascha Wildner 	acpi_device_scan_cb, NULL, &ctx, NULL));
15475db2f26eSSascha Wildner }
15485db2f26eSSascha Wildner 
15495db2f26eSSascha Wildner /*
15505db2f26eSSascha Wildner  * Even though ACPI devices are not PCI, we use the PCI approach for setting
15515db2f26eSSascha Wildner  * device power states since it's close enough to ACPI.
15525db2f26eSSascha Wildner  */
15535db2f26eSSascha Wildner static int
acpi_set_powerstate_method(device_t bus,device_t child,int state)15545db2f26eSSascha Wildner acpi_set_powerstate_method(device_t bus, device_t child, int state)
15555db2f26eSSascha Wildner {
15565db2f26eSSascha Wildner     ACPI_HANDLE h;
15575db2f26eSSascha Wildner     ACPI_STATUS status;
15585db2f26eSSascha Wildner     int error;
15595db2f26eSSascha Wildner 
15605db2f26eSSascha Wildner     error = 0;
15615db2f26eSSascha Wildner     h = acpi_get_handle(child);
15625db2f26eSSascha Wildner     if (state < ACPI_STATE_D0 || state > ACPI_STATE_D3)
15635db2f26eSSascha Wildner 	return (EINVAL);
15645db2f26eSSascha Wildner     if (h == NULL)
15655db2f26eSSascha Wildner 	return (0);
15665db2f26eSSascha Wildner 
15675db2f26eSSascha Wildner     /* Ignore errors if the power methods aren't present. */
15685db2f26eSSascha Wildner     status = acpi_pwr_switch_consumer(h, state);
15695db2f26eSSascha Wildner     if (ACPI_FAILURE(status) && status != AE_NOT_FOUND
15705db2f26eSSascha Wildner 	&& status != AE_BAD_PARAMETER)
15715db2f26eSSascha Wildner 	device_printf(bus, "failed to set ACPI power state D%d on %s: %s\n",
15725db2f26eSSascha Wildner 	    state, acpi_name(h), AcpiFormatException(status));
15735db2f26eSSascha Wildner 
15745db2f26eSSascha Wildner     return (error);
15755db2f26eSSascha Wildner }
15765db2f26eSSascha Wildner 
15775db2f26eSSascha Wildner static int
acpi_isa_pnp_probe(device_t bus,device_t child,struct isa_pnp_id * ids)15785db2f26eSSascha Wildner acpi_isa_pnp_probe(device_t bus, device_t child, struct isa_pnp_id *ids)
15795db2f26eSSascha Wildner {
15805db2f26eSSascha Wildner     int			result, cid_count, i;
15815db2f26eSSascha Wildner     uint32_t		lid, cids[8];
15825db2f26eSSascha Wildner 
15835db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
15845db2f26eSSascha Wildner 
15855db2f26eSSascha Wildner     /*
15865db2f26eSSascha Wildner      * ISA-style drivers attached to ACPI may persist and
15875db2f26eSSascha Wildner      * probe manually if we return ENOENT.  We never want
15885db2f26eSSascha Wildner      * that to happen, so don't ever return it.
15895db2f26eSSascha Wildner      */
15905db2f26eSSascha Wildner     result = ENXIO;
15915db2f26eSSascha Wildner 
15925db2f26eSSascha Wildner     /* Scan the supplied IDs for a match */
15935db2f26eSSascha Wildner     lid = acpi_isa_get_logicalid(child);
15945db2f26eSSascha Wildner     cid_count = acpi_isa_get_compatid(child, cids, 8);
15955db2f26eSSascha Wildner     while (ids && ids->ip_id) {
15965db2f26eSSascha Wildner 	if (lid == ids->ip_id) {
15975db2f26eSSascha Wildner 	    result = 0;
15985db2f26eSSascha Wildner 	    goto out;
15995db2f26eSSascha Wildner 	}
16005db2f26eSSascha Wildner 	for (i = 0; i < cid_count; i++) {
16015db2f26eSSascha Wildner 	    if (cids[i] == ids->ip_id) {
16025db2f26eSSascha Wildner 		result = 0;
16035db2f26eSSascha Wildner 		goto out;
16045db2f26eSSascha Wildner 	    }
16055db2f26eSSascha Wildner 	}
16065db2f26eSSascha Wildner 	ids++;
16075db2f26eSSascha Wildner     }
16085db2f26eSSascha Wildner 
16095db2f26eSSascha Wildner  out:
16105db2f26eSSascha Wildner     if (result == 0 && ids->ip_desc)
16115db2f26eSSascha Wildner 	device_set_desc(child, ids->ip_desc);
16125db2f26eSSascha Wildner 
16135db2f26eSSascha Wildner     return_VALUE (result);
16145db2f26eSSascha Wildner }
16155db2f26eSSascha Wildner 
16165db2f26eSSascha Wildner /*
16175db2f26eSSascha Wildner  * Look for a MCFG table.  If it is present, use the settings for
16185db2f26eSSascha Wildner  * domain (segment) 0 to setup PCI config space access via the memory
16195db2f26eSSascha Wildner  * map.
16205db2f26eSSascha Wildner  */
16215db2f26eSSascha Wildner static void
acpi_enable_pcie(void)16225db2f26eSSascha Wildner acpi_enable_pcie(void)
16235db2f26eSSascha Wildner {
16245db2f26eSSascha Wildner 	ACPI_TABLE_HEADER *hdr;
16255db2f26eSSascha Wildner 	ACPI_MCFG_ALLOCATION *alloc, *end;
16265db2f26eSSascha Wildner 	ACPI_STATUS status;
16275db2f26eSSascha Wildner 
16285db2f26eSSascha Wildner 	status = AcpiGetTable(ACPI_SIG_MCFG, 1, &hdr);
16295db2f26eSSascha Wildner 	if (ACPI_FAILURE(status))
16305db2f26eSSascha Wildner 		return;
16315db2f26eSSascha Wildner 
16325db2f26eSSascha Wildner 	end = (ACPI_MCFG_ALLOCATION *)((char *)hdr + hdr->Length);
16335db2f26eSSascha Wildner 	alloc = (ACPI_MCFG_ALLOCATION *)((ACPI_TABLE_MCFG *)hdr + 1);
16345db2f26eSSascha Wildner 	while (alloc < end) {
16355db2f26eSSascha Wildner 		if (alloc->PciSegment == 0) {
16365db2f26eSSascha Wildner 			pcie_cfgregopen(alloc->Address, alloc->StartBusNumber,
16375db2f26eSSascha Wildner 			    alloc->EndBusNumber);
16385db2f26eSSascha Wildner 			return;
16395db2f26eSSascha Wildner 		}
16405db2f26eSSascha Wildner 		alloc++;
16415db2f26eSSascha Wildner 	}
16425db2f26eSSascha Wildner }
16435db2f26eSSascha Wildner 
16445db2f26eSSascha Wildner /*
16455db2f26eSSascha Wildner  * Scan all of the ACPI namespace and attach child devices.
16465db2f26eSSascha Wildner  *
16475db2f26eSSascha Wildner  * We should only expect to find devices in the \_PR, \_TZ, \_SI, and
16485db2f26eSSascha Wildner  * \_SB scopes, and \_PR and \_TZ became obsolete in the ACPI 2.0 spec.
16495db2f26eSSascha Wildner  * However, in violation of the spec, some systems place their PCI link
16505db2f26eSSascha Wildner  * devices in \, so we have to walk the whole namespace.  We check the
16515db2f26eSSascha Wildner  * type of namespace nodes, so this should be ok.
16525db2f26eSSascha Wildner  */
16535db2f26eSSascha Wildner static void
acpi_probe_children(device_t bus)16545db2f26eSSascha Wildner acpi_probe_children(device_t bus)
16555db2f26eSSascha Wildner {
1656ebb7869eSImre Vadász     device_t *children;
1657ebb7869eSImre Vadász     int cnt;
16585db2f26eSSascha Wildner 
16595db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
16605db2f26eSSascha Wildner 
16615db2f26eSSascha Wildner     /*
16625db2f26eSSascha Wildner      * Scan the namespace and insert placeholders for all the devices that
16635db2f26eSSascha Wildner      * we find.  We also probe/attach any early devices.
16645db2f26eSSascha Wildner      *
16655db2f26eSSascha Wildner      * Note that we use AcpiWalkNamespace rather than AcpiGetDevices because
16665db2f26eSSascha Wildner      * we want to create nodes for all devices, not just those that are
16675db2f26eSSascha Wildner      * currently present. (This assumes that we don't want to create/remove
16685db2f26eSSascha Wildner      * devices as they appear, which might be smarter.)
16695db2f26eSSascha Wildner      */
16705db2f26eSSascha Wildner     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "namespace scan\n"));
16715db2f26eSSascha Wildner     AcpiWalkNamespace(ACPI_TYPE_ANY, ACPI_ROOT_OBJECT, 100,
16725db2f26eSSascha Wildner 	acpi_probe_child, NULL, bus, NULL);
1673ebb7869eSImre Vadász     /* This gets us all the children that we added from the ACPI namespace. */
1674ebb7869eSImre Vadász     device_get_children(bus, &children, &cnt);
16755db2f26eSSascha Wildner 
16765db2f26eSSascha Wildner     /* Pre-allocate resources for our rman from any sysresource devices. */
16775db2f26eSSascha Wildner     acpi_sysres_alloc(bus);
16785db2f26eSSascha Wildner     /* Create any static children by calling device identify methods. */
16795db2f26eSSascha Wildner     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "device identify routines\n"));
16805db2f26eSSascha Wildner     bus_generic_probe(bus);
16815db2f26eSSascha Wildner 
16825db2f26eSSascha Wildner     /* Probe/attach all children, created staticly and from the namespace. */
16835db2f26eSSascha Wildner     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "first bus_generic_attach\n"));
1684df21e16dSImre Vadász     bus_generic_attach_gpri(bus, KOBJ_GPRI_ACPI+2);
16855025fc65SMatthew Dillon     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "second bus_generic_attach\n"));
1686df21e16dSImre Vadász     bus_generic_attach_gpri(bus, KOBJ_GPRI_ACPI+1);
1687ebb7869eSImre Vadász     /* Re-check device presence for previously disabled devices. */
1688ebb7869eSImre Vadász     acpi_reprobe_children(bus, children, cnt);
1689ebb7869eSImre Vadász     kfree(children, M_TEMP);
1690df21e16dSImre Vadász     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "third bus_generic_attach\n"));
1691df21e16dSImre Vadász     bus_generic_attach_gpri(bus, KOBJ_GPRI_ACPI);
1692df21e16dSImre Vadász     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "fourth bus_generic_attach\n"));
16935025fc65SMatthew Dillon     bus_generic_attach_gpri(bus, KOBJ_GPRI_ACPI);
16945db2f26eSSascha Wildner 
16955db2f26eSSascha Wildner     /*
16965db2f26eSSascha Wildner      * Some of these children may have attached others as part of their attach
16975db2f26eSSascha Wildner      * process (eg. the root PCI bus driver), so rescan.
16985db2f26eSSascha Wildner      */
1699df21e16dSImre Vadász     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "fifth bus_generic_attach\n"));
17005025fc65SMatthew Dillon     bus_generic_attach(bus);
17015025fc65SMatthew Dillon 
1702df21e16dSImre Vadász     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "sixth bus_generic_attach\n"));
17035db2f26eSSascha Wildner     bus_generic_attach(bus);
17045db2f26eSSascha Wildner 
17055db2f26eSSascha Wildner     /* Attach wake sysctls. */
17065db2f26eSSascha Wildner     acpi_wake_sysctl_walk(bus);
17075db2f26eSSascha Wildner 
17085db2f26eSSascha Wildner     ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "done attaching children\n"));
17095db2f26eSSascha Wildner     return_VOID;
17105db2f26eSSascha Wildner }
17115db2f26eSSascha Wildner 
17125db2f26eSSascha Wildner /*
17135db2f26eSSascha Wildner  * Determine the probe order for a given device.
17145db2f26eSSascha Wildner  */
17155db2f26eSSascha Wildner static void
acpi_probe_order(ACPI_HANDLE handle,int * order)17165db2f26eSSascha Wildner acpi_probe_order(ACPI_HANDLE handle, int *order)
17175db2f26eSSascha Wildner {
17185db2f26eSSascha Wildner     ACPI_OBJECT_TYPE type;
17195db2f26eSSascha Wildner 
17205db2f26eSSascha Wildner     /*
17215db2f26eSSascha Wildner      * 1. I/O port and memory system resource holders
17225db2f26eSSascha Wildner      * 2. Embedded controllers (to handle early accesses)
17235db2f26eSSascha Wildner      * 3. PCI Link Devices
17245db2f26eSSascha Wildner      * 100000. CPUs
17255db2f26eSSascha Wildner      */
17265db2f26eSSascha Wildner     AcpiGetType(handle, &type);
17275db2f26eSSascha Wildner     if (acpi_MatchHid(handle, "PNP0C01") || acpi_MatchHid(handle, "PNP0C02"))
17285db2f26eSSascha Wildner 	*order = 1;
17295db2f26eSSascha Wildner     else if (acpi_MatchHid(handle, "PNP0C09"))
17305db2f26eSSascha Wildner 	*order = 2;
17315db2f26eSSascha Wildner     else if (acpi_MatchHid(handle, "PNP0C0F"))
17325db2f26eSSascha Wildner 	*order = 3;
17335db2f26eSSascha Wildner     else if (type == ACPI_TYPE_PROCESSOR)
17345db2f26eSSascha Wildner 	*order = 100000;
17355db2f26eSSascha Wildner }
17365db2f26eSSascha Wildner 
17375db2f26eSSascha Wildner /*
1738ebb7869eSImre Vadász  * Flag a device as disabled, because it isn't present according to the
1739ebb7869eSImre Vadász  * _STA method. We set the recheck instance-variable, to make sure that we
1740ebb7869eSImre Vadász  * recheck the device presence at a later point.
1741ebb7869eSImre Vadász  */
1742ebb7869eSImre Vadász static void
acpi_disable_not_present(device_t child)1743ebb7869eSImre Vadász acpi_disable_not_present(device_t child)
1744ebb7869eSImre Vadász {
1745ebb7869eSImre Vadász 	device_disable(child);
1746ebb7869eSImre Vadász 	acpi_set_recheck(child, 1);
1747ebb7869eSImre Vadász }
1748ebb7869eSImre Vadász 
1749ebb7869eSImre Vadász /*
1750ebb7869eSImre Vadász  * This rechecks the device presence for all the devices which were disabled
1751ebb7869eSImre Vadász  * using acpi_disable_not_present().
1752ebb7869eSImre Vadász  */
1753ebb7869eSImre Vadász static void
acpi_reprobe_children(device_t bus,device_t * children,int cnt)1754ebb7869eSImre Vadász acpi_reprobe_children(device_t bus, device_t *children, int cnt)
1755ebb7869eSImre Vadász {
1756ebb7869eSImre Vadász 	int i;
1757ebb7869eSImre Vadász 
1758ebb7869eSImre Vadász 	for (i = 0; i < cnt; i++) {
1759ebb7869eSImre Vadász 		device_t dev = children[i];
1760ebb7869eSImre Vadász 
1761ebb7869eSImre Vadász 		if (device_is_enabled(dev))
1762ebb7869eSImre Vadász 			continue;
1763ebb7869eSImre Vadász 
1764ebb7869eSImre Vadász 		if (acpi_get_recheck(dev)) {
1765ebb7869eSImre Vadász 			if (acpi_DeviceIsPresent(dev)) {
1766ebb7869eSImre Vadász 				acpi_set_recheck(dev, 0);
1767ebb7869eSImre Vadász 				device_enable(dev);
1768ebb7869eSImre Vadász 				/*
1769ebb7869eSImre Vadász 				 * Currently we parse the resources for every
1770ebb7869eSImre Vadász 				 * device at the first time, when we see
1771ebb7869eSImre Vadász 				 * that it is present.
1772ebb7869eSImre Vadász 				 */
1773ebb7869eSImre Vadász 				acpi_parse_resources(dev, acpi_get_handle(dev),
1774ebb7869eSImre Vadász 				    &acpi_res_parse_set, NULL);
1775ebb7869eSImre Vadász 			}
1776ebb7869eSImre Vadász 		}
1777ebb7869eSImre Vadász 	}
1778ebb7869eSImre Vadász }
1779ebb7869eSImre Vadász 
1780ebb7869eSImre Vadász /*
17815db2f26eSSascha Wildner  * Evaluate a child device and determine whether we might attach a device to
17825db2f26eSSascha Wildner  * it.
17835db2f26eSSascha Wildner  */
17845db2f26eSSascha Wildner static ACPI_STATUS
acpi_probe_child(ACPI_HANDLE handle,UINT32 level,void * context,void ** status)17855db2f26eSSascha Wildner acpi_probe_child(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
17865db2f26eSSascha Wildner {
17875db2f26eSSascha Wildner     struct acpi_prw_data prw;
17885db2f26eSSascha Wildner     ACPI_OBJECT_TYPE type;
17895db2f26eSSascha Wildner     ACPI_HANDLE h;
17905db2f26eSSascha Wildner     device_t bus, child;
17915db2f26eSSascha Wildner     int order;
17925db2f26eSSascha Wildner     char *handle_str;
17935db2f26eSSascha Wildner 
17945db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
17955db2f26eSSascha Wildner 
17965db2f26eSSascha Wildner     if (acpi_disabled("children"))
17975db2f26eSSascha Wildner 	return_ACPI_STATUS (AE_OK);
17985db2f26eSSascha Wildner 
17995db2f26eSSascha Wildner     /* Skip this device if we think we'll have trouble with it. */
18005db2f26eSSascha Wildner     if (acpi_avoid(handle))
18015db2f26eSSascha Wildner 	return_ACPI_STATUS (AE_OK);
18025db2f26eSSascha Wildner 
18035db2f26eSSascha Wildner     bus = (device_t)context;
18045db2f26eSSascha Wildner     if (ACPI_SUCCESS(AcpiGetType(handle, &type))) {
18055db2f26eSSascha Wildner 	handle_str = acpi_name(handle);
18065db2f26eSSascha Wildner 	switch (type) {
18075db2f26eSSascha Wildner 	case ACPI_TYPE_DEVICE:
18085db2f26eSSascha Wildner 	    /*
18095db2f26eSSascha Wildner 	     * Since we scan from \, be sure to skip system scope objects.
18105db2f26eSSascha Wildner 	     * \_SB_ and \_TZ_ are defined in ACPICA as devices to work around
18115db2f26eSSascha Wildner 	     * BIOS bugs.  For example, \_SB_ is to allow \_SB_._INI to be run
18125db2f26eSSascha Wildner 	     * during the intialization and \_TZ_ is to support Notify() on it.
18135db2f26eSSascha Wildner 	     */
18145db2f26eSSascha Wildner 	    if (strcmp(handle_str, "\\_SB_") == 0 ||
18155db2f26eSSascha Wildner 		strcmp(handle_str, "\\_TZ_") == 0)
18165db2f26eSSascha Wildner 		break;
18175db2f26eSSascha Wildner 
18185db2f26eSSascha Wildner 	    if (acpi_parse_prw(handle, &prw) == 0)
18195db2f26eSSascha Wildner 		AcpiSetupGpeForWake(handle, prw.gpe_handle, prw.gpe_bit);
18205db2f26eSSascha Wildner 
18215db2f26eSSascha Wildner 	    /* FALLTHROUGH */
18225db2f26eSSascha Wildner 	case ACPI_TYPE_PROCESSOR:
18235db2f26eSSascha Wildner 	case ACPI_TYPE_THERMAL:
18245db2f26eSSascha Wildner 	case ACPI_TYPE_POWER:
18255db2f26eSSascha Wildner 	    /*
18265db2f26eSSascha Wildner 	     * Create a placeholder device for this node.  Sort the
18275db2f26eSSascha Wildner 	     * placeholder so that the probe/attach passes will run
18285db2f26eSSascha Wildner 	     * breadth-first.  Orders less than ACPI_DEV_BASE_ORDER
18295db2f26eSSascha Wildner 	     * are reserved for special objects (i.e., system
18305db2f26eSSascha Wildner 	     * resources).  CPU devices have a very high order to
18315db2f26eSSascha Wildner 	     * ensure they are probed after other devices.
18325db2f26eSSascha Wildner 	     */
18335db2f26eSSascha Wildner 	    ACPI_DEBUG_PRINT((ACPI_DB_OBJECTS, "scanning '%s'\n", handle_str));
18345db2f26eSSascha Wildner 	    order = level * 10 + 100;
18355db2f26eSSascha Wildner 	    acpi_probe_order(handle, &order);
18365db2f26eSSascha Wildner 	    child = BUS_ADD_CHILD(bus, bus, order, NULL, -1);
18375db2f26eSSascha Wildner 	    if (child == NULL)
18385db2f26eSSascha Wildner 		break;
18395db2f26eSSascha Wildner 
18405db2f26eSSascha Wildner 	    /* Associate the handle with the device_t and vice versa. */
18415db2f26eSSascha Wildner 	    acpi_set_handle(child, handle);
18425db2f26eSSascha Wildner 	    AcpiAttachData(handle, acpi_fake_objhandler, child);
18435db2f26eSSascha Wildner 
18445db2f26eSSascha Wildner 	    /*
18455db2f26eSSascha Wildner 	     * Check that the device is present.  If it's not present,
18465db2f26eSSascha Wildner 	     * leave it disabled (so that we have a device_t attached to
18475db2f26eSSascha Wildner 	     * the handle, but we don't probe it).
18485db2f26eSSascha Wildner 	     *
18495db2f26eSSascha Wildner 	     * XXX PCI link devices sometimes report "present" but not
18505db2f26eSSascha Wildner 	     * "functional" (i.e. if disabled).  Go ahead and probe them
18515db2f26eSSascha Wildner 	     * anyway since we may enable them later.
18525db2f26eSSascha Wildner 	     */
18535db2f26eSSascha Wildner 	    if (type == ACPI_TYPE_DEVICE && !acpi_DeviceIsPresent(child)) {
18545db2f26eSSascha Wildner 		/* Never disable PCI link devices. */
18555db2f26eSSascha Wildner 		if (acpi_MatchHid(handle, "PNP0C0F"))
18565db2f26eSSascha Wildner 		    break;
18575db2f26eSSascha Wildner 		/*
18585db2f26eSSascha Wildner 		 * Docking stations should remain enabled since the system
18595db2f26eSSascha Wildner 		 * may be undocked at boot.
18605db2f26eSSascha Wildner 		 */
18615db2f26eSSascha Wildner 		if (ACPI_SUCCESS(AcpiGetHandle(handle, "_DCK", &h)))
18625db2f26eSSascha Wildner 		    break;
18635db2f26eSSascha Wildner 
1864ebb7869eSImre Vadász 		acpi_disable_not_present(child);
18655db2f26eSSascha Wildner 		break;
18665db2f26eSSascha Wildner 	    }
18675db2f26eSSascha Wildner 
18685db2f26eSSascha Wildner 	    /*
18695db2f26eSSascha Wildner 	     * Get the device's resource settings and attach them.
18705db2f26eSSascha Wildner 	     * Note that if the device has _PRS but no _CRS, we need
18715db2f26eSSascha Wildner 	     * to decide when it's appropriate to try to configure the
18725db2f26eSSascha Wildner 	     * device.  Ignore the return value here; it's OK for the
18735db2f26eSSascha Wildner 	     * device not to have any resources.
18745db2f26eSSascha Wildner 	     */
18755db2f26eSSascha Wildner 	    acpi_parse_resources(child, handle, &acpi_res_parse_set, NULL);
18765db2f26eSSascha Wildner 	    break;
18775db2f26eSSascha Wildner 	}
18785db2f26eSSascha Wildner     }
18795db2f26eSSascha Wildner 
18805db2f26eSSascha Wildner     return_ACPI_STATUS (AE_OK);
18815db2f26eSSascha Wildner }
18825db2f26eSSascha Wildner 
18835db2f26eSSascha Wildner /*
18845db2f26eSSascha Wildner  * AcpiAttachData() requires an object handler but never uses it.  This is a
18855db2f26eSSascha Wildner  * placeholder object handler so we can store a device_t in an ACPI_HANDLE.
18865db2f26eSSascha Wildner  */
18875db2f26eSSascha Wildner void
acpi_fake_objhandler(ACPI_HANDLE h,void * data)18885db2f26eSSascha Wildner acpi_fake_objhandler(ACPI_HANDLE h, void *data)
18895db2f26eSSascha Wildner {
18905db2f26eSSascha Wildner }
18915db2f26eSSascha Wildner 
18925db2f26eSSascha Wildner static void
acpi_shutdown_final(void * arg,int howto)18935db2f26eSSascha Wildner acpi_shutdown_final(void *arg, int howto)
18945db2f26eSSascha Wildner {
18955db2f26eSSascha Wildner     struct acpi_softc *sc;
18965db2f26eSSascha Wildner     ACPI_STATUS status;
18975db2f26eSSascha Wildner 
18985db2f26eSSascha Wildner     /*
18995db2f26eSSascha Wildner      * XXX Shutdown code should only run on the BSP (cpuid 0).
19005db2f26eSSascha Wildner      * Some chipsets do not power off the system correctly if called from
19015db2f26eSSascha Wildner      * an AP.
19025db2f26eSSascha Wildner      */
19035db2f26eSSascha Wildner     sc = arg;
19045db2f26eSSascha Wildner     if ((howto & RB_POWEROFF) != 0) {
19055db2f26eSSascha Wildner 	status = AcpiEnterSleepStatePrep(ACPI_STATE_S5);
19065db2f26eSSascha Wildner 	if (ACPI_FAILURE(status)) {
1907e11869f0SSascha Wildner 	    device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n",
19085db2f26eSSascha Wildner 		   AcpiFormatException(status));
19095db2f26eSSascha Wildner 	    return;
19105db2f26eSSascha Wildner 	}
1911e11869f0SSascha Wildner 	device_printf(sc->acpi_dev, "Powering system off\n");
19125db2f26eSSascha Wildner 	ACPI_DISABLE_IRQS();
19135db2f26eSSascha Wildner 	status = AcpiEnterSleepState(ACPI_STATE_S5);
19145db2f26eSSascha Wildner 	if (ACPI_FAILURE(status)) {
1915e11869f0SSascha Wildner 	    device_printf(sc->acpi_dev, "power-off failed - %s\n",
1916e11869f0SSascha Wildner 		AcpiFormatException(status));
19175db2f26eSSascha Wildner 	} else {
19185db2f26eSSascha Wildner 	    DELAY(1000000);
1919e11869f0SSascha Wildner 	    device_printf(sc->acpi_dev, "power-off failed - timeout\n");
19205db2f26eSSascha Wildner 	}
19215db2f26eSSascha Wildner     } else if ((howto & RB_HALT) == 0 && sc->acpi_handle_reboot) {
19225db2f26eSSascha Wildner 	/* Reboot using the reset register. */
19235db2f26eSSascha Wildner 	status = AcpiReset();
19245db2f26eSSascha Wildner 	if (ACPI_FAILURE(status)) {
19255db2f26eSSascha Wildner 	    if (status != AE_NOT_EXIST)
1926e11869f0SSascha Wildner 		    device_printf(sc->acpi_dev, "reset failed - %s\n",
1927e11869f0SSascha Wildner 			AcpiFormatException(status));
19285db2f26eSSascha Wildner 	} else {
19295db2f26eSSascha Wildner 	    DELAY(1000000);
1930e11869f0SSascha Wildner 	    device_printf(sc->acpi_dev, "reset failed - timeout\n");
19315db2f26eSSascha Wildner 	}
19325db2f26eSSascha Wildner     } else if (sc->acpi_do_disable && panicstr == NULL) {
19335db2f26eSSascha Wildner 	/*
19345db2f26eSSascha Wildner 	 * Only disable ACPI if the user requested.  On some systems, writing
19355db2f26eSSascha Wildner 	 * the disable value to SMI_CMD hangs the system.
19365db2f26eSSascha Wildner 	 */
1937e11869f0SSascha Wildner 	device_printf(sc->acpi_dev, "Shutting down\n");
19385db2f26eSSascha Wildner 	AcpiTerminate();
19395db2f26eSSascha Wildner     }
19405db2f26eSSascha Wildner }
19415db2f26eSSascha Wildner 
19425db2f26eSSascha Wildner static void
acpi_enable_fixed_events(struct acpi_softc * sc)19435db2f26eSSascha Wildner acpi_enable_fixed_events(struct acpi_softc *sc)
19445db2f26eSSascha Wildner {
19455db2f26eSSascha Wildner     static int	first_time = 1;
19465db2f26eSSascha Wildner 
19475db2f26eSSascha Wildner     /* Enable and clear fixed events and install handlers. */
19485db2f26eSSascha Wildner     if ((AcpiGbl_FADT.Flags & ACPI_FADT_POWER_BUTTON) == 0) {
19495db2f26eSSascha Wildner 	AcpiClearEvent(ACPI_EVENT_POWER_BUTTON);
19505db2f26eSSascha Wildner 	AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON,
19515db2f26eSSascha Wildner 				     acpi_event_power_button_sleep, sc);
19525db2f26eSSascha Wildner 	if (first_time)
19535db2f26eSSascha Wildner 	    device_printf(sc->acpi_dev, "Power Button (fixed)\n");
19545db2f26eSSascha Wildner     }
19555db2f26eSSascha Wildner     if ((AcpiGbl_FADT.Flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
19565db2f26eSSascha Wildner 	AcpiClearEvent(ACPI_EVENT_SLEEP_BUTTON);
19575db2f26eSSascha Wildner 	AcpiInstallFixedEventHandler(ACPI_EVENT_SLEEP_BUTTON,
19585db2f26eSSascha Wildner 				     acpi_event_sleep_button_sleep, sc);
19595db2f26eSSascha Wildner 	if (first_time)
19605db2f26eSSascha Wildner 	    device_printf(sc->acpi_dev, "Sleep Button (fixed)\n");
19615db2f26eSSascha Wildner     }
19625db2f26eSSascha Wildner 
19635db2f26eSSascha Wildner     first_time = 0;
19645db2f26eSSascha Wildner }
19655db2f26eSSascha Wildner 
19665db2f26eSSascha Wildner /*
19675db2f26eSSascha Wildner  * Returns true if the device is actually present and should
19685db2f26eSSascha Wildner  * be attached to.  This requires the present, enabled, UI-visible
19695db2f26eSSascha Wildner  * and diagnostics-passed bits to be set.
19705db2f26eSSascha Wildner  */
19715db2f26eSSascha Wildner BOOLEAN
acpi_DeviceIsPresent(device_t dev)19725db2f26eSSascha Wildner acpi_DeviceIsPresent(device_t dev)
19735db2f26eSSascha Wildner {
19745db2f26eSSascha Wildner     ACPI_HANDLE		h;
19757bcb6cafSSascha Wildner     UINT32		s;
19767bcb6cafSSascha Wildner     ACPI_STATUS		status;
19775db2f26eSSascha Wildner 
19787bcb6cafSSascha Wildner     h = acpi_get_handle(dev);
19797bcb6cafSSascha Wildner     if (h == NULL)
19805db2f26eSSascha Wildner 	return (FALSE);
19817bcb6cafSSascha Wildner     status = acpi_GetInteger(h, "_STA", &s);
19825db2f26eSSascha Wildner 
1983691b8c66SSascha Wildner     /*
1984691b8c66SSascha Wildner      * If no _STA method or if it failed, then assume that
1985691b8c66SSascha Wildner      * the device is present.
1986691b8c66SSascha Wildner      */
19877bcb6cafSSascha Wildner     if (ACPI_FAILURE(status))
1988691b8c66SSascha Wildner 	return (TRUE);
19895db2f26eSSascha Wildner 
19907bcb6cafSSascha Wildner     return (ACPI_DEVICE_PRESENT(s) ? TRUE : FALSE);
19915db2f26eSSascha Wildner }
19925db2f26eSSascha Wildner 
19935db2f26eSSascha Wildner /*
19945db2f26eSSascha Wildner  * Returns true if the battery is actually present and inserted.
19955db2f26eSSascha Wildner  */
19965db2f26eSSascha Wildner BOOLEAN
acpi_BatteryIsPresent(device_t dev)19975db2f26eSSascha Wildner acpi_BatteryIsPresent(device_t dev)
19985db2f26eSSascha Wildner {
19995db2f26eSSascha Wildner     ACPI_HANDLE		h;
20007bcb6cafSSascha Wildner     UINT32		s;
20017bcb6cafSSascha Wildner     ACPI_STATUS		status;
20025db2f26eSSascha Wildner 
20037bcb6cafSSascha Wildner     h = acpi_get_handle(dev);
20047bcb6cafSSascha Wildner     if (h == NULL)
20055db2f26eSSascha Wildner 	return (FALSE);
20067bcb6cafSSascha Wildner     status = acpi_GetInteger(h, "_STA", &s);
20075db2f26eSSascha Wildner 
2008691b8c66SSascha Wildner     /*
2009691b8c66SSascha Wildner      * If no _STA method or if it failed, then assume that
2010691b8c66SSascha Wildner      * the device is present.
2011691b8c66SSascha Wildner      */
20127bcb6cafSSascha Wildner     if (ACPI_FAILURE(status))
2013691b8c66SSascha Wildner 	return (TRUE);
20145db2f26eSSascha Wildner 
20157bcb6cafSSascha Wildner     return (ACPI_BATTERY_PRESENT(s) ? TRUE : FALSE);
20165db2f26eSSascha Wildner }
20175db2f26eSSascha Wildner 
20185db2f26eSSascha Wildner /*
20195db2f26eSSascha Wildner  * Match a HID string against a handle
20205db2f26eSSascha Wildner  */
20215db2f26eSSascha Wildner BOOLEAN
acpi_MatchHid(ACPI_HANDLE h,const char * hid)20225db2f26eSSascha Wildner acpi_MatchHid(ACPI_HANDLE h, const char *hid)
20235db2f26eSSascha Wildner {
20245db2f26eSSascha Wildner     ACPI_DEVICE_INFO	*devinfo;
20255db2f26eSSascha Wildner     int			ret, i;
20265db2f26eSSascha Wildner 
20275db2f26eSSascha Wildner     ret = FALSE;
20286de2a7e6SSascha Wildner     if (hid == NULL || h == NULL ||
20296de2a7e6SSascha Wildner 	ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo)))
20305db2f26eSSascha Wildner 	return (ret);
20315db2f26eSSascha Wildner 
20325db2f26eSSascha Wildner     if ((devinfo->Valid & ACPI_VALID_HID) != 0 &&
20335db2f26eSSascha Wildner 	strcmp(hid, devinfo->HardwareId.String) == 0)
20345db2f26eSSascha Wildner 	    ret = TRUE;
20355db2f26eSSascha Wildner     else if ((devinfo->Valid & ACPI_VALID_CID) != 0) {
20365db2f26eSSascha Wildner 	for (i = 0; i < devinfo->CompatibleIdList.Count; i++) {
20375db2f26eSSascha Wildner 	    if (strcmp(hid, devinfo->CompatibleIdList.Ids[i].String) == 0) {
20385db2f26eSSascha Wildner 		ret = TRUE;
20395db2f26eSSascha Wildner 		break;
20405db2f26eSSascha Wildner 	    }
20415db2f26eSSascha Wildner 	}
20425db2f26eSSascha Wildner     }
20435db2f26eSSascha Wildner 
20445db2f26eSSascha Wildner     AcpiOsFree(devinfo);
20455db2f26eSSascha Wildner     return (ret);
20465db2f26eSSascha Wildner }
20475db2f26eSSascha Wildner 
20485db2f26eSSascha Wildner /*
204991912fdfSImre Vadász  * Match a UID string against a handle
205091912fdfSImre Vadász  */
205191912fdfSImre Vadász BOOLEAN
acpi_MatchUid(ACPI_HANDLE h,const char * uid)205291912fdfSImre Vadász acpi_MatchUid(ACPI_HANDLE h, const char *uid)
205391912fdfSImre Vadász {
205491912fdfSImre Vadász     ACPI_DEVICE_INFO	*devinfo;
205591912fdfSImre Vadász     int			ret;
205691912fdfSImre Vadász 
205791912fdfSImre Vadász     ret = FALSE;
205891912fdfSImre Vadász     if (uid == NULL || h == NULL ||
205991912fdfSImre Vadász 	ACPI_FAILURE(AcpiGetObjectInfo(h, &devinfo)))
206091912fdfSImre Vadász 	return (ret);
206191912fdfSImre Vadász 
206291912fdfSImre Vadász     if ((devinfo->Valid & ACPI_VALID_UID) != 0 &&
206391912fdfSImre Vadász 	strcmp(uid, devinfo->UniqueId.String) == 0)
206491912fdfSImre Vadász 	ret = TRUE;
206591912fdfSImre Vadász 
206691912fdfSImre Vadász     AcpiOsFree(devinfo);
206791912fdfSImre Vadász     return (ret);
206891912fdfSImre Vadász }
206991912fdfSImre Vadász 
207091912fdfSImre Vadász /*
20715db2f26eSSascha Wildner  * Return the handle of a named object within our scope, ie. that of (parent)
20725db2f26eSSascha Wildner  * or one if its parents.
20735db2f26eSSascha Wildner  */
20745db2f26eSSascha Wildner ACPI_STATUS
acpi_GetHandleInScope(ACPI_HANDLE parent,char * path,ACPI_HANDLE * result)20755db2f26eSSascha Wildner acpi_GetHandleInScope(ACPI_HANDLE parent, char *path, ACPI_HANDLE *result)
20765db2f26eSSascha Wildner {
20775db2f26eSSascha Wildner     ACPI_HANDLE		r;
20785db2f26eSSascha Wildner     ACPI_STATUS		status;
20795db2f26eSSascha Wildner 
20805db2f26eSSascha Wildner     /* Walk back up the tree to the root */
20815db2f26eSSascha Wildner     for (;;) {
20825db2f26eSSascha Wildner 	status = AcpiGetHandle(parent, path, &r);
20835db2f26eSSascha Wildner 	if (ACPI_SUCCESS(status)) {
20845db2f26eSSascha Wildner 	    *result = r;
20855db2f26eSSascha Wildner 	    return (AE_OK);
20865db2f26eSSascha Wildner 	}
20875db2f26eSSascha Wildner 	/* XXX Return error here? */
20885db2f26eSSascha Wildner 	if (status != AE_NOT_FOUND)
20895db2f26eSSascha Wildner 	    return (AE_OK);
20905db2f26eSSascha Wildner 	if (ACPI_FAILURE(AcpiGetParent(parent, &r)))
20915db2f26eSSascha Wildner 	    return (AE_NOT_FOUND);
20925db2f26eSSascha Wildner 	parent = r;
20935db2f26eSSascha Wildner     }
20945db2f26eSSascha Wildner }
20955db2f26eSSascha Wildner 
20965db2f26eSSascha Wildner /*
20975db2f26eSSascha Wildner  * Allocate a buffer with a preset data size.
20985db2f26eSSascha Wildner  */
20995db2f26eSSascha Wildner ACPI_BUFFER *
acpi_AllocBuffer(int size)21005db2f26eSSascha Wildner acpi_AllocBuffer(int size)
21015db2f26eSSascha Wildner {
21025db2f26eSSascha Wildner     ACPI_BUFFER	*buf;
21035db2f26eSSascha Wildner 
21045db2f26eSSascha Wildner     if ((buf = kmalloc(size + sizeof(*buf), M_ACPIDEV, M_NOWAIT)) == NULL)
21055db2f26eSSascha Wildner 	return (NULL);
21065db2f26eSSascha Wildner     buf->Length = size;
21075db2f26eSSascha Wildner     buf->Pointer = (void *)(buf + 1);
21085db2f26eSSascha Wildner     return (buf);
21095db2f26eSSascha Wildner }
21105db2f26eSSascha Wildner 
21115db2f26eSSascha Wildner ACPI_STATUS
acpi_SetInteger(ACPI_HANDLE handle,char * path,UINT32 number)21125db2f26eSSascha Wildner acpi_SetInteger(ACPI_HANDLE handle, char *path, UINT32 number)
21135db2f26eSSascha Wildner {
21145db2f26eSSascha Wildner     ACPI_OBJECT arg1;
21155db2f26eSSascha Wildner     ACPI_OBJECT_LIST args;
21165db2f26eSSascha Wildner 
21175db2f26eSSascha Wildner     arg1.Type = ACPI_TYPE_INTEGER;
21185db2f26eSSascha Wildner     arg1.Integer.Value = number;
21195db2f26eSSascha Wildner     args.Count = 1;
21205db2f26eSSascha Wildner     args.Pointer = &arg1;
21215db2f26eSSascha Wildner 
21225db2f26eSSascha Wildner     return (AcpiEvaluateObject(handle, path, &args, NULL));
21235db2f26eSSascha Wildner }
21245db2f26eSSascha Wildner 
21255db2f26eSSascha Wildner /*
21265db2f26eSSascha Wildner  * Evaluate a path that should return an integer.
21275db2f26eSSascha Wildner  */
21285db2f26eSSascha Wildner ACPI_STATUS
acpi_GetInteger(ACPI_HANDLE handle,char * path,UINT32 * number)21295db2f26eSSascha Wildner acpi_GetInteger(ACPI_HANDLE handle, char *path, UINT32 *number)
21305db2f26eSSascha Wildner {
21315db2f26eSSascha Wildner     ACPI_STATUS	status;
21325db2f26eSSascha Wildner     ACPI_BUFFER	buf;
21335db2f26eSSascha Wildner     ACPI_OBJECT	param;
21345db2f26eSSascha Wildner 
21355db2f26eSSascha Wildner     if (handle == NULL)
21365db2f26eSSascha Wildner 	handle = ACPI_ROOT_OBJECT;
21375db2f26eSSascha Wildner 
21385db2f26eSSascha Wildner     /*
21395db2f26eSSascha Wildner      * Assume that what we've been pointed at is an Integer object, or
21405db2f26eSSascha Wildner      * a method that will return an Integer.
21415db2f26eSSascha Wildner      */
21425db2f26eSSascha Wildner     buf.Pointer = &param;
21435db2f26eSSascha Wildner     buf.Length = sizeof(param);
21445db2f26eSSascha Wildner     status = AcpiEvaluateObject(handle, path, NULL, &buf);
21455db2f26eSSascha Wildner     if (ACPI_SUCCESS(status)) {
21465db2f26eSSascha Wildner 	if (param.Type == ACPI_TYPE_INTEGER)
21475db2f26eSSascha Wildner 	    *number = param.Integer.Value;
21485db2f26eSSascha Wildner 	else
21495db2f26eSSascha Wildner 	    status = AE_TYPE;
21505db2f26eSSascha Wildner     }
21515db2f26eSSascha Wildner 
21525db2f26eSSascha Wildner     /*
21535db2f26eSSascha Wildner      * In some applications, a method that's expected to return an Integer
21545db2f26eSSascha Wildner      * may instead return a Buffer (probably to simplify some internal
21555db2f26eSSascha Wildner      * arithmetic).  We'll try to fetch whatever it is, and if it's a Buffer,
21565db2f26eSSascha Wildner      * convert it into an Integer as best we can.
21575db2f26eSSascha Wildner      *
21585db2f26eSSascha Wildner      * This is a hack.
21595db2f26eSSascha Wildner      */
21605db2f26eSSascha Wildner     if (status == AE_BUFFER_OVERFLOW) {
21615db2f26eSSascha Wildner 	if ((buf.Pointer = AcpiOsAllocate(buf.Length)) == NULL) {
21625db2f26eSSascha Wildner 	    status = AE_NO_MEMORY;
21635db2f26eSSascha Wildner 	} else {
21645db2f26eSSascha Wildner 	    status = AcpiEvaluateObject(handle, path, NULL, &buf);
21655db2f26eSSascha Wildner 	    if (ACPI_SUCCESS(status))
21665db2f26eSSascha Wildner 		status = acpi_ConvertBufferToInteger(&buf, number);
21675db2f26eSSascha Wildner 	    AcpiOsFree(buf.Pointer);
21685db2f26eSSascha Wildner 	}
21695db2f26eSSascha Wildner     }
21705db2f26eSSascha Wildner     return (status);
21715db2f26eSSascha Wildner }
21725db2f26eSSascha Wildner 
21735db2f26eSSascha Wildner ACPI_STATUS
acpi_ConvertBufferToInteger(ACPI_BUFFER * bufp,UINT32 * number)21745db2f26eSSascha Wildner acpi_ConvertBufferToInteger(ACPI_BUFFER *bufp, UINT32 *number)
21755db2f26eSSascha Wildner {
21765db2f26eSSascha Wildner     ACPI_OBJECT	*p;
21775db2f26eSSascha Wildner     UINT8	*val;
21785db2f26eSSascha Wildner     int		i;
21795db2f26eSSascha Wildner 
21805db2f26eSSascha Wildner     p = (ACPI_OBJECT *)bufp->Pointer;
21815db2f26eSSascha Wildner     if (p->Type == ACPI_TYPE_INTEGER) {
21825db2f26eSSascha Wildner 	*number = p->Integer.Value;
21835db2f26eSSascha Wildner 	return (AE_OK);
21845db2f26eSSascha Wildner     }
21855db2f26eSSascha Wildner     if (p->Type != ACPI_TYPE_BUFFER)
21865db2f26eSSascha Wildner 	return (AE_TYPE);
21875db2f26eSSascha Wildner     if (p->Buffer.Length > sizeof(int))
21885db2f26eSSascha Wildner 	return (AE_BAD_DATA);
21895db2f26eSSascha Wildner 
21905db2f26eSSascha Wildner     *number = 0;
21915db2f26eSSascha Wildner     val = p->Buffer.Pointer;
21925db2f26eSSascha Wildner     for (i = 0; i < p->Buffer.Length; i++)
21935db2f26eSSascha Wildner 	*number += val[i] << (i * 8);
21945db2f26eSSascha Wildner     return (AE_OK);
21955db2f26eSSascha Wildner }
21965db2f26eSSascha Wildner 
21975db2f26eSSascha Wildner /*
21985db2f26eSSascha Wildner  * Iterate over the elements of an a package object, calling the supplied
21995db2f26eSSascha Wildner  * function for each element.
22005db2f26eSSascha Wildner  *
22015db2f26eSSascha Wildner  * XXX possible enhancement might be to abort traversal on error.
22025db2f26eSSascha Wildner  */
22035db2f26eSSascha Wildner ACPI_STATUS
acpi_ForeachPackageObject(ACPI_OBJECT * pkg,void (* func)(ACPI_OBJECT * comp,void * arg),void * arg)22045db2f26eSSascha Wildner acpi_ForeachPackageObject(ACPI_OBJECT *pkg,
22055db2f26eSSascha Wildner 	void (*func)(ACPI_OBJECT *comp, void *arg), void *arg)
22065db2f26eSSascha Wildner {
22075db2f26eSSascha Wildner     ACPI_OBJECT	*comp;
22085db2f26eSSascha Wildner     int		i;
22095db2f26eSSascha Wildner 
22105db2f26eSSascha Wildner     if (pkg == NULL || pkg->Type != ACPI_TYPE_PACKAGE)
22115db2f26eSSascha Wildner 	return (AE_BAD_PARAMETER);
22125db2f26eSSascha Wildner 
22135db2f26eSSascha Wildner     /* Iterate over components */
22145db2f26eSSascha Wildner     i = 0;
22155db2f26eSSascha Wildner     comp = pkg->Package.Elements;
22165db2f26eSSascha Wildner     for (; i < pkg->Package.Count; i++, comp++)
22175db2f26eSSascha Wildner 	func(comp, arg);
22185db2f26eSSascha Wildner 
22195db2f26eSSascha Wildner     return (AE_OK);
22205db2f26eSSascha Wildner }
22215db2f26eSSascha Wildner 
22225db2f26eSSascha Wildner /*
22235db2f26eSSascha Wildner  * Find the (index)th resource object in a set.
22245db2f26eSSascha Wildner  */
22255db2f26eSSascha Wildner ACPI_STATUS
acpi_FindIndexedResource(ACPI_BUFFER * buf,int index,ACPI_RESOURCE ** resp)22265db2f26eSSascha Wildner acpi_FindIndexedResource(ACPI_BUFFER *buf, int index, ACPI_RESOURCE **resp)
22275db2f26eSSascha Wildner {
22285db2f26eSSascha Wildner     ACPI_RESOURCE	*rp;
22295db2f26eSSascha Wildner     int			i;
22305db2f26eSSascha Wildner 
22315db2f26eSSascha Wildner     rp = (ACPI_RESOURCE *)buf->Pointer;
22325db2f26eSSascha Wildner     i = index;
22335db2f26eSSascha Wildner     while (i-- > 0) {
22345db2f26eSSascha Wildner 	/* Range check */
22353905511eSSascha Wildner 	if (rp > (ACPI_RESOURCE *)((uint8_t *)buf->Pointer + buf->Length))
22365db2f26eSSascha Wildner 	    return (AE_BAD_PARAMETER);
22375db2f26eSSascha Wildner 
22385db2f26eSSascha Wildner 	/* Check for terminator */
22395db2f26eSSascha Wildner 	if (rp->Type == ACPI_RESOURCE_TYPE_END_TAG || rp->Length == 0)
22405db2f26eSSascha Wildner 	    return (AE_NOT_FOUND);
22415db2f26eSSascha Wildner 	rp = ACPI_NEXT_RESOURCE(rp);
22425db2f26eSSascha Wildner     }
22435db2f26eSSascha Wildner     if (resp != NULL)
22445db2f26eSSascha Wildner 	*resp = rp;
22455db2f26eSSascha Wildner 
22465db2f26eSSascha Wildner     return (AE_OK);
22475db2f26eSSascha Wildner }
22485db2f26eSSascha Wildner 
22495db2f26eSSascha Wildner /*
22505db2f26eSSascha Wildner  * Append an ACPI_RESOURCE to an ACPI_BUFFER.
22515db2f26eSSascha Wildner  *
22525db2f26eSSascha Wildner  * Given a pointer to an ACPI_RESOURCE structure, expand the ACPI_BUFFER
22535db2f26eSSascha Wildner  * provided to contain it.  If the ACPI_BUFFER is empty, allocate a sensible
22545db2f26eSSascha Wildner  * backing block.  If the ACPI_RESOURCE is NULL, return an empty set of
22555db2f26eSSascha Wildner  * resources.
22565db2f26eSSascha Wildner  */
22575db2f26eSSascha Wildner #define ACPI_INITIAL_RESOURCE_BUFFER_SIZE	512
22585db2f26eSSascha Wildner 
22595db2f26eSSascha Wildner ACPI_STATUS
acpi_AppendBufferResource(ACPI_BUFFER * buf,ACPI_RESOURCE * res)22605db2f26eSSascha Wildner acpi_AppendBufferResource(ACPI_BUFFER *buf, ACPI_RESOURCE *res)
22615db2f26eSSascha Wildner {
22625db2f26eSSascha Wildner     ACPI_RESOURCE	*rp;
22635db2f26eSSascha Wildner     void		*newp;
22645db2f26eSSascha Wildner 
22655db2f26eSSascha Wildner     /* Initialise the buffer if necessary. */
22665db2f26eSSascha Wildner     if (buf->Pointer == NULL) {
22675db2f26eSSascha Wildner 	buf->Length = ACPI_INITIAL_RESOURCE_BUFFER_SIZE;
22685db2f26eSSascha Wildner 	if ((buf->Pointer = AcpiOsAllocate(buf->Length)) == NULL)
22695db2f26eSSascha Wildner 	    return (AE_NO_MEMORY);
22705db2f26eSSascha Wildner 	rp = (ACPI_RESOURCE *)buf->Pointer;
22715db2f26eSSascha Wildner 	rp->Type = ACPI_RESOURCE_TYPE_END_TAG;
227203885966SSascha Wildner 	rp->Length = ACPI_RS_SIZE_MIN;
22735db2f26eSSascha Wildner     }
22745db2f26eSSascha Wildner     if (res == NULL)
22755db2f26eSSascha Wildner 	return (AE_OK);
22765db2f26eSSascha Wildner 
22775db2f26eSSascha Wildner     /*
22785db2f26eSSascha Wildner      * Scan the current buffer looking for the terminator.
22795db2f26eSSascha Wildner      * This will either find the terminator or hit the end
22805db2f26eSSascha Wildner      * of the buffer and return an error.
22815db2f26eSSascha Wildner      */
22825db2f26eSSascha Wildner     rp = (ACPI_RESOURCE *)buf->Pointer;
22835db2f26eSSascha Wildner     for (;;) {
22845db2f26eSSascha Wildner 	/* Range check, don't go outside the buffer */
22853905511eSSascha Wildner 	if (rp >= (ACPI_RESOURCE *)((uint8_t *)buf->Pointer + buf->Length))
22865db2f26eSSascha Wildner 	    return (AE_BAD_PARAMETER);
22875db2f26eSSascha Wildner 	if (rp->Type == ACPI_RESOURCE_TYPE_END_TAG || rp->Length == 0)
22885db2f26eSSascha Wildner 	    break;
22895db2f26eSSascha Wildner 	rp = ACPI_NEXT_RESOURCE(rp);
22905db2f26eSSascha Wildner     }
22915db2f26eSSascha Wildner 
22925db2f26eSSascha Wildner     /*
22935db2f26eSSascha Wildner      * Check the size of the buffer and expand if required.
22945db2f26eSSascha Wildner      *
22955db2f26eSSascha Wildner      * Required size is:
22965db2f26eSSascha Wildner      *	size of existing resources before terminator +
22975db2f26eSSascha Wildner      *	size of new resource and header +
22985db2f26eSSascha Wildner      * 	size of terminator.
22995db2f26eSSascha Wildner      *
23005db2f26eSSascha Wildner      * Note that this loop should really only run once, unless
23015db2f26eSSascha Wildner      * for some reason we are stuffing a *really* huge resource.
23025db2f26eSSascha Wildner      */
23033905511eSSascha Wildner     while ((((uint8_t *)rp - (uint8_t *)buf->Pointer) +
23045db2f26eSSascha Wildner 	    res->Length + ACPI_RS_SIZE_NO_DATA +
23055db2f26eSSascha Wildner 	    ACPI_RS_SIZE_MIN) >= buf->Length) {
23065db2f26eSSascha Wildner 	if ((newp = AcpiOsAllocate(buf->Length * 2)) == NULL)
23075db2f26eSSascha Wildner 	    return (AE_NO_MEMORY);
23085db2f26eSSascha Wildner 	bcopy(buf->Pointer, newp, buf->Length);
23093905511eSSascha Wildner 	rp = (ACPI_RESOURCE *)((uint8_t *)newp +
23103905511eSSascha Wildner 			       ((uint8_t *)rp - (uint8_t *)buf->Pointer));
23115db2f26eSSascha Wildner 	AcpiOsFree(buf->Pointer);
23125db2f26eSSascha Wildner 	buf->Pointer = newp;
23135db2f26eSSascha Wildner 	buf->Length += buf->Length;
23145db2f26eSSascha Wildner     }
23155db2f26eSSascha Wildner 
23165db2f26eSSascha Wildner     /* Insert the new resource. */
23175db2f26eSSascha Wildner     bcopy(res, rp, res->Length + ACPI_RS_SIZE_NO_DATA);
23185db2f26eSSascha Wildner 
23195db2f26eSSascha Wildner     /* And add the terminator. */
23205db2f26eSSascha Wildner     rp = ACPI_NEXT_RESOURCE(rp);
23215db2f26eSSascha Wildner     rp->Type = ACPI_RESOURCE_TYPE_END_TAG;
232203885966SSascha Wildner     rp->Length = ACPI_RS_SIZE_MIN;
23235db2f26eSSascha Wildner 
23245db2f26eSSascha Wildner     return (AE_OK);
23255db2f26eSSascha Wildner }
23265db2f26eSSascha Wildner 
23275db2f26eSSascha Wildner /*
23285db2f26eSSascha Wildner  * Set interrupt model.
23295db2f26eSSascha Wildner  */
23305db2f26eSSascha Wildner ACPI_STATUS
acpi_SetIntrModel(int model)23315db2f26eSSascha Wildner acpi_SetIntrModel(int model)
23325db2f26eSSascha Wildner {
23335db2f26eSSascha Wildner 
23345db2f26eSSascha Wildner     return (acpi_SetInteger(ACPI_ROOT_OBJECT, "_PIC", model));
23355db2f26eSSascha Wildner }
23365db2f26eSSascha Wildner 
23375db2f26eSSascha Wildner /*
23385db2f26eSSascha Wildner  * DEPRECATED.  This interface has serious deficiencies and will be
23395db2f26eSSascha Wildner  * removed.
23405db2f26eSSascha Wildner  *
23415db2f26eSSascha Wildner  * Immediately enter the sleep state.  In the old model, acpiconf(8) ran
23425db2f26eSSascha Wildner  * rc.suspend and rc.resume so we don't have to notify devd(8) to do this.
23435db2f26eSSascha Wildner  */
23445db2f26eSSascha Wildner ACPI_STATUS
acpi_SetSleepState(struct acpi_softc * sc,int state)23455db2f26eSSascha Wildner acpi_SetSleepState(struct acpi_softc *sc, int state)
23465db2f26eSSascha Wildner {
23475db2f26eSSascha Wildner     static int once;
23485db2f26eSSascha Wildner 
23495db2f26eSSascha Wildner     if (!once) {
2350e11869f0SSascha Wildner 	device_printf(sc->acpi_dev,
23515db2f26eSSascha Wildner "warning: acpi_SetSleepState() deprecated, need to update your software\n");
23525db2f26eSSascha Wildner 	once = 1;
23535db2f26eSSascha Wildner     }
23545db2f26eSSascha Wildner     return (acpi_EnterSleepState(sc, state));
23555db2f26eSSascha Wildner }
23565db2f26eSSascha Wildner 
23575db2f26eSSascha Wildner static void
acpi_sleep_force(void * arg)23585db2f26eSSascha Wildner acpi_sleep_force(void *arg)
23595db2f26eSSascha Wildner {
23605db2f26eSSascha Wildner     struct acpi_softc *sc;
23615db2f26eSSascha Wildner 
23625db2f26eSSascha Wildner     sc = arg;
2363e11869f0SSascha Wildner     device_printf(sc->acpi_dev,
2364e11869f0SSascha Wildner 	"suspend request timed out, forcing sleep now\n");
23655db2f26eSSascha Wildner     if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_sstate)))
2366e11869f0SSascha Wildner 	device_printf(sc->acpi_dev, "force sleep state S%d failed\n",
2367e11869f0SSascha Wildner 	    sc->acpi_next_sstate);
23685db2f26eSSascha Wildner }
23695db2f26eSSascha Wildner 
23705db2f26eSSascha Wildner /*
23715db2f26eSSascha Wildner  * Request that the system enter the given suspend state.  All /dev/apm
23725db2f26eSSascha Wildner  * devices and devd(8) will be notified.  Userland then has a chance to
23735db2f26eSSascha Wildner  * save state and acknowledge the request.  The system sleeps once all
23745db2f26eSSascha Wildner  * acks are in.
23755db2f26eSSascha Wildner  */
23765db2f26eSSascha Wildner int
acpi_ReqSleepState(struct acpi_softc * sc,int state)23775db2f26eSSascha Wildner acpi_ReqSleepState(struct acpi_softc *sc, int state)
23785db2f26eSSascha Wildner {
23795db2f26eSSascha Wildner #ifdef notyet
23805db2f26eSSascha Wildner     struct apm_clone_data *clone;
23815db2f26eSSascha Wildner #endif
23825db2f26eSSascha Wildner 
23835db2f26eSSascha Wildner     if (state < ACPI_STATE_S1 || state > ACPI_STATE_S5)
23845db2f26eSSascha Wildner 	return (EINVAL);
23855db2f26eSSascha Wildner 
23865db2f26eSSascha Wildner     /* S5 (soft-off) should be entered directly with no waiting. */
23875db2f26eSSascha Wildner     if (state == ACPI_STATE_S5) {
23885db2f26eSSascha Wildner 	if (ACPI_SUCCESS(acpi_EnterSleepState(sc, state)))
23895db2f26eSSascha Wildner 	    return (0);
23905db2f26eSSascha Wildner 	else
23915db2f26eSSascha Wildner 	    return (ENXIO);
23925db2f26eSSascha Wildner     }
23935db2f26eSSascha Wildner 
23945db2f26eSSascha Wildner     /* This platform does not support acpi suspend/resume. */
23955db2f26eSSascha Wildner     return (EOPNOTSUPP);
23965db2f26eSSascha Wildner 
23975db2f26eSSascha Wildner     /* If a suspend request is already in progress, just return. */
23985db2f26eSSascha Wildner     ACPI_LOCK(acpi);
23995db2f26eSSascha Wildner     if (sc->acpi_next_sstate != 0) {
24005db2f26eSSascha Wildner 	ACPI_UNLOCK(acpi);
24015db2f26eSSascha Wildner 	return (0);
24025db2f26eSSascha Wildner     }
24035db2f26eSSascha Wildner 
24045db2f26eSSascha Wildner     /* Record the pending state and notify all apm devices. */
24055db2f26eSSascha Wildner     sc->acpi_next_sstate = state;
24065db2f26eSSascha Wildner #if 0
24075db2f26eSSascha Wildner     STAILQ_FOREACH(clone, &sc->apm_cdevs, entries) {
24085db2f26eSSascha Wildner 	clone->notify_status = APM_EV_NONE;
24095db2f26eSSascha Wildner 	if ((clone->flags & ACPI_EVF_DEVD) == 0) {
24105db2f26eSSascha Wildner 	    KNOTE(&clone->sel_read.si_note, 0);
24115db2f26eSSascha Wildner 	}
24125db2f26eSSascha Wildner     }
24135db2f26eSSascha Wildner #endif
24145db2f26eSSascha Wildner 
24155db2f26eSSascha Wildner     /* If devd(8) is not running, immediately enter the sleep state. */
24165db2f26eSSascha Wildner     if (devctl_process_running() == FALSE) {
24175db2f26eSSascha Wildner 	ACPI_UNLOCK(acpi);
24185db2f26eSSascha Wildner 	if (ACPI_SUCCESS(acpi_EnterSleepState(sc, sc->acpi_next_sstate))) {
24195db2f26eSSascha Wildner 	    return (0);
24205db2f26eSSascha Wildner 	} else {
24215db2f26eSSascha Wildner 	    return (ENXIO);
24225db2f26eSSascha Wildner 	}
24235db2f26eSSascha Wildner     }
24245db2f26eSSascha Wildner 
24255db2f26eSSascha Wildner     /* Now notify devd(8) also. */
24265db2f26eSSascha Wildner     acpi_UserNotify("Suspend", ACPI_ROOT_OBJECT, state);
24275db2f26eSSascha Wildner 
24285db2f26eSSascha Wildner     /*
24295db2f26eSSascha Wildner      * Set a timeout to fire if userland doesn't ack the suspend request
24305db2f26eSSascha Wildner      * in time.  This way we still eventually go to sleep if we were
24315db2f26eSSascha Wildner      * overheating or running low on battery, even if userland is hung.
24325db2f26eSSascha Wildner      * We cancel this timeout once all userland acks are in or the
24335db2f26eSSascha Wildner      * suspend request is aborted.
24345db2f26eSSascha Wildner      */
24355db2f26eSSascha Wildner     callout_reset(&sc->susp_force_to, 10 * hz, acpi_sleep_force, sc);
24365db2f26eSSascha Wildner     ACPI_UNLOCK(acpi);
24377252c37cSMatthew Dillon 
24385db2f26eSSascha Wildner     return (0);
24395db2f26eSSascha Wildner }
24405db2f26eSSascha Wildner 
24415db2f26eSSascha Wildner /*
24425db2f26eSSascha Wildner  * Acknowledge (or reject) a pending sleep state.  The caller has
24435db2f26eSSascha Wildner  * prepared for suspend and is now ready for it to proceed.  If the
24445db2f26eSSascha Wildner  * error argument is non-zero, it indicates suspend should be cancelled
24455db2f26eSSascha Wildner  * and gives an errno value describing why.  Once all votes are in,
24465db2f26eSSascha Wildner  * we suspend the system.
24475db2f26eSSascha Wildner  */
24485db2f26eSSascha Wildner int
acpi_AckSleepState(struct apm_clone_data * clone,int error)24495db2f26eSSascha Wildner acpi_AckSleepState(struct apm_clone_data *clone, int error)
24505db2f26eSSascha Wildner {
24515db2f26eSSascha Wildner     struct acpi_softc *sc;
24525db2f26eSSascha Wildner     int ret, sleeping;
24535db2f26eSSascha Wildner 
24545db2f26eSSascha Wildner     /* This platform does not support acpi suspend/resume. */
24555db2f26eSSascha Wildner     return (EOPNOTSUPP);
24565db2f26eSSascha Wildner 
24575db2f26eSSascha Wildner     /* If no pending sleep state, return an error. */
24585db2f26eSSascha Wildner     ACPI_LOCK(acpi);
24595db2f26eSSascha Wildner     sc = clone->acpi_sc;
24605db2f26eSSascha Wildner     if (sc->acpi_next_sstate == 0) {
24615db2f26eSSascha Wildner 	ACPI_UNLOCK(acpi);
24625db2f26eSSascha Wildner 	return (ENXIO);
24635db2f26eSSascha Wildner     }
24645db2f26eSSascha Wildner 
24655db2f26eSSascha Wildner     /* Caller wants to abort suspend process. */
24665db2f26eSSascha Wildner     if (error) {
24675db2f26eSSascha Wildner 	sc->acpi_next_sstate = 0;
24685db2f26eSSascha Wildner 	callout_stop(&sc->susp_force_to);
2469e11869f0SSascha Wildner 	device_printf(sc->acpi_dev,
2470e11869f0SSascha Wildner 	    "listener on %s cancelled the pending suspend\n",
24715db2f26eSSascha Wildner 	    devtoname(clone->cdev));
24725db2f26eSSascha Wildner 	ACPI_UNLOCK(acpi);
24735db2f26eSSascha Wildner 	return (0);
24745db2f26eSSascha Wildner     }
24755db2f26eSSascha Wildner 
24765db2f26eSSascha Wildner     /*
24775db2f26eSSascha Wildner      * Mark this device as acking the suspend request.  Then, walk through
24785db2f26eSSascha Wildner      * all devices, seeing if they agree yet.  We only count devices that
24795db2f26eSSascha Wildner      * are writable since read-only devices couldn't ack the request.
24805db2f26eSSascha Wildner      */
24815db2f26eSSascha Wildner     clone->notify_status = APM_EV_ACKED;
24825db2f26eSSascha Wildner     sleeping = TRUE;
24835db2f26eSSascha Wildner     STAILQ_FOREACH(clone, &sc->apm_cdevs, entries) {
24845db2f26eSSascha Wildner 	if ((clone->flags & ACPI_EVF_WRITE) != 0 &&
24855db2f26eSSascha Wildner 	    clone->notify_status != APM_EV_ACKED) {
24865db2f26eSSascha Wildner 	    sleeping = FALSE;
24875db2f26eSSascha Wildner 	    break;
24885db2f26eSSascha Wildner 	}
24895db2f26eSSascha Wildner     }
24905db2f26eSSascha Wildner 
24915db2f26eSSascha Wildner     /* If all devices have voted "yes", we will suspend now. */
24925db2f26eSSascha Wildner     if (sleeping)
24935db2f26eSSascha Wildner 	callout_stop(&sc->susp_force_to);
24945db2f26eSSascha Wildner     ACPI_UNLOCK(acpi);
24955db2f26eSSascha Wildner     ret = 0;
24965db2f26eSSascha Wildner     if (sleeping) {
24975db2f26eSSascha Wildner 	if (ACPI_FAILURE(acpi_EnterSleepState(sc, sc->acpi_next_sstate)))
24985db2f26eSSascha Wildner 		ret = ENODEV;
24995db2f26eSSascha Wildner     }
25005db2f26eSSascha Wildner 
25015db2f26eSSascha Wildner     return (ret);
25025db2f26eSSascha Wildner }
25035db2f26eSSascha Wildner 
25045db2f26eSSascha Wildner static void
acpi_sleep_enable(void * arg)25055db2f26eSSascha Wildner acpi_sleep_enable(void *arg)
25065db2f26eSSascha Wildner {
25075db2f26eSSascha Wildner     ((struct acpi_softc *)arg)->acpi_sleep_disabled = 0;
25085db2f26eSSascha Wildner }
25095db2f26eSSascha Wildner 
25105db2f26eSSascha Wildner enum acpi_sleep_state {
25115db2f26eSSascha Wildner     ACPI_SS_NONE,
25125db2f26eSSascha Wildner     ACPI_SS_GPE_SET,
25135db2f26eSSascha Wildner     ACPI_SS_DEV_SUSPEND,
25145db2f26eSSascha Wildner     ACPI_SS_SLP_PREP,
25155db2f26eSSascha Wildner     ACPI_SS_SLEPT,
25165db2f26eSSascha Wildner };
25175db2f26eSSascha Wildner 
25185db2f26eSSascha Wildner /*
25195db2f26eSSascha Wildner  * Enter the desired system sleep state.
25205db2f26eSSascha Wildner  *
25215db2f26eSSascha Wildner  * Currently we support S1-S5 but S4 is only S4BIOS
25225db2f26eSSascha Wildner  */
25235db2f26eSSascha Wildner static ACPI_STATUS
acpi_EnterSleepState(struct acpi_softc * sc,int state)25245db2f26eSSascha Wildner acpi_EnterSleepState(struct acpi_softc *sc, int state)
25255db2f26eSSascha Wildner {
25265db2f26eSSascha Wildner     ACPI_STATUS	status;
25275db2f26eSSascha Wildner     UINT8	TypeA;
25285db2f26eSSascha Wildner     UINT8	TypeB;
25295db2f26eSSascha Wildner     enum acpi_sleep_state slp_state;
25305db2f26eSSascha Wildner 
25315db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
25325db2f26eSSascha Wildner 
25335db2f26eSSascha Wildner     /* Re-entry once we're suspending is not allowed. */
25345db2f26eSSascha Wildner     status = AE_OK;
25355db2f26eSSascha Wildner     ACPI_LOCK(acpi);
25365db2f26eSSascha Wildner     if (sc->acpi_sleep_disabled) {
25375db2f26eSSascha Wildner 	ACPI_UNLOCK(acpi);
2538e11869f0SSascha Wildner 	device_printf(sc->acpi_dev,
2539e11869f0SSascha Wildner 	    "suspend request ignored (not ready yet)\n");
25405db2f26eSSascha Wildner 	return (AE_ERROR);
25415db2f26eSSascha Wildner     }
25425db2f26eSSascha Wildner     sc->acpi_sleep_disabled = 1;
25435db2f26eSSascha Wildner     ACPI_UNLOCK(acpi);
25445db2f26eSSascha Wildner 
25455db2f26eSSascha Wildner     /*
25465db2f26eSSascha Wildner      * Be sure to hold Giant across DEVICE_SUSPEND/RESUME since non-MPSAFE
25475db2f26eSSascha Wildner      * drivers need this.
25485db2f26eSSascha Wildner      */
25495db2f26eSSascha Wildner     //get_mplock();
2550a639f788SMatthew Dillon 
25515db2f26eSSascha Wildner     slp_state = ACPI_SS_NONE;
25525db2f26eSSascha Wildner     switch (state) {
25535db2f26eSSascha Wildner     case ACPI_STATE_S1:
25545db2f26eSSascha Wildner     case ACPI_STATE_S2:
25555db2f26eSSascha Wildner     case ACPI_STATE_S3:
25565db2f26eSSascha Wildner     case ACPI_STATE_S4:
25575db2f26eSSascha Wildner 	status = AcpiGetSleepTypeData(state, &TypeA, &TypeB);
25585db2f26eSSascha Wildner 	if (status == AE_NOT_FOUND) {
25595db2f26eSSascha Wildner 	    device_printf(sc->acpi_dev,
25605db2f26eSSascha Wildner 			  "Sleep state S%d not supported by BIOS\n", state);
25615db2f26eSSascha Wildner 	    break;
25625db2f26eSSascha Wildner 	} else if (ACPI_FAILURE(status)) {
25635db2f26eSSascha Wildner 	    device_printf(sc->acpi_dev, "AcpiGetSleepTypeData failed - %s\n",
25645db2f26eSSascha Wildner 			  AcpiFormatException(status));
25655db2f26eSSascha Wildner 	    break;
25665db2f26eSSascha Wildner 	}
25675db2f26eSSascha Wildner 
25685db2f26eSSascha Wildner 	sc->acpi_sstate = state;
25695db2f26eSSascha Wildner 
25705db2f26eSSascha Wildner 	/* Enable any GPEs as appropriate and requested by the user. */
25715db2f26eSSascha Wildner 	acpi_wake_prep_walk(state);
25725db2f26eSSascha Wildner 	slp_state = ACPI_SS_GPE_SET;
25735db2f26eSSascha Wildner 
25745db2f26eSSascha Wildner 	/*
25755db2f26eSSascha Wildner 	 * Inform all devices that we are going to sleep.  If at least one
25765db2f26eSSascha Wildner 	 * device fails, DEVICE_SUSPEND() automatically resumes the tree.
25775db2f26eSSascha Wildner 	 *
25785db2f26eSSascha Wildner 	 * XXX Note that a better two-pass approach with a 'veto' pass
25795db2f26eSSascha Wildner 	 * followed by a "real thing" pass would be better, but the current
25805db2f26eSSascha Wildner 	 * bus interface does not provide for this.
25815db2f26eSSascha Wildner 	 */
25825db2f26eSSascha Wildner 	if (DEVICE_SUSPEND(root_bus) != 0) {
25835db2f26eSSascha Wildner 	    device_printf(sc->acpi_dev, "device_suspend failed\n");
25845db2f26eSSascha Wildner 	    break;
25855db2f26eSSascha Wildner 	}
25865db2f26eSSascha Wildner 	slp_state = ACPI_SS_DEV_SUSPEND;
25875db2f26eSSascha Wildner 
25885db2f26eSSascha Wildner 	/* If testing device suspend only, back out of everything here. */
25895db2f26eSSascha Wildner 	if (acpi_susp_bounce)
25905db2f26eSSascha Wildner 	    break;
25915db2f26eSSascha Wildner 
25925db2f26eSSascha Wildner 	status = AcpiEnterSleepStatePrep(state);
25935db2f26eSSascha Wildner 	if (ACPI_FAILURE(status)) {
25945db2f26eSSascha Wildner 	    device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n",
25955db2f26eSSascha Wildner 			  AcpiFormatException(status));
25965db2f26eSSascha Wildner 	    break;
25975db2f26eSSascha Wildner 	}
25985db2f26eSSascha Wildner 	slp_state = ACPI_SS_SLP_PREP;
25995db2f26eSSascha Wildner 
26005db2f26eSSascha Wildner 	if (sc->acpi_sleep_delay > 0)
26015db2f26eSSascha Wildner 	    DELAY(sc->acpi_sleep_delay * 1000000);
26025db2f26eSSascha Wildner 
26035db2f26eSSascha Wildner 	if (state != ACPI_STATE_S1) {
26045db2f26eSSascha Wildner 	    acpi_sleep_machdep(sc, state);
26055db2f26eSSascha Wildner 
26065db2f26eSSascha Wildner 	    /* Re-enable ACPI hardware on wakeup from sleep state 4. */
26075db2f26eSSascha Wildner 	    if (state == ACPI_STATE_S4)
26085db2f26eSSascha Wildner 		AcpiEnable();
26095db2f26eSSascha Wildner 	} else {
26105db2f26eSSascha Wildner 	    ACPI_DISABLE_IRQS();
26115db2f26eSSascha Wildner 	    status = AcpiEnterSleepState(state);
26125db2f26eSSascha Wildner 	    if (ACPI_FAILURE(status)) {
26135db2f26eSSascha Wildner 		device_printf(sc->acpi_dev, "AcpiEnterSleepState failed - %s\n",
26145db2f26eSSascha Wildner 			      AcpiFormatException(status));
26155db2f26eSSascha Wildner 		break;
26165db2f26eSSascha Wildner 	    }
26175db2f26eSSascha Wildner 	}
26185db2f26eSSascha Wildner 	slp_state = ACPI_SS_SLEPT;
26195db2f26eSSascha Wildner 	break;
26205db2f26eSSascha Wildner     case ACPI_STATE_S5:
26215db2f26eSSascha Wildner 	/*
26225db2f26eSSascha Wildner 	 * Shut down cleanly and power off.  This will call us back through the
26235db2f26eSSascha Wildner 	 * shutdown handlers.
26245db2f26eSSascha Wildner 	 */
26255db2f26eSSascha Wildner 	shutdown_nice(RB_POWEROFF);
26265db2f26eSSascha Wildner 	break;
26275db2f26eSSascha Wildner     case ACPI_STATE_S0:
26285db2f26eSSascha Wildner     default:
26295db2f26eSSascha Wildner 	status = AE_BAD_PARAMETER;
26305db2f26eSSascha Wildner 	break;
26315db2f26eSSascha Wildner     }
26325db2f26eSSascha Wildner 
26335db2f26eSSascha Wildner     /*
26345db2f26eSSascha Wildner      * Back out state according to how far along we got in the suspend
26355db2f26eSSascha Wildner      * process.  This handles both the error and success cases.
26365db2f26eSSascha Wildner      */
26375db2f26eSSascha Wildner     sc->acpi_next_sstate = 0;
26385db2f26eSSascha Wildner     if (slp_state >= ACPI_SS_GPE_SET) {
26395db2f26eSSascha Wildner 	acpi_wake_prep_walk(state);
26405db2f26eSSascha Wildner 	sc->acpi_sstate = ACPI_STATE_S0;
26415db2f26eSSascha Wildner     }
26425db2f26eSSascha Wildner     if (slp_state >= ACPI_SS_SLP_PREP)
26435db2f26eSSascha Wildner 	AcpiLeaveSleepState(state);
26445db2f26eSSascha Wildner     if (slp_state >= ACPI_SS_DEV_SUSPEND)
26455db2f26eSSascha Wildner 	DEVICE_RESUME(root_bus);
26465db2f26eSSascha Wildner     if (slp_state >= ACPI_SS_SLEPT)
26475db2f26eSSascha Wildner 	acpi_enable_fixed_events(sc);
26485db2f26eSSascha Wildner 
26495db2f26eSSascha Wildner     /* Allow another sleep request after a while. */
26505db2f26eSSascha Wildner     /* XXX: needs timeout */
26515db2f26eSSascha Wildner     if (state != ACPI_STATE_S5)
26525db2f26eSSascha Wildner 	      acpi_sleep_enable(sc);
26535db2f26eSSascha Wildner 
26545db2f26eSSascha Wildner     /* Run /etc/rc.resume after we are back. */
26555db2f26eSSascha Wildner     acpi_UserNotify("Resume", ACPI_ROOT_OBJECT, state);
26565db2f26eSSascha Wildner 
26575db2f26eSSascha Wildner     //rel_mplock();
2658a639f788SMatthew Dillon 
26595db2f26eSSascha Wildner     return_ACPI_STATUS (status);
26605db2f26eSSascha Wildner }
26615db2f26eSSascha Wildner 
26625db2f26eSSascha Wildner /* Enable or disable the device's GPE. */
26635db2f26eSSascha Wildner int
acpi_wake_set_enable(device_t dev,int enable)26645db2f26eSSascha Wildner acpi_wake_set_enable(device_t dev, int enable)
26655db2f26eSSascha Wildner {
26665db2f26eSSascha Wildner     struct acpi_prw_data prw;
26675db2f26eSSascha Wildner     ACPI_STATUS status;
26685db2f26eSSascha Wildner     int flags;
26695db2f26eSSascha Wildner 
26705db2f26eSSascha Wildner     /* Make sure the device supports waking the system and get the GPE. */
26715db2f26eSSascha Wildner     if (acpi_parse_prw(acpi_get_handle(dev), &prw) != 0)
26725db2f26eSSascha Wildner 	return (ENXIO);
26735db2f26eSSascha Wildner 
26745db2f26eSSascha Wildner     flags = acpi_get_flags(dev);
26755db2f26eSSascha Wildner     if (enable) {
26765db2f26eSSascha Wildner 	status = AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit,
26775db2f26eSSascha Wildner                                     ACPI_GPE_ENABLE);
26785db2f26eSSascha Wildner 	if (ACPI_FAILURE(status)) {
26795db2f26eSSascha Wildner 	    device_printf(dev, "enable wake failed\n");
26805db2f26eSSascha Wildner 	    return (ENXIO);
26815db2f26eSSascha Wildner 	}
26825db2f26eSSascha Wildner 	acpi_set_flags(dev, flags | ACPI_FLAG_WAKE_ENABLED);
26835db2f26eSSascha Wildner     } else {
26845db2f26eSSascha Wildner 	status = AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit,
26855db2f26eSSascha Wildner                                     ACPI_GPE_DISABLE);
26865db2f26eSSascha Wildner 	if (ACPI_FAILURE(status)) {
26875db2f26eSSascha Wildner 	    device_printf(dev, "disable wake failed\n");
26885db2f26eSSascha Wildner 	    return (ENXIO);
26895db2f26eSSascha Wildner 	}
26905db2f26eSSascha Wildner 	acpi_set_flags(dev, flags & ~ACPI_FLAG_WAKE_ENABLED);
26915db2f26eSSascha Wildner     }
26925db2f26eSSascha Wildner 
26935db2f26eSSascha Wildner     return (0);
26945db2f26eSSascha Wildner }
26955db2f26eSSascha Wildner 
26965db2f26eSSascha Wildner static int
acpi_wake_sleep_prep(ACPI_HANDLE handle,int sstate)26975db2f26eSSascha Wildner acpi_wake_sleep_prep(ACPI_HANDLE handle, int sstate)
26985db2f26eSSascha Wildner {
26995db2f26eSSascha Wildner     struct acpi_prw_data prw;
27005db2f26eSSascha Wildner     device_t dev;
27015db2f26eSSascha Wildner 
27025db2f26eSSascha Wildner     /* Check that this is a wake-capable device and get its GPE. */
27035db2f26eSSascha Wildner     if (acpi_parse_prw(handle, &prw) != 0)
27045db2f26eSSascha Wildner 	return (ENXIO);
27055db2f26eSSascha Wildner     dev = acpi_get_device(handle);
27065db2f26eSSascha Wildner 
27075db2f26eSSascha Wildner     /*
27085db2f26eSSascha Wildner      * The destination sleep state must be less than (i.e., higher power)
27095db2f26eSSascha Wildner      * or equal to the value specified by _PRW.  If this GPE cannot be
27105db2f26eSSascha Wildner      * enabled for the next sleep state, then disable it.  If it can and
27115db2f26eSSascha Wildner      * the user requested it be enabled, turn on any required power resources
27125db2f26eSSascha Wildner      * and set _PSW.
27135db2f26eSSascha Wildner      */
27145db2f26eSSascha Wildner     if (sstate > prw.lowest_wake) {
27155db2f26eSSascha Wildner 	AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit, ACPI_GPE_DISABLE);
27165db2f26eSSascha Wildner 	if (bootverbose)
27175db2f26eSSascha Wildner 	    device_printf(dev, "wake_prep disabled wake for %s (S%d)\n",
27185db2f26eSSascha Wildner 		acpi_name(handle), sstate);
27195db2f26eSSascha Wildner     } else if (dev && (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) != 0) {
27205db2f26eSSascha Wildner 	acpi_pwr_wake_enable(handle, 1);
27215db2f26eSSascha Wildner 	acpi_SetInteger(handle, "_PSW", 1);
27225db2f26eSSascha Wildner 	if (bootverbose)
27235db2f26eSSascha Wildner 	    device_printf(dev, "wake_prep enabled for %s (S%d)\n",
27245db2f26eSSascha Wildner 		acpi_name(handle), sstate);
27255db2f26eSSascha Wildner     }
27265db2f26eSSascha Wildner 
27275db2f26eSSascha Wildner     return (0);
27285db2f26eSSascha Wildner }
27295db2f26eSSascha Wildner 
27305db2f26eSSascha Wildner static int
acpi_wake_run_prep(ACPI_HANDLE handle,int sstate)27315db2f26eSSascha Wildner acpi_wake_run_prep(ACPI_HANDLE handle, int sstate)
27325db2f26eSSascha Wildner {
27335db2f26eSSascha Wildner     struct acpi_prw_data prw;
27345db2f26eSSascha Wildner     device_t dev;
27355db2f26eSSascha Wildner 
27365db2f26eSSascha Wildner     /*
27375db2f26eSSascha Wildner      * Check that this is a wake-capable device and get its GPE.  Return
27385db2f26eSSascha Wildner      * now if the user didn't enable this device for wake.
27395db2f26eSSascha Wildner      */
27405db2f26eSSascha Wildner     if (acpi_parse_prw(handle, &prw) != 0)
27415db2f26eSSascha Wildner 	return (ENXIO);
27425db2f26eSSascha Wildner     dev = acpi_get_device(handle);
27435db2f26eSSascha Wildner     if (dev == NULL || (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) == 0)
27445db2f26eSSascha Wildner 	return (0);
27455db2f26eSSascha Wildner 
27465db2f26eSSascha Wildner     /*
27475db2f26eSSascha Wildner      * If this GPE couldn't be enabled for the previous sleep state, it was
27485db2f26eSSascha Wildner      * disabled before going to sleep so re-enable it.  If it was enabled,
27495db2f26eSSascha Wildner      * clear _PSW and turn off any power resources it used.
27505db2f26eSSascha Wildner      */
27515db2f26eSSascha Wildner     if (sstate > prw.lowest_wake) {
27525db2f26eSSascha Wildner 	AcpiSetGpeWakeMask(prw.gpe_handle, prw.gpe_bit, ACPI_GPE_ENABLE);
27535db2f26eSSascha Wildner 	if (bootverbose)
27545db2f26eSSascha Wildner 	    device_printf(dev, "run_prep re-enabled %s\n", acpi_name(handle));
27555db2f26eSSascha Wildner     } else {
27565db2f26eSSascha Wildner 	acpi_SetInteger(handle, "_PSW", 0);
27575db2f26eSSascha Wildner 	acpi_pwr_wake_enable(handle, 0);
27585db2f26eSSascha Wildner 	if (bootverbose)
27595db2f26eSSascha Wildner 	    device_printf(dev, "run_prep cleaned up for %s\n",
27605db2f26eSSascha Wildner 		acpi_name(handle));
27615db2f26eSSascha Wildner     }
27625db2f26eSSascha Wildner 
27635db2f26eSSascha Wildner     return (0);
27645db2f26eSSascha Wildner }
27655db2f26eSSascha Wildner 
27665db2f26eSSascha Wildner static ACPI_STATUS
acpi_wake_prep(ACPI_HANDLE handle,UINT32 level,void * context,void ** status)27675db2f26eSSascha Wildner acpi_wake_prep(ACPI_HANDLE handle, UINT32 level, void *context, void **status)
27685db2f26eSSascha Wildner {
27695db2f26eSSascha Wildner     int sstate;
27705db2f26eSSascha Wildner 
27715db2f26eSSascha Wildner     /* If suspending, run the sleep prep function, otherwise wake. */
27725db2f26eSSascha Wildner     sstate = *(int *)context;
27735db2f26eSSascha Wildner     if (AcpiGbl_SystemAwakeAndRunning)
27745db2f26eSSascha Wildner 	acpi_wake_sleep_prep(handle, sstate);
27755db2f26eSSascha Wildner     else
27765db2f26eSSascha Wildner 	acpi_wake_run_prep(handle, sstate);
27775db2f26eSSascha Wildner     return (AE_OK);
27785db2f26eSSascha Wildner }
27795db2f26eSSascha Wildner 
27805db2f26eSSascha Wildner /* Walk the tree rooted at acpi0 to prep devices for suspend/resume. */
27815db2f26eSSascha Wildner static int
acpi_wake_prep_walk(int sstate)27825db2f26eSSascha Wildner acpi_wake_prep_walk(int sstate)
27835db2f26eSSascha Wildner {
27845db2f26eSSascha Wildner     ACPI_HANDLE sb_handle;
27855db2f26eSSascha Wildner 
27865db2f26eSSascha Wildner     if (ACPI_SUCCESS(AcpiGetHandle(ACPI_ROOT_OBJECT, "\\_SB_", &sb_handle))) {
27875db2f26eSSascha Wildner 	AcpiWalkNamespace(ACPI_TYPE_DEVICE, sb_handle, 100,
27885db2f26eSSascha Wildner 	    acpi_wake_prep, NULL, &sstate, NULL);
27895db2f26eSSascha Wildner     }
27905db2f26eSSascha Wildner     return (0);
27915db2f26eSSascha Wildner }
27925db2f26eSSascha Wildner 
27935db2f26eSSascha Wildner /* Walk the tree rooted at acpi0 to attach per-device wake sysctls. */
27945db2f26eSSascha Wildner static int
acpi_wake_sysctl_walk(device_t dev)27955db2f26eSSascha Wildner acpi_wake_sysctl_walk(device_t dev)
27965db2f26eSSascha Wildner {
27975db2f26eSSascha Wildner #ifdef notyet
27985db2f26eSSascha Wildner     int error, i, numdevs;
27995db2f26eSSascha Wildner     device_t *devlist;
28005db2f26eSSascha Wildner     device_t child;
28015db2f26eSSascha Wildner     ACPI_STATUS status;
28025db2f26eSSascha Wildner 
28035db2f26eSSascha Wildner     error = device_get_children(dev, &devlist, &numdevs);
28045db2f26eSSascha Wildner     if (error != 0 || numdevs == 0) {
28055db2f26eSSascha Wildner 	if (numdevs == 0)
28065db2f26eSSascha Wildner 	    kfree(devlist, M_TEMP);
28075db2f26eSSascha Wildner 	return (error);
28085db2f26eSSascha Wildner     }
28095db2f26eSSascha Wildner     for (i = 0; i < numdevs; i++) {
28105db2f26eSSascha Wildner 	child = devlist[i];
28115db2f26eSSascha Wildner 	acpi_wake_sysctl_walk(child);
28125db2f26eSSascha Wildner 	if (!device_is_attached(child))
28135db2f26eSSascha Wildner 	    continue;
28145db2f26eSSascha Wildner 	status = AcpiEvaluateObject(acpi_get_handle(child), "_PRW", NULL, NULL);
28155db2f26eSSascha Wildner 	if (ACPI_SUCCESS(status)) {
28165db2f26eSSascha Wildner 	    SYSCTL_ADD_PROC(device_get_sysctl_ctx(child),
28175db2f26eSSascha Wildner 		SYSCTL_CHILDREN(device_get_sysctl_tree(child)), OID_AUTO,
28185db2f26eSSascha Wildner 		"wake", CTLTYPE_INT | CTLFLAG_RW, child, 0,
28195db2f26eSSascha Wildner 		acpi_wake_set_sysctl, "I", "Device set to wake the system");
28205db2f26eSSascha Wildner 	}
28215db2f26eSSascha Wildner     }
28225db2f26eSSascha Wildner     kfree(devlist, M_TEMP);
28235db2f26eSSascha Wildner #endif
28245db2f26eSSascha Wildner 
28255db2f26eSSascha Wildner     return (0);
28265db2f26eSSascha Wildner }
28275db2f26eSSascha Wildner 
28285db2f26eSSascha Wildner #ifdef notyet
28295db2f26eSSascha Wildner /* Enable or disable wake from userland. */
28305db2f26eSSascha Wildner static int
acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS)28315db2f26eSSascha Wildner acpi_wake_set_sysctl(SYSCTL_HANDLER_ARGS)
28325db2f26eSSascha Wildner {
28335db2f26eSSascha Wildner     int enable, error;
28345db2f26eSSascha Wildner     device_t dev;
28355db2f26eSSascha Wildner 
28365db2f26eSSascha Wildner     dev = (device_t)arg1;
28375db2f26eSSascha Wildner     enable = (acpi_get_flags(dev) & ACPI_FLAG_WAKE_ENABLED) ? 1 : 0;
28385db2f26eSSascha Wildner 
28395db2f26eSSascha Wildner     error = sysctl_handle_int(oidp, &enable, 0, req);
28405db2f26eSSascha Wildner     if (error != 0 || req->newptr == NULL)
28415db2f26eSSascha Wildner 	return (error);
28425db2f26eSSascha Wildner     if (enable != 0 && enable != 1)
28435db2f26eSSascha Wildner 	return (EINVAL);
28445db2f26eSSascha Wildner 
28455db2f26eSSascha Wildner     return (acpi_wake_set_enable(dev, enable));
28465db2f26eSSascha Wildner }
28475db2f26eSSascha Wildner #endif
28485db2f26eSSascha Wildner 
28495db2f26eSSascha Wildner /* Parse a device's _PRW into a structure. */
28505db2f26eSSascha Wildner int
acpi_parse_prw(ACPI_HANDLE h,struct acpi_prw_data * prw)28515db2f26eSSascha Wildner acpi_parse_prw(ACPI_HANDLE h, struct acpi_prw_data *prw)
28525db2f26eSSascha Wildner {
28535db2f26eSSascha Wildner     ACPI_STATUS			status;
28545db2f26eSSascha Wildner     ACPI_BUFFER			prw_buffer;
28555db2f26eSSascha Wildner     ACPI_OBJECT			*res, *res2;
28565db2f26eSSascha Wildner     int				error, i, power_count;
28575db2f26eSSascha Wildner 
28585db2f26eSSascha Wildner     if (h == NULL || prw == NULL)
28595db2f26eSSascha Wildner 	return (EINVAL);
28605db2f26eSSascha Wildner 
28615db2f26eSSascha Wildner     /*
28625db2f26eSSascha Wildner      * The _PRW object (7.2.9) is only required for devices that have the
28635db2f26eSSascha Wildner      * ability to wake the system from a sleeping state.
28645db2f26eSSascha Wildner      */
28655db2f26eSSascha Wildner     error = EINVAL;
28665db2f26eSSascha Wildner     prw_buffer.Pointer = NULL;
28675db2f26eSSascha Wildner     prw_buffer.Length = ACPI_ALLOCATE_BUFFER;
28685db2f26eSSascha Wildner     status = AcpiEvaluateObject(h, "_PRW", NULL, &prw_buffer);
28695db2f26eSSascha Wildner     if (ACPI_FAILURE(status))
28705db2f26eSSascha Wildner 	return (ENOENT);
28715db2f26eSSascha Wildner     res = (ACPI_OBJECT *)prw_buffer.Pointer;
28725db2f26eSSascha Wildner     if (res == NULL)
28735db2f26eSSascha Wildner 	return (ENOENT);
28745db2f26eSSascha Wildner     if (!ACPI_PKG_VALID(res, 2))
28755db2f26eSSascha Wildner 	goto out;
28765db2f26eSSascha Wildner 
28775db2f26eSSascha Wildner     /*
28785db2f26eSSascha Wildner      * Element 1 of the _PRW object:
28795db2f26eSSascha Wildner      * The lowest power system sleeping state that can be entered while still
28805db2f26eSSascha Wildner      * providing wake functionality.  The sleeping state being entered must
28815db2f26eSSascha Wildner      * be less than (i.e., higher power) or equal to this value.
28825db2f26eSSascha Wildner      */
28835db2f26eSSascha Wildner     if (acpi_PkgInt32(res, 1, &prw->lowest_wake) != 0)
28845db2f26eSSascha Wildner 	goto out;
28855db2f26eSSascha Wildner 
28865db2f26eSSascha Wildner     /*
28875db2f26eSSascha Wildner      * Element 0 of the _PRW object:
28885db2f26eSSascha Wildner      */
28895db2f26eSSascha Wildner     switch (res->Package.Elements[0].Type) {
28905db2f26eSSascha Wildner     case ACPI_TYPE_INTEGER:
28915db2f26eSSascha Wildner 	/*
28925db2f26eSSascha Wildner 	 * If the data type of this package element is numeric, then this
28935db2f26eSSascha Wildner 	 * _PRW package element is the bit index in the GPEx_EN, in the
28945db2f26eSSascha Wildner 	 * GPE blocks described in the FADT, of the enable bit that is
28955db2f26eSSascha Wildner 	 * enabled for the wake event.
28965db2f26eSSascha Wildner 	 */
28975db2f26eSSascha Wildner 	prw->gpe_handle = NULL;
28985db2f26eSSascha Wildner 	prw->gpe_bit = res->Package.Elements[0].Integer.Value;
28995db2f26eSSascha Wildner 	error = 0;
29005db2f26eSSascha Wildner 	break;
29015db2f26eSSascha Wildner     case ACPI_TYPE_PACKAGE:
29025db2f26eSSascha Wildner 	/*
29035db2f26eSSascha Wildner 	 * If the data type of this package element is a package, then this
29045db2f26eSSascha Wildner 	 * _PRW package element is itself a package containing two
29055db2f26eSSascha Wildner 	 * elements.  The first is an object reference to the GPE Block
29065db2f26eSSascha Wildner 	 * device that contains the GPE that will be triggered by the wake
29075db2f26eSSascha Wildner 	 * event.  The second element is numeric and it contains the bit
29085db2f26eSSascha Wildner 	 * index in the GPEx_EN, in the GPE Block referenced by the
29095db2f26eSSascha Wildner 	 * first element in the package, of the enable bit that is enabled for
29105db2f26eSSascha Wildner 	 * the wake event.
29115db2f26eSSascha Wildner 	 *
29125db2f26eSSascha Wildner 	 * For example, if this field is a package then it is of the form:
29135db2f26eSSascha Wildner 	 * Package() {\_SB.PCI0.ISA.GPE, 2}
29145db2f26eSSascha Wildner 	 */
29155db2f26eSSascha Wildner 	res2 = &res->Package.Elements[0];
29165db2f26eSSascha Wildner 	if (!ACPI_PKG_VALID(res2, 2))
29175db2f26eSSascha Wildner 	    goto out;
29185db2f26eSSascha Wildner 	prw->gpe_handle = acpi_GetReference(NULL, &res2->Package.Elements[0]);
29195db2f26eSSascha Wildner 	if (prw->gpe_handle == NULL)
29205db2f26eSSascha Wildner 	    goto out;
29215db2f26eSSascha Wildner 	if (acpi_PkgInt32(res2, 1, &prw->gpe_bit) != 0)
29225db2f26eSSascha Wildner 	    goto out;
29235db2f26eSSascha Wildner 	error = 0;
29245db2f26eSSascha Wildner 	break;
29255db2f26eSSascha Wildner     default:
29265db2f26eSSascha Wildner 	goto out;
29275db2f26eSSascha Wildner     }
29285db2f26eSSascha Wildner 
29295db2f26eSSascha Wildner     /* Elements 2 to N of the _PRW object are power resources. */
29305db2f26eSSascha Wildner     power_count = res->Package.Count - 2;
29315db2f26eSSascha Wildner     if (power_count > ACPI_PRW_MAX_POWERRES) {
29325db2f26eSSascha Wildner 	kprintf("ACPI device %s has too many power resources\n", acpi_name(h));
29335db2f26eSSascha Wildner 	power_count = 0;
29345db2f26eSSascha Wildner     }
29355db2f26eSSascha Wildner     prw->power_res_count = power_count;
29365db2f26eSSascha Wildner     for (i = 0; i < power_count; i++)
29375db2f26eSSascha Wildner 	prw->power_res[i] = res->Package.Elements[i];
29385db2f26eSSascha Wildner 
29395db2f26eSSascha Wildner out:
29405db2f26eSSascha Wildner     if (prw_buffer.Pointer != NULL)
29415db2f26eSSascha Wildner 	AcpiOsFree(prw_buffer.Pointer);
29425db2f26eSSascha Wildner     return (error);
29435db2f26eSSascha Wildner }
29445db2f26eSSascha Wildner 
29455db2f26eSSascha Wildner /*
29465db2f26eSSascha Wildner  * ACPI Event Handlers
29475db2f26eSSascha Wildner  */
29485db2f26eSSascha Wildner 
29495db2f26eSSascha Wildner /* System Event Handlers (registered by EVENTHANDLER_REGISTER) */
29505db2f26eSSascha Wildner 
29515db2f26eSSascha Wildner static void
acpi_system_eventhandler_sleep(void * arg,int state)29525db2f26eSSascha Wildner acpi_system_eventhandler_sleep(void *arg, int state)
29535db2f26eSSascha Wildner {
2954e11869f0SSascha Wildner     struct acpi_softc *sc;
29555db2f26eSSascha Wildner     int ret;
29565db2f26eSSascha Wildner 
29575db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
29585db2f26eSSascha Wildner 
2959e11869f0SSascha Wildner     sc = arg;
2960e11869f0SSascha Wildner 
29615db2f26eSSascha Wildner     /* Check if button action is disabled. */
29625db2f26eSSascha Wildner     if (state == ACPI_S_STATES_MAX + 1)
29635db2f26eSSascha Wildner 	return;
29645db2f26eSSascha Wildner 
29655db2f26eSSascha Wildner     /* Request that the system prepare to enter the given suspend state. */
29665db2f26eSSascha Wildner     ret = acpi_ReqSleepState((struct acpi_softc *)arg, state);
29675db2f26eSSascha Wildner     if (ret != 0)
2968e11869f0SSascha Wildner 	device_printf(sc->acpi_dev,
2969e11869f0SSascha Wildner 	    "request to enter state S%d failed (err %d)\n", state, ret);
29705db2f26eSSascha Wildner 
29715db2f26eSSascha Wildner     return_VOID;
29725db2f26eSSascha Wildner }
29735db2f26eSSascha Wildner 
29745db2f26eSSascha Wildner static void
acpi_system_eventhandler_wakeup(void * arg,int state)29755db2f26eSSascha Wildner acpi_system_eventhandler_wakeup(void *arg, int state)
29765db2f26eSSascha Wildner {
29775db2f26eSSascha Wildner 
29785db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
29795db2f26eSSascha Wildner 
29805db2f26eSSascha Wildner     /* Currently, nothing to do for wakeup. */
29815db2f26eSSascha Wildner 
29825db2f26eSSascha Wildner     return_VOID;
29835db2f26eSSascha Wildner }
29845db2f26eSSascha Wildner 
29855db2f26eSSascha Wildner /*
29865db2f26eSSascha Wildner  * ACPICA Event Handlers (FixedEvent, also called from button notify handler)
29875db2f26eSSascha Wildner  */
29885db2f26eSSascha Wildner UINT32
acpi_event_power_button_sleep(void * context)29895db2f26eSSascha Wildner acpi_event_power_button_sleep(void *context)
29905db2f26eSSascha Wildner {
29915db2f26eSSascha Wildner     struct acpi_softc	*sc = (struct acpi_softc *)context;
29925db2f26eSSascha Wildner 
29935db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
29945db2f26eSSascha Wildner 
29955db2f26eSSascha Wildner     EVENTHANDLER_INVOKE(acpi_sleep_event, sc->acpi_power_button_sx);
29965db2f26eSSascha Wildner 
29975db2f26eSSascha Wildner     return_VALUE (ACPI_INTERRUPT_HANDLED);
29985db2f26eSSascha Wildner }
29995db2f26eSSascha Wildner 
30005db2f26eSSascha Wildner UINT32
acpi_event_power_button_wake(void * context)30015db2f26eSSascha Wildner acpi_event_power_button_wake(void *context)
30025db2f26eSSascha Wildner {
30035db2f26eSSascha Wildner     struct acpi_softc	*sc = (struct acpi_softc *)context;
30045db2f26eSSascha Wildner 
30055db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
30065db2f26eSSascha Wildner 
30075db2f26eSSascha Wildner     EVENTHANDLER_INVOKE(acpi_wakeup_event, sc->acpi_power_button_sx);
30085db2f26eSSascha Wildner 
30095db2f26eSSascha Wildner     return_VALUE (ACPI_INTERRUPT_HANDLED);
30105db2f26eSSascha Wildner }
30115db2f26eSSascha Wildner 
30125db2f26eSSascha Wildner UINT32
acpi_event_sleep_button_sleep(void * context)30135db2f26eSSascha Wildner acpi_event_sleep_button_sleep(void *context)
30145db2f26eSSascha Wildner {
30155db2f26eSSascha Wildner     struct acpi_softc	*sc = (struct acpi_softc *)context;
30165db2f26eSSascha Wildner 
30175db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
30185db2f26eSSascha Wildner 
30195db2f26eSSascha Wildner     EVENTHANDLER_INVOKE(acpi_sleep_event, sc->acpi_sleep_button_sx);
30205db2f26eSSascha Wildner 
30215db2f26eSSascha Wildner     return_VALUE (ACPI_INTERRUPT_HANDLED);
30225db2f26eSSascha Wildner }
30235db2f26eSSascha Wildner 
30245db2f26eSSascha Wildner UINT32
acpi_event_sleep_button_wake(void * context)30255db2f26eSSascha Wildner acpi_event_sleep_button_wake(void *context)
30265db2f26eSSascha Wildner {
30275db2f26eSSascha Wildner     struct acpi_softc	*sc = (struct acpi_softc *)context;
30285db2f26eSSascha Wildner 
30295db2f26eSSascha Wildner     ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__);
30305db2f26eSSascha Wildner 
30315db2f26eSSascha Wildner     EVENTHANDLER_INVOKE(acpi_wakeup_event, sc->acpi_sleep_button_sx);
30325db2f26eSSascha Wildner 
30335db2f26eSSascha Wildner     return_VALUE (ACPI_INTERRUPT_HANDLED);
30345db2f26eSSascha Wildner }
30355db2f26eSSascha Wildner 
30365db2f26eSSascha Wildner /*
30375db2f26eSSascha Wildner  * XXX This static buffer is suboptimal.  There is no locking so only
30385db2f26eSSascha Wildner  * use this for single-threaded callers.
30395db2f26eSSascha Wildner  */
30405db2f26eSSascha Wildner char *
acpi_name(ACPI_HANDLE handle)30415db2f26eSSascha Wildner acpi_name(ACPI_HANDLE handle)
30425db2f26eSSascha Wildner {
30435db2f26eSSascha Wildner     ACPI_BUFFER buf;
30445db2f26eSSascha Wildner     static char data[256];
30455db2f26eSSascha Wildner 
30465db2f26eSSascha Wildner     buf.Length = sizeof(data);
30475db2f26eSSascha Wildner     buf.Pointer = data;
30485db2f26eSSascha Wildner 
30495db2f26eSSascha Wildner     if (handle && ACPI_SUCCESS(AcpiGetName(handle, ACPI_FULL_PATHNAME, &buf)))
30505db2f26eSSascha Wildner 	return (data);
30515db2f26eSSascha Wildner     return ("(unknown)");
30525db2f26eSSascha Wildner }
30535db2f26eSSascha Wildner 
30545db2f26eSSascha Wildner /*
30555db2f26eSSascha Wildner  * Debugging/bug-avoidance.  Avoid trying to fetch info on various
30565db2f26eSSascha Wildner  * parts of the namespace.
30575db2f26eSSascha Wildner  */
30585db2f26eSSascha Wildner int
acpi_avoid(ACPI_HANDLE handle)30595db2f26eSSascha Wildner acpi_avoid(ACPI_HANDLE handle)
30605db2f26eSSascha Wildner {
30615db2f26eSSascha Wildner     char	*cp, *env, *np;
30625db2f26eSSascha Wildner     int		len;
30635db2f26eSSascha Wildner 
30645db2f26eSSascha Wildner     np = acpi_name(handle);
30655db2f26eSSascha Wildner     if (*np == '\\')
30665db2f26eSSascha Wildner 	np++;
30675db2f26eSSascha Wildner     if ((env = kgetenv("debug.acpi.avoid")) == NULL)
30685db2f26eSSascha Wildner 	return (0);
30695db2f26eSSascha Wildner 
30705db2f26eSSascha Wildner     /* Scan the avoid list checking for a match */
30715db2f26eSSascha Wildner     cp = env;
30725db2f26eSSascha Wildner     for (;;) {
30735db2f26eSSascha Wildner 	while (*cp != 0 && isspace(*cp))
30745db2f26eSSascha Wildner 	    cp++;
30755db2f26eSSascha Wildner 	if (*cp == 0)
30765db2f26eSSascha Wildner 	    break;
30775db2f26eSSascha Wildner 	len = 0;
30785db2f26eSSascha Wildner 	while (cp[len] != 0 && !isspace(cp[len]))
30795db2f26eSSascha Wildner 	    len++;
30805db2f26eSSascha Wildner 	if (!strncmp(cp, np, len)) {
30815db2f26eSSascha Wildner 	    kfreeenv(env);
30825db2f26eSSascha Wildner 	    return(1);
30835db2f26eSSascha Wildner 	}
30845db2f26eSSascha Wildner 	cp += len;
30855db2f26eSSascha Wildner     }
30865db2f26eSSascha Wildner     kfreeenv(env);
30875db2f26eSSascha Wildner 
30885db2f26eSSascha Wildner     return (0);
30895db2f26eSSascha Wildner }
30905db2f26eSSascha Wildner 
30915db2f26eSSascha Wildner /*
30925db2f26eSSascha Wildner  * Debugging/bug-avoidance.  Disable ACPI subsystem components.
30935db2f26eSSascha Wildner  */
30945db2f26eSSascha Wildner int
acpi_disabled(char * subsys)30955db2f26eSSascha Wildner acpi_disabled(char *subsys)
30965db2f26eSSascha Wildner {
30975db2f26eSSascha Wildner     char	*cp, *env;
30985db2f26eSSascha Wildner     int		len;
30995db2f26eSSascha Wildner 
31005db2f26eSSascha Wildner     if ((env = kgetenv("debug.acpi.disabled")) == NULL)
31015db2f26eSSascha Wildner 	return (0);
31025db2f26eSSascha Wildner     if (strcmp(env, "all") == 0) {
31035db2f26eSSascha Wildner 	kfreeenv(env);
31045db2f26eSSascha Wildner 	return (1);
31055db2f26eSSascha Wildner     }
31065db2f26eSSascha Wildner 
31075db2f26eSSascha Wildner     /* Scan the disable list, checking for a match. */
31085db2f26eSSascha Wildner     cp = env;
31095db2f26eSSascha Wildner     for (;;) {
31105db2f26eSSascha Wildner 	while (*cp != '\0' && isspace(*cp))
31115db2f26eSSascha Wildner 	    cp++;
31125db2f26eSSascha Wildner 	if (*cp == '\0')
31135db2f26eSSascha Wildner 	    break;
31145db2f26eSSascha Wildner 	len = 0;
31155db2f26eSSascha Wildner 	while (cp[len] != '\0' && !isspace(cp[len]))
31165db2f26eSSascha Wildner 	    len++;
31175db2f26eSSascha Wildner 	if (strncmp(cp, subsys, len) == 0) {
31185db2f26eSSascha Wildner 	    kfreeenv(env);
31195db2f26eSSascha Wildner 	    return (1);
31205db2f26eSSascha Wildner 	}
31215db2f26eSSascha Wildner 	cp += len;
31225db2f26eSSascha Wildner     }
31235db2f26eSSascha Wildner     kfreeenv(env);
31245db2f26eSSascha Wildner 
31255db2f26eSSascha Wildner     return (0);
31265db2f26eSSascha Wildner }
31275db2f26eSSascha Wildner 
31285db2f26eSSascha Wildner /*
31295db2f26eSSascha Wildner  * Debugging/bug-avoidance.  Enable ACPI subsystem components.  Most
31305db2f26eSSascha Wildner  * components are enabled by default.  The ones that are not have to be
31315db2f26eSSascha Wildner  * enabled via debug.acpi.enabled.
31325db2f26eSSascha Wildner  */
31335db2f26eSSascha Wildner int
acpi_enabled(char * subsys)31345db2f26eSSascha Wildner acpi_enabled(char *subsys)
31355db2f26eSSascha Wildner {
31365db2f26eSSascha Wildner     char        *cp, *env;
31375db2f26eSSascha Wildner     int         len;
31385db2f26eSSascha Wildner 
31395db2f26eSSascha Wildner     if ((env = kgetenv("debug.acpi.enabled")) == NULL)
31405db2f26eSSascha Wildner         return (0);
31415db2f26eSSascha Wildner     if (strcmp(env, "all") == 0) {
31425db2f26eSSascha Wildner         kfreeenv(env);
31435db2f26eSSascha Wildner         return (1);
31445db2f26eSSascha Wildner     }
31455db2f26eSSascha Wildner 
31465db2f26eSSascha Wildner     /* Scan the enable list, checking for a match. */
31475db2f26eSSascha Wildner     cp = env;
31485db2f26eSSascha Wildner     for (;;) {
31495db2f26eSSascha Wildner         while (*cp != '\0' && isspace(*cp))
31505db2f26eSSascha Wildner             cp++;
31515db2f26eSSascha Wildner         if (*cp == '\0')
31525db2f26eSSascha Wildner             break;
31535db2f26eSSascha Wildner         len = 0;
31545db2f26eSSascha Wildner         while (cp[len] != '\0' && !isspace(cp[len]))
31555db2f26eSSascha Wildner             len++;
31565db2f26eSSascha Wildner         if (strncmp(cp, subsys, len) == 0) {
31575db2f26eSSascha Wildner             kfreeenv(env);
31585db2f26eSSascha Wildner             return (1);
31595db2f26eSSascha Wildner         }
31605db2f26eSSascha Wildner         cp += len;
31615db2f26eSSascha Wildner     }
31625db2f26eSSascha Wildner     kfreeenv(env);
31635db2f26eSSascha Wildner 
31645db2f26eSSascha Wildner     return (0);
31655db2f26eSSascha Wildner }
31665db2f26eSSascha Wildner 
31675db2f26eSSascha Wildner /*
31685db2f26eSSascha Wildner  * Control interface.
31695db2f26eSSascha Wildner  *
31705db2f26eSSascha Wildner  * We multiplex ioctls for all participating ACPI devices here.  Individual
31715db2f26eSSascha Wildner  * drivers wanting to be accessible via /dev/acpi should use the
31725db2f26eSSascha Wildner  * register/deregister interface to make their handlers visible.
31735db2f26eSSascha Wildner  */
31745db2f26eSSascha Wildner struct acpi_ioctl_hook
31755db2f26eSSascha Wildner {
31765db2f26eSSascha Wildner     TAILQ_ENTRY(acpi_ioctl_hook) link;
31775db2f26eSSascha Wildner     u_long			 cmd;
31785db2f26eSSascha Wildner     acpi_ioctl_fn		 fn;
31795db2f26eSSascha Wildner     void			 *arg;
31805db2f26eSSascha Wildner };
31815db2f26eSSascha Wildner 
31825db2f26eSSascha Wildner static TAILQ_HEAD(,acpi_ioctl_hook)	acpi_ioctl_hooks;
31835db2f26eSSascha Wildner static int				acpi_ioctl_hooks_initted;
31845db2f26eSSascha Wildner 
31855db2f26eSSascha Wildner int
acpi_register_ioctl(u_long cmd,acpi_ioctl_fn fn,void * arg)31865db2f26eSSascha Wildner acpi_register_ioctl(u_long cmd, acpi_ioctl_fn fn, void *arg)
31875db2f26eSSascha Wildner {
31885db2f26eSSascha Wildner     struct acpi_ioctl_hook	*hp;
31895db2f26eSSascha Wildner 
31905db2f26eSSascha Wildner     if ((hp = kmalloc(sizeof(*hp), M_ACPIDEV, M_NOWAIT)) == NULL)
31915db2f26eSSascha Wildner 	return (ENOMEM);
31925db2f26eSSascha Wildner     hp->cmd = cmd;
31935db2f26eSSascha Wildner     hp->fn = fn;
31945db2f26eSSascha Wildner     hp->arg = arg;
31955db2f26eSSascha Wildner 
31965db2f26eSSascha Wildner     ACPI_LOCK(acpi);
31975db2f26eSSascha Wildner     if (acpi_ioctl_hooks_initted == 0) {
31985db2f26eSSascha Wildner 	TAILQ_INIT(&acpi_ioctl_hooks);
31995db2f26eSSascha Wildner 	acpi_ioctl_hooks_initted = 1;
32005db2f26eSSascha Wildner     }
32015db2f26eSSascha Wildner     TAILQ_INSERT_TAIL(&acpi_ioctl_hooks, hp, link);
32025db2f26eSSascha Wildner     ACPI_UNLOCK(acpi);
32035db2f26eSSascha Wildner 
32045db2f26eSSascha Wildner     return (0);
32055db2f26eSSascha Wildner }
32065db2f26eSSascha Wildner 
32075db2f26eSSascha Wildner void
acpi_deregister_ioctl(u_long cmd,acpi_ioctl_fn fn)32085db2f26eSSascha Wildner acpi_deregister_ioctl(u_long cmd, acpi_ioctl_fn fn)
32095db2f26eSSascha Wildner {
32105db2f26eSSascha Wildner     struct acpi_ioctl_hook	*hp;
32115db2f26eSSascha Wildner 
32125db2f26eSSascha Wildner     ACPI_LOCK(acpi);
32135db2f26eSSascha Wildner     TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link)
32145db2f26eSSascha Wildner 	if (hp->cmd == cmd && hp->fn == fn)
32155db2f26eSSascha Wildner 	    break;
32165db2f26eSSascha Wildner 
32175db2f26eSSascha Wildner     if (hp != NULL) {
32185db2f26eSSascha Wildner 	TAILQ_REMOVE(&acpi_ioctl_hooks, hp, link);
32195db2f26eSSascha Wildner 	kfree(hp, M_ACPIDEV);
32205db2f26eSSascha Wildner     }
32215db2f26eSSascha Wildner     ACPI_UNLOCK(acpi);
32225db2f26eSSascha Wildner }
32235db2f26eSSascha Wildner 
32245db2f26eSSascha Wildner static int
acpiopen(struct dev_open_args * ap)32255db2f26eSSascha Wildner acpiopen(struct dev_open_args *ap)
32265db2f26eSSascha Wildner {
32275db2f26eSSascha Wildner     return (0);
32285db2f26eSSascha Wildner }
32295db2f26eSSascha Wildner 
32305db2f26eSSascha Wildner static int
acpiclose(struct dev_close_args * ap)32315db2f26eSSascha Wildner acpiclose(struct dev_close_args *ap)
32325db2f26eSSascha Wildner {
32335db2f26eSSascha Wildner     return (0);
32345db2f26eSSascha Wildner }
32355db2f26eSSascha Wildner 
3236529b0458SSascha Wildner static void
acpi_free_object_list(ACPI_OBJECT_LIST * list)3237529b0458SSascha Wildner acpi_free_object_list(ACPI_OBJECT_LIST *list)
3238529b0458SSascha Wildner {
3239529b0458SSascha Wildner     for (int i = 0; i < list->Count; i++) {
3240529b0458SSascha Wildner 	switch (list->Pointer[i].Type) {
3241529b0458SSascha Wildner 	case ACPI_TYPE_STRING:
3242529b0458SSascha Wildner 	    AcpiOsFree(list->Pointer[i].String.Pointer);
3243529b0458SSascha Wildner 	    break;
3244529b0458SSascha Wildner 	case ACPI_TYPE_BUFFER:
3245529b0458SSascha Wildner 	    AcpiOsFree(list->Pointer[i].Buffer.Pointer);
3246529b0458SSascha Wildner 	    break;
3247529b0458SSascha Wildner 	default:
3248529b0458SSascha Wildner 	    break;
3249529b0458SSascha Wildner 	}
3250529b0458SSascha Wildner     }
3251529b0458SSascha Wildner     AcpiOsFree(list);
3252529b0458SSascha Wildner }
3253529b0458SSascha Wildner 
3254529b0458SSascha Wildner static ACPI_OBJECT_LIST *
acpi_copyin_object_list(ACPI_OBJECT_LIST * src)3255529b0458SSascha Wildner acpi_copyin_object_list(ACPI_OBJECT_LIST *src)
3256529b0458SSascha Wildner {
3257529b0458SSascha Wildner     ACPI_OBJECT_LIST	*dest;
3258529b0458SSascha Wildner     BOOLEAN		failed;
3259529b0458SSascha Wildner 
3260529b0458SSascha Wildner     if (src->Count > 7)
3261529b0458SSascha Wildner 	return NULL;
3262529b0458SSascha Wildner 
3263529b0458SSascha Wildner     dest = AcpiOsAllocate(sizeof(ACPI_OBJECT_LIST) + sizeof(ACPI_OBJECT) * src->Count);
3264529b0458SSascha Wildner     if (!dest)
3265529b0458SSascha Wildner 	return NULL;
3266529b0458SSascha Wildner 
3267529b0458SSascha Wildner     dest->Count = src->Count;
3268529b0458SSascha Wildner     dest->Pointer = (ACPI_OBJECT *)(dest + 1);
3269529b0458SSascha Wildner     if (copyin(src->Pointer, dest->Pointer, sizeof(ACPI_OBJECT) * dest->Count)) {
3270529b0458SSascha Wildner 	AcpiOsFree(dest);
3271529b0458SSascha Wildner 	return NULL;
3272529b0458SSascha Wildner     }
3273529b0458SSascha Wildner 
3274529b0458SSascha Wildner     failed = FALSE;
3275529b0458SSascha Wildner 
3276529b0458SSascha Wildner     for (int i = 0; i < dest->Count; i++) {
3277529b0458SSascha Wildner 	switch (dest->Pointer[i].Type) {
3278529b0458SSascha Wildner 	case ACPI_TYPE_INTEGER:
3279529b0458SSascha Wildner 	    break;
3280529b0458SSascha Wildner 	case ACPI_TYPE_STRING: {
3281529b0458SSascha Wildner 	    void *v = AcpiOsAllocate(dest->Pointer[i].String.Length);
3282529b0458SSascha Wildner 	    if (!v || copyin(dest->Pointer[i].String.Pointer, v, dest->Pointer[i].String.Length))
3283529b0458SSascha Wildner 		failed = TRUE;
3284529b0458SSascha Wildner 	    dest->Pointer[i].String.Pointer = v;
3285529b0458SSascha Wildner 	    break;
3286529b0458SSascha Wildner 	}
3287529b0458SSascha Wildner 	case ACPI_TYPE_BUFFER: {
3288529b0458SSascha Wildner 	    void *v = AcpiOsAllocate(dest->Pointer[i].Buffer.Length);
3289529b0458SSascha Wildner 	    if (!v || copyin(dest->Pointer[i].Buffer.Pointer, v, dest->Pointer[i].Buffer.Length))
3290529b0458SSascha Wildner 		failed = TRUE;
3291529b0458SSascha Wildner 	    dest->Pointer[i].String.Pointer = v;
3292529b0458SSascha Wildner 	    break;
3293529b0458SSascha Wildner 	}
3294529b0458SSascha Wildner 	default:
3295529b0458SSascha Wildner 	    failed = TRUE;
3296529b0458SSascha Wildner 	    break;
3297529b0458SSascha Wildner 	}
3298529b0458SSascha Wildner     }
3299529b0458SSascha Wildner 
3300529b0458SSascha Wildner     if (failed) {
3301529b0458SSascha Wildner 	acpi_free_object_list(dest);
3302529b0458SSascha Wildner 	dest = NULL;
3303529b0458SSascha Wildner     }
3304529b0458SSascha Wildner 
3305529b0458SSascha Wildner     return dest;
3306529b0458SSascha Wildner }
3307529b0458SSascha Wildner 
3308529b0458SSascha Wildner static int
acpi_call_ioctl(caddr_t addr)3309529b0458SSascha Wildner acpi_call_ioctl(caddr_t addr)
3310529b0458SSascha Wildner {
3311529b0458SSascha Wildner     struct acpi_mcall_ioctl_arg *params;
3312529b0458SSascha Wildner     ACPI_OBJECT_LIST	*args;
3313529b0458SSascha Wildner     ACPI_BUFFER		result;
3314529b0458SSascha Wildner     char		path[256];
3315529b0458SSascha Wildner 
3316529b0458SSascha Wildner     result.Length = ACPI_ALLOCATE_BUFFER;
3317529b0458SSascha Wildner     result.Pointer = NULL;
3318529b0458SSascha Wildner 
3319529b0458SSascha Wildner     params = (struct acpi_mcall_ioctl_arg *)addr;
3320529b0458SSascha Wildner     args = acpi_copyin_object_list(&params->args);
3321529b0458SSascha Wildner     if (!args)
3322529b0458SSascha Wildner 	return EINVAL;
3323529b0458SSascha Wildner     if (copyinstr(params->path, path, sizeof(path), NULL))
3324529b0458SSascha Wildner 	return EINVAL;
3325529b0458SSascha Wildner     params->retval = AcpiEvaluateObject(NULL, path, args, &result);
3326529b0458SSascha Wildner     if (ACPI_SUCCESS(params->retval)) {
3327529b0458SSascha Wildner 	if (result.Pointer != NULL) {
3328529b0458SSascha Wildner 	    if (params->result.Pointer != NULL) {
3329529b0458SSascha Wildner 		params->result.Length = min(params->result.Length,
3330529b0458SSascha Wildner 		    result.Length);
3331529b0458SSascha Wildner 		if (result.Length >= sizeof(ACPI_OBJECT)) {
3332529b0458SSascha Wildner 		    acpi_call_fixup_pointers((ACPI_OBJECT *)result.Pointer,
3333529b0458SSascha Wildner 			params->result.Pointer);
3334529b0458SSascha Wildner 		}
3335529b0458SSascha Wildner 		copyout(result.Pointer, params->result.Pointer,
3336529b0458SSascha Wildner 		    params->result.Length);
3337529b0458SSascha Wildner 		params->reslen = result.Length;
3338529b0458SSascha Wildner 	    }
3339529b0458SSascha Wildner 	    AcpiOsFree(result.Pointer);
3340529b0458SSascha Wildner 	}
3341529b0458SSascha Wildner     }
3342529b0458SSascha Wildner     acpi_free_object_list(args);
3343529b0458SSascha Wildner 
3344529b0458SSascha Wildner     return (0);
3345529b0458SSascha Wildner }
3346529b0458SSascha Wildner 
3347529b0458SSascha Wildner void
acpi_call_fixup_pointers(ACPI_OBJECT * p,UINT8 * dest)3348529b0458SSascha Wildner acpi_call_fixup_pointers(ACPI_OBJECT *p, UINT8 *dest)
3349529b0458SSascha Wildner {
3350529b0458SSascha Wildner     switch (p->Type) {
3351529b0458SSascha Wildner     case ACPI_TYPE_STRING:
3352529b0458SSascha Wildner 	p->String.Pointer += dest - (UINT8 *)p;
3353529b0458SSascha Wildner 	break;
3354529b0458SSascha Wildner     case ACPI_TYPE_BUFFER:
3355529b0458SSascha Wildner 	p->Buffer.Pointer += dest - (UINT8 *)p;
3356529b0458SSascha Wildner 	break;
3357529b0458SSascha Wildner     }
3358529b0458SSascha Wildner }
3359529b0458SSascha Wildner 
33605db2f26eSSascha Wildner static int
acpiioctl(struct dev_ioctl_args * ap)33615db2f26eSSascha Wildner acpiioctl(struct dev_ioctl_args *ap)
33625db2f26eSSascha Wildner {
33635db2f26eSSascha Wildner     struct acpi_softc		*sc;
33645db2f26eSSascha Wildner     struct acpi_ioctl_hook	*hp;
33655db2f26eSSascha Wildner     int				error, state;
33665db2f26eSSascha Wildner 
33675db2f26eSSascha Wildner     error = 0;
33685db2f26eSSascha Wildner     hp = NULL;
33695db2f26eSSascha Wildner     sc = ap->a_head.a_dev->si_drv1;
33705db2f26eSSascha Wildner 
33715db2f26eSSascha Wildner     /*
33725db2f26eSSascha Wildner      * Scan the list of registered ioctls, looking for handlers.
33735db2f26eSSascha Wildner      */
3374a639f788SMatthew Dillon     lwkt_gettoken(&acpi_token);
33755db2f26eSSascha Wildner     ACPI_LOCK(acpi);
33767252c37cSMatthew Dillon     if (acpi_ioctl_hooks_initted) {
33775db2f26eSSascha Wildner 	TAILQ_FOREACH(hp, &acpi_ioctl_hooks, link) {
33785db2f26eSSascha Wildner 	    if (hp->cmd == ap->a_cmd)
33795db2f26eSSascha Wildner 		break;
33805db2f26eSSascha Wildner 	}
33817252c37cSMatthew Dillon     }
33825db2f26eSSascha Wildner     ACPI_UNLOCK(acpi);
3383a639f788SMatthew Dillon     if (hp) {
3384a639f788SMatthew Dillon 	error = hp->fn(ap->a_cmd, ap->a_data, hp->arg);
3385a639f788SMatthew Dillon 	lwkt_reltoken(&acpi_token);
3386a639f788SMatthew Dillon 	return error;
3387a639f788SMatthew Dillon     }
33885db2f26eSSascha Wildner 
33895db2f26eSSascha Wildner     /*
33905db2f26eSSascha Wildner      * Core ioctls are not permitted for non-writable user.
33915db2f26eSSascha Wildner      * Currently, other ioctls just fetch information.
33925db2f26eSSascha Wildner      * Not changing system behavior.
33935db2f26eSSascha Wildner      */
3394a639f788SMatthew Dillon     if ((ap->a_fflag & FWRITE) == 0) {
3395a639f788SMatthew Dillon 	lwkt_reltoken(&acpi_token);
33965db2f26eSSascha Wildner 	return (EPERM);
3397a639f788SMatthew Dillon     }
33985db2f26eSSascha Wildner 
33995db2f26eSSascha Wildner     /* Core system ioctls. */
34005db2f26eSSascha Wildner     switch (ap->a_cmd) {
34015db2f26eSSascha Wildner     case ACPIIO_REQSLPSTATE:
34025db2f26eSSascha Wildner 	state = *(int *)ap->a_data;
34035db2f26eSSascha Wildner 	if (state != ACPI_STATE_S5)
34045db2f26eSSascha Wildner 	    error = acpi_ReqSleepState(sc, state);
34055db2f26eSSascha Wildner 	else {
3406e11869f0SSascha Wildner 	    device_printf(sc->acpi_dev,
3407e11869f0SSascha Wildner 		"power off via acpi ioctl not supported\n");
34085db2f26eSSascha Wildner 	    error = ENXIO;
34095db2f26eSSascha Wildner 	}
34105db2f26eSSascha Wildner 	break;
34115db2f26eSSascha Wildner     case ACPIIO_ACKSLPSTATE:
34125db2f26eSSascha Wildner 	error = EOPNOTSUPP;
34135db2f26eSSascha Wildner #if 0 /* notyet */
34145db2f26eSSascha Wildner 	error = *(int *)ap->a_data;
34155db2f26eSSascha Wildner 	error = acpi_AckSleepState(sc->acpi_clone, error);
34165db2f26eSSascha Wildner #endif
34175db2f26eSSascha Wildner 	break;
34185db2f26eSSascha Wildner     case ACPIIO_SETSLPSTATE:	/* DEPRECATED */
34195db2f26eSSascha Wildner 	error = EINVAL;
34205db2f26eSSascha Wildner 	state = *(int *)ap->a_data;
34215db2f26eSSascha Wildner 	if (state >= ACPI_STATE_S0 && state <= ACPI_S_STATES_MAX)
34225db2f26eSSascha Wildner 	    if (ACPI_SUCCESS(acpi_SetSleepState(sc, state)))
34235db2f26eSSascha Wildner 		error = 0;
34245db2f26eSSascha Wildner 	break;
3425279dd846SSascha Wildner     case ACPIIO_DO_MCALL:
3426279dd846SSascha Wildner 	if (acpi_allow_mcall == 1) {
3427529b0458SSascha Wildner 	    error = acpi_call_ioctl(ap->a_data);
3428279dd846SSascha Wildner 	} else {
3429279dd846SSascha Wildner 	    device_printf(sc->acpi_dev,
3430*0994aedbSSascha Wildner 		"debug.acpi.allow_method_calls tunable must be set\n");
3431279dd846SSascha Wildner 	    error = ENXIO;
3432279dd846SSascha Wildner 	}
3433279dd846SSascha Wildner 	break;
34345db2f26eSSascha Wildner     default:
34355db2f26eSSascha Wildner 	error = ENXIO;
34365db2f26eSSascha Wildner 	break;
34375db2f26eSSascha Wildner     }
3438a639f788SMatthew Dillon     lwkt_reltoken(&acpi_token);
3439a639f788SMatthew Dillon 
34405db2f26eSSascha Wildner     return (error);
34415db2f26eSSascha Wildner }
34425db2f26eSSascha Wildner 
34435db2f26eSSascha Wildner static int
acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS)34445db2f26eSSascha Wildner acpi_supported_sleep_state_sysctl(SYSCTL_HANDLER_ARGS)
34455db2f26eSSascha Wildner {
34465db2f26eSSascha Wildner     int error;
34475db2f26eSSascha Wildner     struct sbuf sb;
34485db2f26eSSascha Wildner     UINT8 state, TypeA, TypeB;
34495db2f26eSSascha Wildner 
34505db2f26eSSascha Wildner     sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND);
34515db2f26eSSascha Wildner     for (state = ACPI_STATE_S1; state < ACPI_S_STATES_MAX + 1; state++)
34525db2f26eSSascha Wildner 	if (ACPI_SUCCESS(AcpiGetSleepTypeData(state, &TypeA, &TypeB)))
34535db2f26eSSascha Wildner 	    sbuf_printf(&sb, "S%d ", state);
34545db2f26eSSascha Wildner     sbuf_trim(&sb);
34555db2f26eSSascha Wildner     sbuf_finish(&sb);
34565db2f26eSSascha Wildner     error = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
34575db2f26eSSascha Wildner     sbuf_delete(&sb);
34585db2f26eSSascha Wildner     return (error);
34595db2f26eSSascha Wildner }
34605db2f26eSSascha Wildner 
34615db2f26eSSascha Wildner static int
acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS)34625db2f26eSSascha Wildner acpi_sleep_state_sysctl(SYSCTL_HANDLER_ARGS)
34635db2f26eSSascha Wildner {
34645db2f26eSSascha Wildner     char sleep_state[10];
34655db2f26eSSascha Wildner     int error;
34665db2f26eSSascha Wildner     u_int new_state, old_state;
34675db2f26eSSascha Wildner 
34685db2f26eSSascha Wildner     old_state = *(u_int *)oidp->oid_arg1;
34695db2f26eSSascha Wildner     if (old_state > ACPI_S_STATES_MAX + 1)
34705db2f26eSSascha Wildner 	strlcpy(sleep_state, "unknown", sizeof(sleep_state));
34715db2f26eSSascha Wildner     else
34725db2f26eSSascha Wildner 	strlcpy(sleep_state, sleep_state_names[old_state], sizeof(sleep_state));
34735db2f26eSSascha Wildner     error = sysctl_handle_string(oidp, sleep_state, sizeof(sleep_state), req);
34745db2f26eSSascha Wildner     if (error == 0 && req->newptr != NULL) {
34755db2f26eSSascha Wildner 	new_state = ACPI_STATE_S0;
34765db2f26eSSascha Wildner 	for (; new_state <= ACPI_S_STATES_MAX + 1; new_state++)
34775db2f26eSSascha Wildner 	    if (strcmp(sleep_state, sleep_state_names[new_state]) == 0)
34785db2f26eSSascha Wildner 		break;
34795db2f26eSSascha Wildner 	if (new_state <= ACPI_S_STATES_MAX + 1) {
34805db2f26eSSascha Wildner 	    if (new_state != old_state)
34815db2f26eSSascha Wildner 		*(u_int *)oidp->oid_arg1 = new_state;
34825db2f26eSSascha Wildner 	} else
34835db2f26eSSascha Wildner 	    error = EINVAL;
34845db2f26eSSascha Wildner     }
34855db2f26eSSascha Wildner 
34865db2f26eSSascha Wildner     return (error);
34875db2f26eSSascha Wildner }
34885db2f26eSSascha Wildner 
34895db2f26eSSascha Wildner /* Inform devctl(4) when we receive a Notify. */
34905db2f26eSSascha Wildner void
acpi_UserNotify(const char * subsystem,ACPI_HANDLE h,uint8_t notify)34915db2f26eSSascha Wildner acpi_UserNotify(const char *subsystem, ACPI_HANDLE h, uint8_t notify)
34925db2f26eSSascha Wildner {
34935db2f26eSSascha Wildner     char		notify_buf[16];
34945db2f26eSSascha Wildner     ACPI_BUFFER		handle_buf;
34955db2f26eSSascha Wildner     ACPI_STATUS		status;
34965db2f26eSSascha Wildner 
34975db2f26eSSascha Wildner     if (subsystem == NULL)
34985db2f26eSSascha Wildner 	return;
34995db2f26eSSascha Wildner 
35005db2f26eSSascha Wildner     handle_buf.Pointer = NULL;
35015db2f26eSSascha Wildner     handle_buf.Length = ACPI_ALLOCATE_BUFFER;
3502267c04fdSSascha Wildner     status = AcpiNsHandleToPathname(h, &handle_buf, FALSE);
35035db2f26eSSascha Wildner     if (ACPI_FAILURE(status))
35045db2f26eSSascha Wildner 	return;
35055db2f26eSSascha Wildner     ksnprintf(notify_buf, sizeof(notify_buf), "notify=0x%02x", notify);
35065db2f26eSSascha Wildner     devctl_notify("ACPI", subsystem, handle_buf.Pointer, notify_buf);
35075db2f26eSSascha Wildner     AcpiOsFree(handle_buf.Pointer);
35085db2f26eSSascha Wildner }
35095db2f26eSSascha Wildner 
35105db2f26eSSascha Wildner #ifdef ACPI_DEBUG
35115db2f26eSSascha Wildner /*
35125db2f26eSSascha Wildner  * Support for parsing debug options from the kernel environment.
35135db2f26eSSascha Wildner  *
35145db2f26eSSascha Wildner  * Bits may be set in the AcpiDbgLayer and AcpiDbgLevel debug registers
35155db2f26eSSascha Wildner  * by specifying the names of the bits in the debug.acpi.layer and
35165db2f26eSSascha Wildner  * debug.acpi.level environment variables.  Bits may be unset by
35175db2f26eSSascha Wildner  * prefixing the bit name with !.
35185db2f26eSSascha Wildner  */
35195db2f26eSSascha Wildner struct debugtag
35205db2f26eSSascha Wildner {
35215db2f26eSSascha Wildner     char	*name;
35225db2f26eSSascha Wildner     UINT32	value;
35235db2f26eSSascha Wildner };
35245db2f26eSSascha Wildner 
35255db2f26eSSascha Wildner static struct debugtag	dbg_layer[] = {
35265db2f26eSSascha Wildner     {"ACPI_UTILITIES",		ACPI_UTILITIES},
35275db2f26eSSascha Wildner     {"ACPI_HARDWARE",		ACPI_HARDWARE},
35285db2f26eSSascha Wildner     {"ACPI_EVENTS",		ACPI_EVENTS},
35295db2f26eSSascha Wildner     {"ACPI_TABLES",		ACPI_TABLES},
35305db2f26eSSascha Wildner     {"ACPI_NAMESPACE",		ACPI_NAMESPACE},
35315db2f26eSSascha Wildner     {"ACPI_PARSER",		ACPI_PARSER},
35325db2f26eSSascha Wildner     {"ACPI_DISPATCHER",		ACPI_DISPATCHER},
35335db2f26eSSascha Wildner     {"ACPI_EXECUTER",		ACPI_EXECUTER},
35345db2f26eSSascha Wildner     {"ACPI_RESOURCES",		ACPI_RESOURCES},
35355db2f26eSSascha Wildner     {"ACPI_CA_DEBUGGER",	ACPI_CA_DEBUGGER},
35365db2f26eSSascha Wildner     {"ACPI_OS_SERVICES",	ACPI_OS_SERVICES},
35375db2f26eSSascha Wildner     {"ACPI_CA_DISASSEMBLER",	ACPI_CA_DISASSEMBLER},
35385db2f26eSSascha Wildner     {"ACPI_ALL_COMPONENTS",	ACPI_ALL_COMPONENTS},
35395db2f26eSSascha Wildner 
35405db2f26eSSascha Wildner     {"ACPI_AC_ADAPTER",		ACPI_AC_ADAPTER},
35415db2f26eSSascha Wildner     {"ACPI_BATTERY",		ACPI_BATTERY},
35425db2f26eSSascha Wildner     {"ACPI_BUS",		ACPI_BUS},
35435db2f26eSSascha Wildner     {"ACPI_BUTTON",		ACPI_BUTTON},
35445db2f26eSSascha Wildner     {"ACPI_EC", 		ACPI_EC},
35455db2f26eSSascha Wildner     {"ACPI_FAN",		ACPI_FAN},
35465db2f26eSSascha Wildner     {"ACPI_POWERRES",		ACPI_POWERRES},
35475db2f26eSSascha Wildner     {"ACPI_PROCESSOR",		ACPI_PROCESSOR},
35485db2f26eSSascha Wildner     {"ACPI_THERMAL",		ACPI_THERMAL},
35495db2f26eSSascha Wildner     {"ACPI_TIMER",		ACPI_TIMER},
35505db2f26eSSascha Wildner     {"ACPI_ALL_DRIVERS",	ACPI_ALL_DRIVERS},
35515db2f26eSSascha Wildner     {NULL, 0}
35525db2f26eSSascha Wildner };
35535db2f26eSSascha Wildner 
35545db2f26eSSascha Wildner static struct debugtag dbg_level[] = {
35555db2f26eSSascha Wildner     {"ACPI_LV_INIT",		ACPI_LV_INIT},
35565db2f26eSSascha Wildner     {"ACPI_LV_DEBUG_OBJECT",	ACPI_LV_DEBUG_OBJECT},
35575db2f26eSSascha Wildner     {"ACPI_LV_INFO",		ACPI_LV_INFO},
35580bcdf371SSascha Wildner     {"ACPI_LV_REPAIR",		ACPI_LV_REPAIR},
35595db2f26eSSascha Wildner     {"ACPI_LV_ALL_EXCEPTIONS",	ACPI_LV_ALL_EXCEPTIONS},
35605db2f26eSSascha Wildner 
35615db2f26eSSascha Wildner     /* Trace verbosity level 1 [Standard Trace Level] */
35625db2f26eSSascha Wildner     {"ACPI_LV_INIT_NAMES",	ACPI_LV_INIT_NAMES},
35635db2f26eSSascha Wildner     {"ACPI_LV_PARSE",		ACPI_LV_PARSE},
35645db2f26eSSascha Wildner     {"ACPI_LV_LOAD",		ACPI_LV_LOAD},
35655db2f26eSSascha Wildner     {"ACPI_LV_DISPATCH",	ACPI_LV_DISPATCH},
35665db2f26eSSascha Wildner     {"ACPI_LV_EXEC",		ACPI_LV_EXEC},
35675db2f26eSSascha Wildner     {"ACPI_LV_NAMES",		ACPI_LV_NAMES},
35685db2f26eSSascha Wildner     {"ACPI_LV_OPREGION",	ACPI_LV_OPREGION},
35695db2f26eSSascha Wildner     {"ACPI_LV_BFIELD",		ACPI_LV_BFIELD},
35705db2f26eSSascha Wildner     {"ACPI_LV_TABLES",		ACPI_LV_TABLES},
35715db2f26eSSascha Wildner     {"ACPI_LV_VALUES",		ACPI_LV_VALUES},
35725db2f26eSSascha Wildner     {"ACPI_LV_OBJECTS",		ACPI_LV_OBJECTS},
35735db2f26eSSascha Wildner     {"ACPI_LV_RESOURCES",	ACPI_LV_RESOURCES},
35745db2f26eSSascha Wildner     {"ACPI_LV_USER_REQUESTS",	ACPI_LV_USER_REQUESTS},
35755db2f26eSSascha Wildner     {"ACPI_LV_PACKAGE",		ACPI_LV_PACKAGE},
3576ef944814SSascha Wildner     {"ACPI_LV_EVALUATION",	ACPI_LV_EVALUATION},
35775db2f26eSSascha Wildner     {"ACPI_LV_VERBOSITY1",	ACPI_LV_VERBOSITY1},
35785db2f26eSSascha Wildner 
35795db2f26eSSascha Wildner     /* Trace verbosity level 2 [Function tracing and memory allocation] */
35805db2f26eSSascha Wildner     {"ACPI_LV_ALLOCATIONS",	ACPI_LV_ALLOCATIONS},
35815db2f26eSSascha Wildner     {"ACPI_LV_FUNCTIONS",	ACPI_LV_FUNCTIONS},
35825db2f26eSSascha Wildner     {"ACPI_LV_OPTIMIZATIONS",	ACPI_LV_OPTIMIZATIONS},
35835db2f26eSSascha Wildner     {"ACPI_LV_VERBOSITY2",	ACPI_LV_VERBOSITY2},
35845db2f26eSSascha Wildner     {"ACPI_LV_ALL",		ACPI_LV_ALL},
35855db2f26eSSascha Wildner 
35865db2f26eSSascha Wildner     /* Trace verbosity level 3 [Threading, I/O, and Interrupts] */
35875db2f26eSSascha Wildner     {"ACPI_LV_MUTEX",		ACPI_LV_MUTEX},
35885db2f26eSSascha Wildner     {"ACPI_LV_THREADS",		ACPI_LV_THREADS},
35895db2f26eSSascha Wildner     {"ACPI_LV_IO",		ACPI_LV_IO},
35905db2f26eSSascha Wildner     {"ACPI_LV_INTERRUPTS",	ACPI_LV_INTERRUPTS},
35915db2f26eSSascha Wildner     {"ACPI_LV_VERBOSITY3",	ACPI_LV_VERBOSITY3},
35925db2f26eSSascha Wildner 
35935db2f26eSSascha Wildner     /* Exceptionally verbose output -- also used in the global "DebugLevel"  */
35945db2f26eSSascha Wildner     {"ACPI_LV_AML_DISASSEMBLE",	ACPI_LV_AML_DISASSEMBLE},
35955db2f26eSSascha Wildner     {"ACPI_LV_VERBOSE_INFO",	ACPI_LV_VERBOSE_INFO},
35965db2f26eSSascha Wildner     {"ACPI_LV_FULL_TABLES",	ACPI_LV_FULL_TABLES},
35975db2f26eSSascha Wildner     {"ACPI_LV_EVENTS",		ACPI_LV_EVENTS},
35985db2f26eSSascha Wildner     {"ACPI_LV_VERBOSE",		ACPI_LV_VERBOSE},
35995db2f26eSSascha Wildner     {NULL, 0}
36005db2f26eSSascha Wildner };
36015db2f26eSSascha Wildner 
36025db2f26eSSascha Wildner static void
acpi_parse_debug(char * cp,struct debugtag * tag,UINT32 * flag)36035db2f26eSSascha Wildner acpi_parse_debug(char *cp, struct debugtag *tag, UINT32 *flag)
36045db2f26eSSascha Wildner {
36055db2f26eSSascha Wildner     char	*ep;
36065db2f26eSSascha Wildner     int		i, l;
36075db2f26eSSascha Wildner     int		set;
36085db2f26eSSascha Wildner 
36095db2f26eSSascha Wildner     while (*cp) {
36105db2f26eSSascha Wildner 	if (isspace(*cp)) {
36115db2f26eSSascha Wildner 	    cp++;
36125db2f26eSSascha Wildner 	    continue;
36135db2f26eSSascha Wildner 	}
36145db2f26eSSascha Wildner 	ep = cp;
36155db2f26eSSascha Wildner 	while (*ep && !isspace(*ep))
36165db2f26eSSascha Wildner 	    ep++;
36175db2f26eSSascha Wildner 	if (*cp == '!') {
36185db2f26eSSascha Wildner 	    set = 0;
36195db2f26eSSascha Wildner 	    cp++;
36205db2f26eSSascha Wildner 	    if (cp == ep)
36215db2f26eSSascha Wildner 		continue;
36225db2f26eSSascha Wildner 	} else {
36235db2f26eSSascha Wildner 	    set = 1;
36245db2f26eSSascha Wildner 	}
36255db2f26eSSascha Wildner 	l = ep - cp;
36265db2f26eSSascha Wildner 	for (i = 0; tag[i].name != NULL; i++) {
36275db2f26eSSascha Wildner 	    if (!strncmp(cp, tag[i].name, l)) {
36285db2f26eSSascha Wildner 		if (set)
36295db2f26eSSascha Wildner 		    *flag |= tag[i].value;
36305db2f26eSSascha Wildner 		else
36315db2f26eSSascha Wildner 		    *flag &= ~tag[i].value;
36325db2f26eSSascha Wildner 	    }
36335db2f26eSSascha Wildner 	}
36345db2f26eSSascha Wildner 	cp = ep;
36355db2f26eSSascha Wildner     }
36365db2f26eSSascha Wildner }
36375db2f26eSSascha Wildner 
36385db2f26eSSascha Wildner static void
acpi_set_debugging(void * junk)36395db2f26eSSascha Wildner acpi_set_debugging(void *junk)
36405db2f26eSSascha Wildner {
36415db2f26eSSascha Wildner     char	*layer, *level;
36425db2f26eSSascha Wildner 
36435db2f26eSSascha Wildner     if (cold) {
36445db2f26eSSascha Wildner 	AcpiDbgLayer = 0;
36455db2f26eSSascha Wildner 	AcpiDbgLevel = 0;
36465db2f26eSSascha Wildner     }
36475db2f26eSSascha Wildner 
36485db2f26eSSascha Wildner     layer = kgetenv("debug.acpi.layer");
36495db2f26eSSascha Wildner     level = kgetenv("debug.acpi.level");
36505db2f26eSSascha Wildner     if (layer == NULL && level == NULL)
36515db2f26eSSascha Wildner 	return;
36525db2f26eSSascha Wildner 
36535db2f26eSSascha Wildner     kprintf("ACPI set debug");
36545db2f26eSSascha Wildner     if (layer != NULL) {
36555db2f26eSSascha Wildner 	if (strcmp("NONE", layer) != 0)
36565db2f26eSSascha Wildner 	    kprintf(" layer '%s'", layer);
36575db2f26eSSascha Wildner 	acpi_parse_debug(layer, &dbg_layer[0], &AcpiDbgLayer);
36585db2f26eSSascha Wildner 	kfreeenv(layer);
36595db2f26eSSascha Wildner     }
36605db2f26eSSascha Wildner     if (level != NULL) {
36615db2f26eSSascha Wildner 	if (strcmp("NONE", level) != 0)
36625db2f26eSSascha Wildner 	    kprintf(" level '%s'", level);
36635db2f26eSSascha Wildner 	acpi_parse_debug(level, &dbg_level[0], &AcpiDbgLevel);
36645db2f26eSSascha Wildner 	kfreeenv(level);
36655db2f26eSSascha Wildner     }
36665db2f26eSSascha Wildner     kprintf("\n");
36675db2f26eSSascha Wildner }
36685db2f26eSSascha Wildner 
36695db2f26eSSascha Wildner SYSINIT(acpi_debugging, SI_BOOT1_TUNABLES, SI_ORDER_ANY, acpi_set_debugging,
36705db2f26eSSascha Wildner 	NULL);
36715db2f26eSSascha Wildner 
36725db2f26eSSascha Wildner static int
acpi_debug_sysctl(SYSCTL_HANDLER_ARGS)36735db2f26eSSascha Wildner acpi_debug_sysctl(SYSCTL_HANDLER_ARGS)
36745db2f26eSSascha Wildner {
36755db2f26eSSascha Wildner     int		 error, *dbg;
36765db2f26eSSascha Wildner     struct	 debugtag *tag;
36775db2f26eSSascha Wildner     struct	 sbuf sb;
36785db2f26eSSascha Wildner 
36795db2f26eSSascha Wildner     if (sbuf_new(&sb, NULL, 128, SBUF_AUTOEXTEND) == NULL)
36805db2f26eSSascha Wildner 	return (ENOMEM);
36815db2f26eSSascha Wildner     if (strcmp(oidp->oid_arg1, "debug.acpi.layer") == 0) {
36825db2f26eSSascha Wildner 	tag = &dbg_layer[0];
36835db2f26eSSascha Wildner 	dbg = &AcpiDbgLayer;
36845db2f26eSSascha Wildner     } else {
36855db2f26eSSascha Wildner 	tag = &dbg_level[0];
36865db2f26eSSascha Wildner 	dbg = &AcpiDbgLevel;
36875db2f26eSSascha Wildner     }
36885db2f26eSSascha Wildner 
36895db2f26eSSascha Wildner     /* Get old values if this is a get request. */
36905db2f26eSSascha Wildner     ACPI_SERIAL_BEGIN(acpi);
36915db2f26eSSascha Wildner     if (*dbg == 0) {
36925db2f26eSSascha Wildner 	sbuf_cpy(&sb, "NONE");
36935db2f26eSSascha Wildner     } else if (req->newptr == NULL) {
36945db2f26eSSascha Wildner 	for (; tag->name != NULL; tag++) {
36955db2f26eSSascha Wildner 	    if ((*dbg & tag->value) == tag->value)
36965db2f26eSSascha Wildner 		sbuf_printf(&sb, "%s ", tag->name);
36975db2f26eSSascha Wildner 	}
36985db2f26eSSascha Wildner     }
36995db2f26eSSascha Wildner     sbuf_trim(&sb);
37005db2f26eSSascha Wildner     sbuf_finish(&sb);
37015db2f26eSSascha Wildner 
37025db2f26eSSascha Wildner     /* Copy out the old values to the user. */
37035db2f26eSSascha Wildner     error = SYSCTL_OUT(req, sbuf_data(&sb), sbuf_len(&sb));
37045db2f26eSSascha Wildner     sbuf_delete(&sb);
37055db2f26eSSascha Wildner 
37065db2f26eSSascha Wildner     /* If the user is setting a string, parse it. */
37075db2f26eSSascha Wildner     if (error == 0 && req->newptr != NULL) {
37085db2f26eSSascha Wildner 	*dbg = 0;
37095db2f26eSSascha Wildner 	ksetenv((char *)oidp->oid_arg1, (char *)req->newptr);
37105db2f26eSSascha Wildner 	acpi_set_debugging(NULL);
37115db2f26eSSascha Wildner     }
37125db2f26eSSascha Wildner     ACPI_SERIAL_END(acpi);
37135db2f26eSSascha Wildner 
37145db2f26eSSascha Wildner     return (error);
37155db2f26eSSascha Wildner }
37165db2f26eSSascha Wildner 
37175db2f26eSSascha Wildner SYSCTL_PROC(_debug_acpi, OID_AUTO, layer, CTLFLAG_RW | CTLTYPE_STRING,
37185db2f26eSSascha Wildner 	    "debug.acpi.layer", 0, acpi_debug_sysctl, "A", "");
37195db2f26eSSascha Wildner SYSCTL_PROC(_debug_acpi, OID_AUTO, level, CTLFLAG_RW | CTLTYPE_STRING,
37205db2f26eSSascha Wildner 	    "debug.acpi.level", 0, acpi_debug_sysctl, "A", "");
37215db2f26eSSascha Wildner #endif /* ACPI_DEBUG */
37225db2f26eSSascha Wildner 
37235db2f26eSSascha Wildner static int
acpi_debug_objects_sysctl(SYSCTL_HANDLER_ARGS)3724586fced2SSascha Wildner acpi_debug_objects_sysctl(SYSCTL_HANDLER_ARGS)
3725586fced2SSascha Wildner {
3726586fced2SSascha Wildner 	int	error;
3727586fced2SSascha Wildner 	int	old;
3728586fced2SSascha Wildner 
3729586fced2SSascha Wildner 	old = acpi_debug_objects;
3730586fced2SSascha Wildner 	error = sysctl_handle_int(oidp, &acpi_debug_objects, 0, req);
3731586fced2SSascha Wildner 	if (error != 0 || req->newptr == NULL)
3732586fced2SSascha Wildner 		return (error);
3733586fced2SSascha Wildner 	if (old == acpi_debug_objects || (old && acpi_debug_objects))
3734586fced2SSascha Wildner 		return (0);
3735586fced2SSascha Wildner 
3736586fced2SSascha Wildner 	ACPI_SERIAL_BEGIN(acpi);
3737586fced2SSascha Wildner 	AcpiGbl_EnableAmlDebugObject = acpi_debug_objects ? TRUE : FALSE;
3738586fced2SSascha Wildner 	ACPI_SERIAL_END(acpi);
3739586fced2SSascha Wildner 
3740586fced2SSascha Wildner 	return (0);
3741586fced2SSascha Wildner }
3742586fced2SSascha Wildner 
3743fa21302bSSascha Wildner 
3744fa21302bSSascha Wildner static int
acpi_parse_interfaces(char * str,struct acpi_interface * iface)3745fa21302bSSascha Wildner acpi_parse_interfaces(char *str, struct acpi_interface *iface)
3746fa21302bSSascha Wildner {
3747fa21302bSSascha Wildner 	char *p;
3748fa21302bSSascha Wildner 	size_t len;
3749fa21302bSSascha Wildner 	int i, j;
3750fa21302bSSascha Wildner 
3751fa21302bSSascha Wildner 	p = str;
3752fa21302bSSascha Wildner 	while (isspace(*p) || *p == ',')
3753fa21302bSSascha Wildner 		p++;
3754fa21302bSSascha Wildner 	len = strlen(p);
3755fa21302bSSascha Wildner 	if (len == 0)
3756fa21302bSSascha Wildner 		return (0);
3757fa21302bSSascha Wildner 	p = kstrdup(p, M_TEMP);
3758fa21302bSSascha Wildner 	for (i = 0; i < len; i++)
3759fa21302bSSascha Wildner 		if (p[i] == ',')
3760fa21302bSSascha Wildner 			p[i] = '\0';
3761fa21302bSSascha Wildner 	i = j = 0;
3762fa21302bSSascha Wildner 	while (i < len)
3763fa21302bSSascha Wildner 		if (isspace(p[i]) || p[i] == '\0')
3764fa21302bSSascha Wildner 			i++;
3765fa21302bSSascha Wildner 		else {
3766fa21302bSSascha Wildner 			i += strlen(p + i) + 1;
3767fa21302bSSascha Wildner 			j++;
3768fa21302bSSascha Wildner 		}
3769fa21302bSSascha Wildner 	if (j == 0) {
3770fa21302bSSascha Wildner 		kfree(p, M_TEMP);
3771fa21302bSSascha Wildner 		return (0);
3772fa21302bSSascha Wildner 	}
3773fa21302bSSascha Wildner 	iface->data = kmalloc(sizeof(*iface->data) * j, M_TEMP, M_WAITOK);
3774fa21302bSSascha Wildner 	iface->num = j;
3775fa21302bSSascha Wildner 	i = j = 0;
3776fa21302bSSascha Wildner 	while (i < len)
3777fa21302bSSascha Wildner 		if (isspace(p[i]) || p[i] == '\0')
3778fa21302bSSascha Wildner 			i++;
3779fa21302bSSascha Wildner 		else {
3780fa21302bSSascha Wildner 			iface->data[j] = p + i;
3781fa21302bSSascha Wildner 			i += strlen(p + i) + 1;
3782fa21302bSSascha Wildner 			j++;
3783fa21302bSSascha Wildner 		}
3784fa21302bSSascha Wildner 
3785fa21302bSSascha Wildner 	return (j);
3786fa21302bSSascha Wildner }
3787fa21302bSSascha Wildner 
3788fa21302bSSascha Wildner static void
acpi_free_interfaces(struct acpi_interface * iface)3789fa21302bSSascha Wildner acpi_free_interfaces(struct acpi_interface *iface)
3790fa21302bSSascha Wildner {
3791fa21302bSSascha Wildner 	kfree(iface->data[0], M_TEMP);
3792fa21302bSSascha Wildner 	kfree(iface->data, M_TEMP);
3793fa21302bSSascha Wildner }
3794fa21302bSSascha Wildner 
3795fa21302bSSascha Wildner static void
acpi_reset_interfaces(device_t dev)3796fa21302bSSascha Wildner acpi_reset_interfaces(device_t dev)
3797fa21302bSSascha Wildner {
3798fa21302bSSascha Wildner 	struct acpi_interface list;
3799fa21302bSSascha Wildner 	ACPI_STATUS status;
3800fa21302bSSascha Wildner 	int i;
3801fa21302bSSascha Wildner 
3802fa21302bSSascha Wildner 	if (acpi_parse_interfaces(acpi_install_interface, &list) > 0) {
3803fa21302bSSascha Wildner 		for (i = 0; i < list.num; i++) {
3804fa21302bSSascha Wildner 			status = AcpiInstallInterface(list.data[i]);
3805fa21302bSSascha Wildner 			if (ACPI_FAILURE(status))
3806fa21302bSSascha Wildner 				device_printf(dev,
3807fa21302bSSascha Wildner 				    "failed to install _OSI(\"%s\"): %s\n",
3808fa21302bSSascha Wildner 				    list.data[i], AcpiFormatException(status));
3809fa21302bSSascha Wildner 			else if (bootverbose)
3810fa21302bSSascha Wildner 				device_printf(dev, "installed _OSI(\"%s\")\n",
3811fa21302bSSascha Wildner 				    list.data[i]);
3812fa21302bSSascha Wildner 		}
3813fa21302bSSascha Wildner 		acpi_free_interfaces(&list);
3814fa21302bSSascha Wildner 	}
3815fa21302bSSascha Wildner 	if (acpi_parse_interfaces(acpi_remove_interface, &list) > 0) {
3816fa21302bSSascha Wildner 		for (i = 0; i < list.num; i++) {
3817fa21302bSSascha Wildner 			status = AcpiRemoveInterface(list.data[i]);
3818fa21302bSSascha Wildner 			if (ACPI_FAILURE(status))
3819fa21302bSSascha Wildner 				device_printf(dev,
3820fa21302bSSascha Wildner 				    "failed to remove _OSI(\"%s\"): %s\n",
3821fa21302bSSascha Wildner 				    list.data[i], AcpiFormatException(status));
3822fa21302bSSascha Wildner 			else if (bootverbose)
3823fa21302bSSascha Wildner 				device_printf(dev, "removed _OSI(\"%s\")\n",
3824fa21302bSSascha Wildner 				    list.data[i]);
3825fa21302bSSascha Wildner 		}
3826fa21302bSSascha Wildner 		acpi_free_interfaces(&list);
3827fa21302bSSascha Wildner 	}
3828fa21302bSSascha Wildner }
3829fa21302bSSascha Wildner 
3830586fced2SSascha Wildner static int
acpi_pm_func(u_long cmd,void * arg,...)38315db2f26eSSascha Wildner acpi_pm_func(u_long cmd, void *arg, ...)
38325db2f26eSSascha Wildner {
38335db2f26eSSascha Wildner 	int	state, acpi_state;
38345db2f26eSSascha Wildner 	int	error;
38355db2f26eSSascha Wildner 	struct	acpi_softc *sc;
3836d26841ecSSascha Wildner 	__va_list ap;
38375db2f26eSSascha Wildner 
38385db2f26eSSascha Wildner 	error = 0;
38395db2f26eSSascha Wildner 	switch (cmd) {
38405db2f26eSSascha Wildner 	case POWER_CMD_SUSPEND:
38415db2f26eSSascha Wildner 		sc = (struct acpi_softc *)arg;
38425db2f26eSSascha Wildner 		if (sc == NULL) {
38435db2f26eSSascha Wildner 			error = EINVAL;
38445db2f26eSSascha Wildner 			goto out;
38455db2f26eSSascha Wildner 		}
38465db2f26eSSascha Wildner 
3847d26841ecSSascha Wildner 		__va_start(ap, arg);
3848d26841ecSSascha Wildner 		state = __va_arg(ap, int);
3849d26841ecSSascha Wildner 		__va_end(ap);
38505db2f26eSSascha Wildner 
38515db2f26eSSascha Wildner 		switch (state) {
38525db2f26eSSascha Wildner 		case POWER_SLEEP_STATE_STANDBY:
38535db2f26eSSascha Wildner 			acpi_state = sc->acpi_standby_sx;
38545db2f26eSSascha Wildner 			break;
38555db2f26eSSascha Wildner 		case POWER_SLEEP_STATE_SUSPEND:
38565db2f26eSSascha Wildner 			acpi_state = sc->acpi_suspend_sx;
38575db2f26eSSascha Wildner 			break;
38585db2f26eSSascha Wildner 		case POWER_SLEEP_STATE_HIBERNATE:
38595db2f26eSSascha Wildner 			acpi_state = ACPI_STATE_S4;
38605db2f26eSSascha Wildner 			break;
38615db2f26eSSascha Wildner 		default:
38625db2f26eSSascha Wildner 			error = EINVAL;
38635db2f26eSSascha Wildner 			goto out;
38645db2f26eSSascha Wildner 		}
38655db2f26eSSascha Wildner 
38665db2f26eSSascha Wildner 		if (ACPI_FAILURE(acpi_EnterSleepState(sc, acpi_state)))
38675db2f26eSSascha Wildner 			error = ENXIO;
38685db2f26eSSascha Wildner 		break;
38695db2f26eSSascha Wildner 	default:
38705db2f26eSSascha Wildner 		error = EINVAL;
38715db2f26eSSascha Wildner 		goto out;
38725db2f26eSSascha Wildner 	}
38735db2f26eSSascha Wildner 
38745db2f26eSSascha Wildner out:
38755db2f26eSSascha Wildner 	return (error);
38765db2f26eSSascha Wildner }
38775db2f26eSSascha Wildner 
38785db2f26eSSascha Wildner static void
acpi_pm_register(void * arg)38795db2f26eSSascha Wildner acpi_pm_register(void *arg)
38805db2f26eSSascha Wildner {
38815db2f26eSSascha Wildner     if (!cold || resource_disabled("acpi", 0))
38825db2f26eSSascha Wildner 	return;
38835db2f26eSSascha Wildner 
38845db2f26eSSascha Wildner     power_pm_register(POWER_PM_TYPE_ACPI, acpi_pm_func, NULL);
38855db2f26eSSascha Wildner }
38865db2f26eSSascha Wildner 
38875db2f26eSSascha Wildner SYSINIT(power, SI_BOOT2_KLD, SI_ORDER_ANY, acpi_pm_register, 0);
3888