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), 82246128Ssbz DEVMETHOD_END 8367761Smsmith}; 8467761Smsmith 8567761Smsmithstatic driver_t acpi_button_driver = { 8667761Smsmith "acpi_button", 8767761Smsmith acpi_button_methods, 8867761Smsmith sizeof(struct acpi_button_softc), 8967761Smsmith}; 9067761Smsmith 9189054Smsmithstatic devclass_t acpi_button_devclass; 92118783SnjlDRIVER_MODULE(acpi_button, acpi, acpi_button_driver, acpi_button_devclass, 93118783Snjl 0, 0); 94128071SnjlMODULE_DEPEND(acpi_button, acpi, 1, 1, 1); 9567761Smsmith 9667761Smsmithstatic int 9767761Smsmithacpi_button_probe(device_t dev) 9867761Smsmith{ 99131282Snjl struct acpi_button_softc *sc; 100131282Snjl char *str; 10167761Smsmith 102131282Snjl if (acpi_disabled("button") || 103131282Snjl (str = ACPI_ID_PROBE(device_get_parent(dev), dev, btn_ids)) == NULL) 104131282Snjl return (ENXIO); 105131282Snjl 10667761Smsmith sc = device_get_softc(dev); 107131282Snjl if (strcmp(str, "PNP0C0C") == 0) { 108131282Snjl device_set_desc(dev, "Power Button"); 109131282Snjl sc->button_type = ACPI_POWER_BUTTON; 110131282Snjl } else if (strcmp(str, "ACPI_FPB") == 0) { 111131282Snjl device_set_desc(dev, "Power Button (fixed)"); 112131282Snjl sc->button_type = ACPI_POWER_BUTTON; 113131282Snjl sc->fixed = 1; 114131282Snjl } else if (strcmp(str, "PNP0C0E") == 0) { 115131282Snjl device_set_desc(dev, "Sleep Button"); 116131282Snjl sc->button_type = ACPI_SLEEP_BUTTON; 117131282Snjl } else if (strcmp(str, "ACPI_FSB") == 0) { 118131282Snjl device_set_desc(dev, "Sleep Button (fixed)"); 119131282Snjl sc->button_type = ACPI_SLEEP_BUTTON; 120131282Snjl sc->fixed = 1; 12167761Smsmith } 122131282Snjl 123131282Snjl return (0); 12467761Smsmith} 12567761Smsmith 12667761Smsmithstatic int 12767761Smsmithacpi_button_attach(device_t dev) 12867761Smsmith{ 129209746Sjkim struct acpi_prw_data prw; 13067761Smsmith struct acpi_button_softc *sc; 13167761Smsmith ACPI_STATUS status; 132120308Snjl int event; 13367761Smsmith 13496926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 13569744Smsmith 13667761Smsmith sc = device_get_softc(dev); 13767761Smsmith sc->button_dev = dev; 13867761Smsmith sc->button_handle = acpi_get_handle(dev); 139125679Snjl event = (sc->button_type == ACPI_SLEEP_BUTTON) ? 140125679Snjl ACPI_EVENT_SLEEP_BUTTON : ACPI_EVENT_POWER_BUTTON; 14167761Smsmith 142126014Snjl /* 143126014Snjl * Install the new handler. We could remove any fixed handlers added 144126014Snjl * from the FADT once we have a duplicate from the AML but some systems 145126014Snjl * only return events on one or the other so we have to keep both. 146126014Snjl */ 147120308Snjl if (sc->fixed) { 148125679Snjl AcpiClearEvent(event); 149120308Snjl status = AcpiInstallFixedEventHandler(event, 150120308Snjl acpi_button_fixed_handler, sc); 151120308Snjl } else { 152129692Snjl /* 153129692Snjl * If a system does not get lid events, it may make sense to change 154129692Snjl * the type to ACPI_ALL_NOTIFY. Some systems generate both a wake 155129692Snjl * and runtime notify in that case though. 156129692Snjl */ 157120308Snjl status = AcpiInstallNotifyHandler(sc->button_handle, 158120308Snjl ACPI_DEVICE_NOTIFY, acpi_button_notify_handler, sc); 159120308Snjl } 160118783Snjl if (ACPI_FAILURE(status)) { 161120308Snjl device_printf(sc->button_dev, "couldn't install notify handler - %s\n", 162118783Snjl AcpiFormatException(status)); 163118783Snjl return_VALUE (ENXIO); 16467761Smsmith } 165125679Snjl 166129783Snjl /* Enable the GPE for wake/runtime. */ 167129783Snjl acpi_wake_set_enable(dev, 1); 168209746Sjkim if (acpi_parse_prw(sc->button_handle, &prw) == 0) 169209746Sjkim AcpiEnableGpe(prw.gpe_handle, prw.gpe_bit); 170216471Sjkim 171118783Snjl return_VALUE (0); 17267761Smsmith} 17367761Smsmith 174100497Siwasakistatic int 175100497Siwasakiacpi_button_suspend(device_t dev) 176100497Siwasaki{ 177100497Siwasaki return (0); 178100497Siwasaki} 179100497Siwasaki 180100497Siwasakistatic int 181100497Siwasakiacpi_button_resume(device_t dev) 182100497Siwasaki{ 183100497Siwasaki return (0); 184100497Siwasaki} 185100497Siwasaki 18667761Smsmithstatic void 187125679Snjlacpi_button_notify_sleep(void *arg) 18867761Smsmith{ 18967761Smsmith struct acpi_button_softc *sc; 19067761Smsmith struct acpi_softc *acpi_sc; 19167761Smsmith 19296926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 19369744Smsmith 19467761Smsmith sc = (struct acpi_button_softc *)arg; 19567761Smsmith acpi_sc = acpi_device_get_parent_softc(sc->button_dev); 196118783Snjl if (acpi_sc == NULL) 19769744Smsmith return_VOID; 19867761Smsmith 199121493Snjl acpi_UserNotify("Button", sc->button_handle, sc->button_type); 200121493Snjl 20167761Smsmith switch (sc->button_type) { 20267761Smsmith case ACPI_POWER_BUTTON: 20397274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "power button pressed\n"); 204125679Snjl acpi_event_power_button_sleep(acpi_sc); 20567761Smsmith break; 20667761Smsmith case ACPI_SLEEP_BUTTON: 20797274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "sleep button pressed\n"); 208125679Snjl acpi_event_sleep_button_sleep(acpi_sc); 20967761Smsmith break; 21067761Smsmith default: 21169744Smsmith break; /* unknown button type */ 21267761Smsmith } 21367761Smsmith} 21467761Smsmith 21567761Smsmithstatic void 216125679Snjlacpi_button_notify_wakeup(void *arg) 21767761Smsmith{ 21867761Smsmith struct acpi_button_softc *sc; 21967761Smsmith struct acpi_softc *acpi_sc; 22067761Smsmith 22196926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 22269744Smsmith 22367761Smsmith sc = (struct acpi_button_softc *)arg; 22467761Smsmith acpi_sc = acpi_device_get_parent_softc(sc->button_dev); 225118783Snjl if (acpi_sc == NULL) 22669744Smsmith return_VOID; 22767761Smsmith 228121493Snjl acpi_UserNotify("Button", sc->button_handle, sc->button_type); 229121493Snjl 23067761Smsmith switch (sc->button_type) { 23167761Smsmith case ACPI_POWER_BUTTON: 23297274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by power button\n"); 233125679Snjl acpi_event_power_button_wake(acpi_sc); 23467761Smsmith break; 23567761Smsmith case ACPI_SLEEP_BUTTON: 23697274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by sleep button\n"); 237125679Snjl acpi_event_sleep_button_wake(acpi_sc); 23867761Smsmith break; 23967761Smsmith default: 24069744Smsmith break; /* unknown button type */ 24167761Smsmith } 24267761Smsmith} 24367761Smsmith 24467761Smsmithstatic void 24567761Smsmithacpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 24667761Smsmith{ 247129692Snjl struct acpi_button_softc *sc; 24867761Smsmith 24996926Speter ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 25069744Smsmith 251129692Snjl sc = (struct acpi_button_softc *)context; 25267761Smsmith switch (notify) { 25367761Smsmith case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP: 254167814Sjkim AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_button_notify_sleep, sc); 25567761Smsmith break; 25667761Smsmith case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP: 257167814Sjkim AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_button_notify_wakeup, sc); 25867761Smsmith break; 25967761Smsmith default: 260129692Snjl device_printf(sc->button_dev, "unknown notify %#x\n", notify); 261129692Snjl break; 26267761Smsmith } 26367761Smsmith} 264120308Snjl 265120308Snjlstatic ACPI_STATUS 266120308Snjlacpi_button_fixed_handler(void *context) 267120308Snjl{ 268120308Snjl struct acpi_button_softc *sc = (struct acpi_button_softc *)context; 269120308Snjl 270120327Snjl ACPI_FUNCTION_TRACE_PTR((char *)(uintptr_t)__func__, context); 271120317Sphk 272120308Snjl if (context == NULL) 273120308Snjl return_ACPI_STATUS (AE_BAD_PARAMETER); 274120308Snjl 275120308Snjl acpi_button_notify_handler(sc->button_handle, 276120308Snjl ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP, sc); 277120327Snjl return_ACPI_STATUS (AE_OK); 278120308Snjl} 279