115e32d5dSMike Smith /*- 215e32d5dSMike Smith * Copyright (c) 2000 Mitsaru IWASAKI <iwasaki@jp.freebsd.org> 315e32d5dSMike Smith * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> 415e32d5dSMike Smith * Copyright (c) 2000 BSDi 515e32d5dSMike Smith * All rights reserved. 615e32d5dSMike Smith * 715e32d5dSMike Smith * Redistribution and use in source and binary forms, with or without 815e32d5dSMike Smith * modification, are permitted provided that the following conditions 915e32d5dSMike Smith * are met: 1015e32d5dSMike Smith * 1. Redistributions of source code must retain the above copyright 1115e32d5dSMike Smith * notice, this list of conditions and the following disclaimer. 1215e32d5dSMike Smith * 2. Redistributions in binary form must reproduce the above copyright 1315e32d5dSMike Smith * notice, this list of conditions and the following disclaimer in the 1415e32d5dSMike Smith * documentation and/or other materials provided with the distribution. 1515e32d5dSMike Smith * 1615e32d5dSMike Smith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1715e32d5dSMike Smith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1815e32d5dSMike Smith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1915e32d5dSMike Smith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2015e32d5dSMike Smith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2115e32d5dSMike Smith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2215e32d5dSMike Smith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2315e32d5dSMike Smith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2415e32d5dSMike Smith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2515e32d5dSMike Smith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2615e32d5dSMike Smith * SUCH DAMAGE. 2715e32d5dSMike Smith * 2815e32d5dSMike Smith * $FreeBSD$ 2915e32d5dSMike Smith */ 3015e32d5dSMike Smith 3115e32d5dSMike Smith #include "opt_acpi.h" 3215e32d5dSMike Smith #include <sys/param.h> 3315e32d5dSMike Smith #include <sys/kernel.h> 3415e32d5dSMike Smith #include <sys/bus.h> 3515e32d5dSMike Smith 3615e32d5dSMike Smith #include "acpi.h" 3715e32d5dSMike Smith #include <dev/acpica/acpivar.h> 3815e32d5dSMike Smith 39798fb860SNate Lawson /* Hooks for the ACPI CA debugging infrastructure */ 402a4ac806SMike Smith #define _COMPONENT ACPI_BUTTON 419127281cSMike Smith ACPI_MODULE_NAME("BUTTON") 420ae55423SMike Smith 4315e32d5dSMike Smith struct acpi_button_softc { 4415e32d5dSMike Smith device_t button_dev; 4515e32d5dSMike Smith ACPI_HANDLE button_handle; 46be8dca59SNate Lawson boolean_t button_type; 4715e32d5dSMike Smith #define ACPI_POWER_BUTTON 0 4815e32d5dSMike Smith #define ACPI_SLEEP_BUTTON 1 49be8dca59SNate Lawson boolean_t fixed; 5015e32d5dSMike Smith }; 5115e32d5dSMike Smith 52798fb860SNate Lawson #define ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP 0x80 53798fb860SNate Lawson #define ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP 0x02 54798fb860SNate Lawson 5515e32d5dSMike Smith static int acpi_button_probe(device_t dev); 5615e32d5dSMike Smith static int acpi_button_attach(device_t dev); 57a1fccb47SMitsuru IWASAKI static int acpi_button_suspend(device_t dev); 58a1fccb47SMitsuru IWASAKI static int acpi_button_resume(device_t dev); 59798fb860SNate Lawson static void acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, 60798fb860SNate Lawson void *context); 61be8dca59SNate Lawson static ACPI_STATUS 62be8dca59SNate Lawson acpi_button_fixed_handler(void *context); 6315e32d5dSMike Smith static void acpi_button_notify_pressed_for_sleep(void *arg); 6415e32d5dSMike Smith static void acpi_button_notify_pressed_for_wakeup(void *arg); 6515e32d5dSMike Smith 6615e32d5dSMike Smith static device_method_t acpi_button_methods[] = { 6715e32d5dSMike Smith /* Device interface */ 6815e32d5dSMike Smith DEVMETHOD(device_probe, acpi_button_probe), 6915e32d5dSMike Smith DEVMETHOD(device_attach, acpi_button_attach), 70a1fccb47SMitsuru IWASAKI DEVMETHOD(device_suspend, acpi_button_suspend), 7162d4c42bSTakanori Watanabe DEVMETHOD(device_shutdown, acpi_button_suspend), 72a1fccb47SMitsuru IWASAKI DEVMETHOD(device_resume, acpi_button_resume), 7315e32d5dSMike Smith 7415e32d5dSMike Smith {0, 0} 7515e32d5dSMike Smith }; 7615e32d5dSMike Smith 7715e32d5dSMike Smith static driver_t acpi_button_driver = { 7815e32d5dSMike Smith "acpi_button", 7915e32d5dSMike Smith acpi_button_methods, 8015e32d5dSMike Smith sizeof(struct acpi_button_softc), 8115e32d5dSMike Smith }; 8215e32d5dSMike Smith 833273b005SMike Smith static devclass_t acpi_button_devclass; 84798fb860SNate Lawson DRIVER_MODULE(acpi_button, acpi, acpi_button_driver, acpi_button_devclass, 85798fb860SNate Lawson 0, 0); 8615e32d5dSMike Smith 8715e32d5dSMike Smith static int 8815e32d5dSMike Smith acpi_button_probe(device_t dev) 8915e32d5dSMike Smith { 9015e32d5dSMike Smith struct acpi_button_softc *sc; 91be8dca59SNate Lawson int ret = ENXIO; 9215e32d5dSMike Smith 9315e32d5dSMike Smith sc = device_get_softc(dev); 94be8dca59SNate Lawson if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("button")) { 9515e32d5dSMike Smith if (acpi_MatchHid(dev, "PNP0C0C")) { 9667ce1673SMike Smith device_set_desc(dev, "Power Button"); 9715e32d5dSMike Smith sc->button_type = ACPI_POWER_BUTTON; 98be8dca59SNate Lawson ret = 0; 99be8dca59SNate Lawson } else if (acpi_MatchHid(dev, "ACPI_FPB")) { 100be8dca59SNate Lawson device_set_desc(dev, "Power Button (fixed)"); 101be8dca59SNate Lawson sc->button_type = ACPI_POWER_BUTTON; 102be8dca59SNate Lawson sc->fixed = 1; 103be8dca59SNate Lawson ret = 0; 104be8dca59SNate Lawson } else if (acpi_MatchHid(dev, "PNP0C0E")) { 10567ce1673SMike Smith device_set_desc(dev, "Sleep Button"); 10615e32d5dSMike Smith sc->button_type = ACPI_SLEEP_BUTTON; 107be8dca59SNate Lawson ret = 0; 108be8dca59SNate Lawson } else if (acpi_MatchHid(dev, "ACPI_FSB")) { 109be8dca59SNate Lawson device_set_desc(dev, "Sleep Button (fixed)"); 110be8dca59SNate Lawson sc->button_type = ACPI_SLEEP_BUTTON; 111be8dca59SNate Lawson sc->fixed = 1; 112be8dca59SNate Lawson ret = 0; 11315e32d5dSMike Smith } 1140ae55423SMike Smith } 115be8dca59SNate Lawson return (ret); 11615e32d5dSMike Smith } 11715e32d5dSMike Smith 11815e32d5dSMike Smith static int 11915e32d5dSMike Smith acpi_button_attach(device_t dev) 12015e32d5dSMike Smith { 12115e32d5dSMike Smith struct acpi_button_softc *sc; 12215e32d5dSMike Smith ACPI_STATUS status; 123be8dca59SNate Lawson int event; 12415e32d5dSMike Smith 125b4a05238SPeter Wemm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 1260ae55423SMike Smith 12715e32d5dSMike Smith sc = device_get_softc(dev); 12815e32d5dSMike Smith sc->button_dev = dev; 12915e32d5dSMike Smith sc->button_handle = acpi_get_handle(dev); 13015e32d5dSMike Smith 131be8dca59SNate Lawson if (sc->fixed) { 132be8dca59SNate Lawson event = (sc->button_type == ACPI_SLEEP_BUTTON) ? 133be8dca59SNate Lawson ACPI_EVENT_SLEEP_BUTTON : ACPI_EVENT_POWER_BUTTON; 134be8dca59SNate Lawson status = AcpiInstallFixedEventHandler(event, 135be8dca59SNate Lawson acpi_button_fixed_handler, sc); 136be8dca59SNate Lawson } else { 137be8dca59SNate Lawson status = AcpiInstallNotifyHandler(sc->button_handle, 138be8dca59SNate Lawson ACPI_DEVICE_NOTIFY, acpi_button_notify_handler, sc); 139be8dca59SNate Lawson } 140798fb860SNate Lawson if (ACPI_FAILURE(status)) { 141be8dca59SNate Lawson device_printf(sc->button_dev, "couldn't install notify handler - %s\n", 142798fb860SNate Lawson AcpiFormatException(status)); 1430ae55423SMike Smith return_VALUE (ENXIO); 14415e32d5dSMike Smith } 145a1fccb47SMitsuru IWASAKI acpi_device_enable_wake_capability(sc->button_handle, 1); 1460ae55423SMike Smith return_VALUE (0); 14715e32d5dSMike Smith } 14815e32d5dSMike Smith 149a1fccb47SMitsuru IWASAKI static int 150a1fccb47SMitsuru IWASAKI acpi_button_suspend(device_t dev) 151a1fccb47SMitsuru IWASAKI { 152a1fccb47SMitsuru IWASAKI struct acpi_button_softc *sc; 153a1fccb47SMitsuru IWASAKI 154a1fccb47SMitsuru IWASAKI sc = device_get_softc(dev); 155a1fccb47SMitsuru IWASAKI acpi_device_enable_wake_event(sc->button_handle); 156a1fccb47SMitsuru IWASAKI return (0); 157a1fccb47SMitsuru IWASAKI } 158a1fccb47SMitsuru IWASAKI 159a1fccb47SMitsuru IWASAKI static int 160a1fccb47SMitsuru IWASAKI acpi_button_resume(device_t dev) 161a1fccb47SMitsuru IWASAKI { 162a1fccb47SMitsuru IWASAKI return (0); 163a1fccb47SMitsuru IWASAKI } 164a1fccb47SMitsuru IWASAKI 16515e32d5dSMike Smith static void 16615e32d5dSMike Smith acpi_button_notify_pressed_for_sleep(void *arg) 16715e32d5dSMike Smith { 16815e32d5dSMike Smith struct acpi_button_softc *sc; 16915e32d5dSMike Smith struct acpi_softc *acpi_sc; 17015e32d5dSMike Smith 171b4a05238SPeter Wemm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 1720ae55423SMike Smith 17315e32d5dSMike Smith sc = (struct acpi_button_softc *)arg; 17415e32d5dSMike Smith acpi_sc = acpi_device_get_parent_softc(sc->button_dev); 175798fb860SNate Lawson if (acpi_sc == NULL) 1760ae55423SMike Smith return_VOID; 17715e32d5dSMike Smith 1789b937d48SNate Lawson acpi_UserNotify("Button", sc->button_handle, sc->button_type); 1799b937d48SNate Lawson 18015e32d5dSMike Smith switch (sc->button_type) { 18115e32d5dSMike Smith case ACPI_POWER_BUTTON: 182e788f796SBruce Evans ACPI_VPRINT(sc->button_dev, acpi_sc, "power button pressed\n"); 18315e32d5dSMike Smith acpi_eventhandler_power_button_for_sleep((void *)acpi_sc); 18415e32d5dSMike Smith break; 18515e32d5dSMike Smith case ACPI_SLEEP_BUTTON: 186e788f796SBruce Evans ACPI_VPRINT(sc->button_dev, acpi_sc, "sleep button pressed\n"); 18715e32d5dSMike Smith acpi_eventhandler_sleep_button_for_sleep((void *)acpi_sc); 18815e32d5dSMike Smith break; 18915e32d5dSMike Smith default: 1900ae55423SMike Smith break; /* unknown button type */ 19115e32d5dSMike Smith } 19215e32d5dSMike Smith } 19315e32d5dSMike Smith 19415e32d5dSMike Smith static void 19515e32d5dSMike Smith acpi_button_notify_pressed_for_wakeup(void *arg) 19615e32d5dSMike Smith { 19715e32d5dSMike Smith struct acpi_button_softc *sc; 19815e32d5dSMike Smith struct acpi_softc *acpi_sc; 19915e32d5dSMike Smith 200b4a05238SPeter Wemm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 2010ae55423SMike Smith 20215e32d5dSMike Smith sc = (struct acpi_button_softc *)arg; 20315e32d5dSMike Smith acpi_sc = acpi_device_get_parent_softc(sc->button_dev); 204798fb860SNate Lawson if (acpi_sc == NULL) 2050ae55423SMike Smith return_VOID; 20615e32d5dSMike Smith 2079b937d48SNate Lawson acpi_UserNotify("Button", sc->button_handle, sc->button_type); 2089b937d48SNate Lawson 20915e32d5dSMike Smith switch (sc->button_type) { 21015e32d5dSMike Smith case ACPI_POWER_BUTTON: 211e788f796SBruce Evans ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by power button\n"); 21215e32d5dSMike Smith acpi_eventhandler_power_button_for_wakeup((void *)acpi_sc); 21315e32d5dSMike Smith break; 21415e32d5dSMike Smith case ACPI_SLEEP_BUTTON: 215e788f796SBruce Evans ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by sleep button\n"); 21615e32d5dSMike Smith acpi_eventhandler_sleep_button_for_wakeup((void *)acpi_sc); 21715e32d5dSMike Smith break; 21815e32d5dSMike Smith default: 2190ae55423SMike Smith break; /* unknown button type */ 22015e32d5dSMike Smith } 22115e32d5dSMike Smith } 22215e32d5dSMike Smith 22315e32d5dSMike Smith static void 22415e32d5dSMike Smith acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 22515e32d5dSMike Smith { 22615e32d5dSMike Smith struct acpi_button_softc *sc = (struct acpi_button_softc *)context; 22715e32d5dSMike Smith 228b4a05238SPeter Wemm ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 2290ae55423SMike Smith 23015e32d5dSMike Smith switch (notify) { 23115e32d5dSMike Smith case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP: 232798fb860SNate Lawson AcpiOsQueueForExecution(OSD_PRIORITY_LO, 233798fb860SNate Lawson acpi_button_notify_pressed_for_sleep, sc); 23415e32d5dSMike Smith break; 23515e32d5dSMike Smith case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP: 236798fb860SNate Lawson AcpiOsQueueForExecution(OSD_PRIORITY_LO, 237798fb860SNate Lawson acpi_button_notify_pressed_for_wakeup, sc); 23815e32d5dSMike Smith break; 23915e32d5dSMike Smith default: 2400ae55423SMike Smith break; /* unknown notification value */ 24115e32d5dSMike Smith } 24215e32d5dSMike Smith } 243be8dca59SNate Lawson 244be8dca59SNate Lawson static ACPI_STATUS 245be8dca59SNate Lawson acpi_button_fixed_handler(void *context) 246be8dca59SNate Lawson { 247be8dca59SNate Lawson struct acpi_button_softc *sc = (struct acpi_button_softc *)context; 248be8dca59SNate Lawson 249a6a1d015SNate Lawson ACPI_FUNCTION_TRACE_PTR((char *)(uintptr_t)__func__, context); 250d2f243d0SPoul-Henning Kamp 251be8dca59SNate Lawson if (context == NULL) 252be8dca59SNate Lawson return_ACPI_STATUS (AE_BAD_PARAMETER); 253be8dca59SNate Lawson 254be8dca59SNate Lawson acpi_button_notify_handler(sc->button_handle, 255be8dca59SNate Lawson ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP, sc); 256a6a1d015SNate Lawson return_ACPI_STATUS (AE_OK); 257be8dca59SNate Lawson } 258