167761Smsmith/*- 267761Smsmith * Copyright (c) 2000 Mitsaru IWASAKI <iwasaki@jp.freebsd.org> 367761Smsmith * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> 467761Smsmith * Copyright (c) 2000 BSDi 567761Smsmith * All rights reserved. 667761Smsmith * 767761Smsmith * Redistribution and use in source and binary forms, with or without 867761Smsmith * modification, are permitted provided that the following conditions 967761Smsmith * are met: 1067761Smsmith * 1. Redistributions of source code must retain the above copyright 1167761Smsmith * notice, this list of conditions and the following disclaimer. 1267761Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1367761Smsmith * notice, this list of conditions and the following disclaimer in the 1467761Smsmith * documentation and/or other materials provided with the distribution. 1567761Smsmith * 1667761Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1767761Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1867761Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1967761Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2067761Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2167761Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2267761Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2367761Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2467761Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2567761Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2667761Smsmith * SUCH DAMAGE. 2767761Smsmith */ 2867761Smsmith 29143002Sobrien#include <sys/cdefs.h> 30143002Sobrien__FBSDID("$FreeBSD$"); 31143002Sobrien 3267761Smsmith#include "opt_acpi.h" 3367761Smsmith#include <sys/param.h> 3467761Smsmith#include <sys/kernel.h> 35129879Sphk#include <sys/module.h> 3667761Smsmith#include <sys/bus.h> 3767761Smsmith 38193530Sjkim#include <contrib/dev/acpica/include/acpi.h> 39193530Sjkim#include <contrib/dev/acpica/include/accommon.h> 40193530Sjkim 4167761Smsmith#include <dev/acpica/acpivar.h> 4267761Smsmith 43118783Snjl/* Hooks for the ACPI CA debugging infrastructure */ 4477432Smsmith#define _COMPONENT ACPI_BUTTON 4591123SmsmithACPI_MODULE_NAME("BUTTON") 4669744Smsmith 4767761Smsmithstruct acpi_button_softc { 4867761Smsmith device_t button_dev; 4967761Smsmith ACPI_HANDLE button_handle; 50120308Snjl boolean_t button_type; 51118783Snjl#define ACPI_POWER_BUTTON 0 52118783Snjl#define ACPI_SLEEP_BUTTON 1 53120308Snjl boolean_t fixed; 5467761Smsmith}; 5567761Smsmith 56118783Snjl#define ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP 0x80 57118783Snjl#define ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP 0x02 58118783Snjl 5967761Smsmithstatic int acpi_button_probe(device_t dev); 6067761Smsmithstatic int acpi_button_attach(device_t dev); 61100497Siwasakistatic int acpi_button_suspend(device_t dev); 62100497Siwasakistatic int acpi_button_resume(device_t dev); 63118783Snjlstatic void acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, 64118783Snjl void *context); 65120308Snjlstatic ACPI_STATUS 66120308Snjl acpi_button_fixed_handler(void *context); 67125679Snjlstatic void acpi_button_notify_sleep(void *arg); 68125679Snjlstatic void acpi_button_notify_wakeup(void *arg); 6967761Smsmith 70131282Snjlstatic char *btn_ids[] = { 71131282Snjl "PNP0C0C", "ACPI_FPB", "PNP0C0E", "ACPI_FSB", 72131282Snjl NULL 73131282Snjl}; 74131282Snjl 7567761Smsmithstatic device_method_t acpi_button_methods[] = { 7667761Smsmith /* Device interface */ 7767761Smsmith DEVMETHOD(device_probe, acpi_button_probe), 7867761Smsmith DEVMETHOD(device_attach, acpi_button_attach), 79100497Siwasaki DEVMETHOD(device_suspend, acpi_button_suspend), 80118049Stakawata DEVMETHOD(device_shutdown, acpi_button_suspend), 81100497Siwasaki DEVMETHOD(device_resume, acpi_button_resume), 8267761Smsmith 8367761Smsmith {0, 0} 8467761Smsmith}; 8567761Smsmith 8667761Smsmithstatic driver_t acpi_button_driver = { 8767761Smsmith "acpi_button", 8867761Smsmith acpi_button_methods, 8967761Smsmith sizeof(struct acpi_button_softc), 9067761Smsmith}; 9167761Smsmith 9289054Smsmithstatic devclass_t acpi_button_devclass; 93118783SnjlDRIVER_MODULE(acpi_button, acpi, acpi_button_driver, acpi_button_devclass, 94118783Snjl 0, 0); 95128071SnjlMODULE_DEPEND(acpi_button, acpi, 1, 1, 1); 9667761Smsmith 9767761Smsmithstatic int 9867761Smsmithacpi_button_probe(device_t dev) 9967761Smsmith{ 100131282Snjl struct acpi_button_softc *sc; 101131282Snjl char *str; 10267761Smsmith 103131282Snjl if (acpi_disabled("button") || 104131282Snjl (str = ACPI_ID_PROBE(device_get_parent(dev), dev, btn_ids)) == NULL) 105131282Snjl return (ENXIO); 106131282Snjl 10767761Smsmith sc = device_get_softc(dev); 108131282Snjl if (strcmp(str, "PNP0C0C") == 0) { 109131282Snjl device_set_desc(dev, "Power Button"); 110131282Snjl sc->button_type = ACPI_POWER_BUTTON; 111131282Snjl } else if (strcmp(str, "ACPI_FPB") == 0) { 112131282Snjl device_set_desc(dev, "Power Button (fixed)"); 113131282Snjl sc->button_type = ACPI_POWER_BUTTON; 114131282Snjl sc->fixed = 1; 115131282Snjl } else if (strcmp(str, "PNP0C0E") == 0) { 116131282Snjl device_set_desc(dev, "Sleep Button"); 117131282Snjl sc->button_type = ACPI_SLEEP_BUTTON; 118131282Snjl } else if (strcmp(str, "ACPI_FSB") == 0) { 119131282Snjl device_set_desc(dev, "Sleep Button (fixed)"); 120131282Snjl sc->button_type = ACPI_SLEEP_BUTTON; 121131282Snjl sc->fixed = 1; 12267761Smsmith } 123131282Snjl 124131282Snjl return (0); 12567761Smsmith} 12667761Smsmith 12767761Smsmithstatic int 12867761Smsmithacpi_button_attach(device_t dev) 12967761Smsmith{ 130209746Sjkim struct acpi_prw_data prw; 13167761Smsmith struct acpi_button_softc *sc; 13267761Smsmith ACPI_STATUS status; 133120308Snjl int event; 13467761Smsmith 13596926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 13669744Smsmith 13767761Smsmith sc = device_get_softc(dev); 13867761Smsmith sc->button_dev = dev; 13967761Smsmith sc->button_handle = acpi_get_handle(dev); 140125679Snjl event = (sc->button_type == ACPI_SLEEP_BUTTON) ? 141125679Snjl ACPI_EVENT_SLEEP_BUTTON : ACPI_EVENT_POWER_BUTTON; 14267761Smsmith 143126014Snjl /* 144126014Snjl * Install the new handler. We could remove any fixed handlers added 145126014Snjl * from the FADT once we have a duplicate from the AML but some systems 146126014Snjl * only return events on one or the other so we have to keep both. 147126014Snjl */ 148120308Snjl if (sc->fixed) { 149125679Snjl AcpiClearEvent(event); 150120308Snjl status = AcpiInstallFixedEventHandler(event, 151120308Snjl acpi_button_fixed_handler, sc); 152120308Snjl } else { 153129692Snjl /* 154129692Snjl * If a system does not get lid events, it may make sense to change 155129692Snjl * the type to ACPI_ALL_NOTIFY. Some systems generate both a wake 156129692Snjl * and runtime notify in that case though. 157129692Snjl */ 158120308Snjl status = AcpiInstallNotifyHandler(sc->button_handle, 159120308Snjl ACPI_DEVICE_NOTIFY, acpi_button_notify_handler, sc); 160120308Snjl } 161118783Snjl if (ACPI_FAILURE(status)) { 162120308Snjl device_printf(sc->button_dev, "couldn't install notify handler - %s\n", 163118783Snjl AcpiFormatException(status)); 164118783Snjl return_VALUE (ENXIO); 16567761Smsmith } 166125679Snjl 167129783Snjl /* Enable the GPE for wake/runtime. */ 168129783Snjl acpi_wake_set_enable(dev, 1); 169209746Sjkim if (acpi_parse_prw(sc->button_handle, &prw) == 0) 170209746Sjkim AcpiEnableGpe(prw.gpe_handle, prw.gpe_bit); 171216471Sjkim 172118783Snjl return_VALUE (0); 17367761Smsmith} 17467761Smsmith 175100497Siwasakistatic int 176100497Siwasakiacpi_button_suspend(device_t dev) 177100497Siwasaki{ 178100497Siwasaki return (0); 179100497Siwasaki} 180100497Siwasaki 181100497Siwasakistatic int 182100497Siwasakiacpi_button_resume(device_t dev) 183100497Siwasaki{ 184100497Siwasaki return (0); 185100497Siwasaki} 186100497Siwasaki 18767761Smsmithstatic void 188125679Snjlacpi_button_notify_sleep(void *arg) 18967761Smsmith{ 19067761Smsmith struct acpi_button_softc *sc; 19167761Smsmith struct acpi_softc *acpi_sc; 19267761Smsmith 19396926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 19469744Smsmith 19567761Smsmith sc = (struct acpi_button_softc *)arg; 19667761Smsmith acpi_sc = acpi_device_get_parent_softc(sc->button_dev); 197118783Snjl if (acpi_sc == NULL) 19869744Smsmith return_VOID; 19967761Smsmith 200121493Snjl acpi_UserNotify("Button", sc->button_handle, sc->button_type); 201121493Snjl 20267761Smsmith switch (sc->button_type) { 20367761Smsmith case ACPI_POWER_BUTTON: 20497274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "power button pressed\n"); 205125679Snjl acpi_event_power_button_sleep(acpi_sc); 20667761Smsmith break; 20767761Smsmith case ACPI_SLEEP_BUTTON: 20897274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "sleep button pressed\n"); 209125679Snjl acpi_event_sleep_button_sleep(acpi_sc); 21067761Smsmith break; 21167761Smsmith default: 21269744Smsmith break; /* unknown button type */ 21367761Smsmith } 21467761Smsmith} 21567761Smsmith 21667761Smsmithstatic void 217125679Snjlacpi_button_notify_wakeup(void *arg) 21867761Smsmith{ 21967761Smsmith struct acpi_button_softc *sc; 22067761Smsmith struct acpi_softc *acpi_sc; 22167761Smsmith 22296926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 22369744Smsmith 22467761Smsmith sc = (struct acpi_button_softc *)arg; 22567761Smsmith acpi_sc = acpi_device_get_parent_softc(sc->button_dev); 226118783Snjl if (acpi_sc == NULL) 22769744Smsmith return_VOID; 22867761Smsmith 229121493Snjl acpi_UserNotify("Button", sc->button_handle, sc->button_type); 230121493Snjl 23167761Smsmith switch (sc->button_type) { 23267761Smsmith case ACPI_POWER_BUTTON: 23397274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by power button\n"); 234125679Snjl acpi_event_power_button_wake(acpi_sc); 23567761Smsmith break; 23667761Smsmith case ACPI_SLEEP_BUTTON: 23797274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by sleep button\n"); 238125679Snjl acpi_event_sleep_button_wake(acpi_sc); 23967761Smsmith break; 24067761Smsmith default: 24169744Smsmith break; /* unknown button type */ 24267761Smsmith } 24367761Smsmith} 24467761Smsmith 24567761Smsmithstatic void 24667761Smsmithacpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 24767761Smsmith{ 248129692Snjl struct acpi_button_softc *sc; 24967761Smsmith 25096926Speter ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 25169744Smsmith 252129692Snjl sc = (struct acpi_button_softc *)context; 25367761Smsmith switch (notify) { 25467761Smsmith case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP: 255167814Sjkim AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_button_notify_sleep, sc); 25667761Smsmith break; 25767761Smsmith case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP: 258167814Sjkim AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_button_notify_wakeup, sc); 25967761Smsmith break; 26067761Smsmith default: 261129692Snjl device_printf(sc->button_dev, "unknown notify %#x\n", notify); 262129692Snjl break; 26367761Smsmith } 26467761Smsmith} 265120308Snjl 266120308Snjlstatic ACPI_STATUS 267120308Snjlacpi_button_fixed_handler(void *context) 268120308Snjl{ 269120308Snjl struct acpi_button_softc *sc = (struct acpi_button_softc *)context; 270120308Snjl 271120327Snjl ACPI_FUNCTION_TRACE_PTR((char *)(uintptr_t)__func__, context); 272120317Sphk 273120308Snjl if (context == NULL) 274120308Snjl return_ACPI_STATUS (AE_BAD_PARAMETER); 275120308Snjl 276120308Snjl acpi_button_notify_handler(sc->button_handle, 277120308Snjl ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP, sc); 278120327Snjl return_ACPI_STATUS (AE_OK); 279120308Snjl} 280