acpi_button.c revision 129805
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 * $FreeBSD: head/sys/dev/acpica/acpi_button.c 129805 2004-05-28 07:04:09Z njl $ 2967761Smsmith */ 3067761Smsmith 3167761Smsmith#include "opt_acpi.h" 3267761Smsmith#include <sys/param.h> 3367761Smsmith#include <sys/kernel.h> 3467761Smsmith#include <sys/bus.h> 3567761Smsmith 3667761Smsmith#include "acpi.h" 3767761Smsmith#include <dev/acpica/acpivar.h> 3867761Smsmith 39118783Snjl/* Hooks for the ACPI CA debugging infrastructure */ 4077432Smsmith#define _COMPONENT ACPI_BUTTON 4191123SmsmithACPI_MODULE_NAME("BUTTON") 4269744Smsmith 4367761Smsmithstruct acpi_button_softc { 4467761Smsmith device_t button_dev; 4567761Smsmith ACPI_HANDLE button_handle; 46120308Snjl boolean_t button_type; 47118783Snjl#define ACPI_POWER_BUTTON 0 48118783Snjl#define ACPI_SLEEP_BUTTON 1 49120308Snjl boolean_t fixed; 5067761Smsmith}; 5167761Smsmith 52118783Snjl#define ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP 0x80 53118783Snjl#define ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP 0x02 54118783Snjl 5567761Smsmithstatic int acpi_button_probe(device_t dev); 5667761Smsmithstatic int acpi_button_attach(device_t dev); 57100497Siwasakistatic int acpi_button_suspend(device_t dev); 58100497Siwasakistatic int acpi_button_resume(device_t dev); 59118783Snjlstatic void acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, 60118783Snjl void *context); 61120308Snjlstatic ACPI_STATUS 62120308Snjl acpi_button_fixed_handler(void *context); 63125679Snjlstatic void acpi_button_notify_sleep(void *arg); 64125679Snjlstatic void acpi_button_notify_wakeup(void *arg); 6567761Smsmith 6667761Smsmithstatic device_method_t acpi_button_methods[] = { 6767761Smsmith /* Device interface */ 6867761Smsmith DEVMETHOD(device_probe, acpi_button_probe), 6967761Smsmith DEVMETHOD(device_attach, acpi_button_attach), 70100497Siwasaki DEVMETHOD(device_suspend, acpi_button_suspend), 71118049Stakawata DEVMETHOD(device_shutdown, acpi_button_suspend), 72100497Siwasaki DEVMETHOD(device_resume, acpi_button_resume), 7367761Smsmith 7467761Smsmith {0, 0} 7567761Smsmith}; 7667761Smsmith 7767761Smsmithstatic driver_t acpi_button_driver = { 7867761Smsmith "acpi_button", 7967761Smsmith acpi_button_methods, 8067761Smsmith sizeof(struct acpi_button_softc), 8167761Smsmith}; 8267761Smsmith 8389054Smsmithstatic devclass_t acpi_button_devclass; 84118783SnjlDRIVER_MODULE(acpi_button, acpi, acpi_button_driver, acpi_button_devclass, 85118783Snjl 0, 0); 86128071SnjlMODULE_DEPEND(acpi_button, acpi, 1, 1, 1); 8767761Smsmith 8867761Smsmithstatic int 8967761Smsmithacpi_button_probe(device_t dev) 9067761Smsmith{ 9167761Smsmith struct acpi_button_softc *sc; 92120308Snjl int ret = ENXIO; 9367761Smsmith 9467761Smsmith sc = device_get_softc(dev); 95120308Snjl if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("button")) { 96120308Snjl if (acpi_MatchHid(dev, "PNP0C0C")) { 97120308Snjl device_set_desc(dev, "Power Button"); 98120308Snjl sc->button_type = ACPI_POWER_BUTTON; 99120308Snjl ret = 0; 100120308Snjl } else if (acpi_MatchHid(dev, "ACPI_FPB")) { 101120308Snjl device_set_desc(dev, "Power Button (fixed)"); 102120308Snjl sc->button_type = ACPI_POWER_BUTTON; 103120308Snjl sc->fixed = 1; 104120308Snjl ret = 0; 105120308Snjl } else if (acpi_MatchHid(dev, "PNP0C0E")) { 106120308Snjl device_set_desc(dev, "Sleep Button"); 107120308Snjl sc->button_type = ACPI_SLEEP_BUTTON; 108120308Snjl ret = 0; 109120308Snjl } else if (acpi_MatchHid(dev, "ACPI_FSB")) { 110120308Snjl device_set_desc(dev, "Sleep Button (fixed)"); 111120308Snjl sc->button_type = ACPI_SLEEP_BUTTON; 112120308Snjl sc->fixed = 1; 113120308Snjl ret = 0; 11467761Smsmith } 11567761Smsmith } 116120308Snjl return (ret); 11767761Smsmith} 11867761Smsmith 11967761Smsmithstatic int 12067761Smsmithacpi_button_attach(device_t dev) 12167761Smsmith{ 12267761Smsmith struct acpi_button_softc *sc; 12367761Smsmith ACPI_STATUS status; 124120308Snjl int event; 12567761Smsmith 12696926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 12769744Smsmith 12867761Smsmith sc = device_get_softc(dev); 12967761Smsmith sc->button_dev = dev; 13067761Smsmith sc->button_handle = acpi_get_handle(dev); 131125679Snjl event = (sc->button_type == ACPI_SLEEP_BUTTON) ? 132125679Snjl ACPI_EVENT_SLEEP_BUTTON : ACPI_EVENT_POWER_BUTTON; 13367761Smsmith 134126014Snjl /* 135126014Snjl * Install the new handler. We could remove any fixed handlers added 136126014Snjl * from the FADT once we have a duplicate from the AML but some systems 137126014Snjl * only return events on one or the other so we have to keep both. 138126014Snjl */ 139120308Snjl if (sc->fixed) { 140125679Snjl AcpiClearEvent(event); 141120308Snjl status = AcpiInstallFixedEventHandler(event, 142120308Snjl acpi_button_fixed_handler, sc); 143120308Snjl } else { 144129692Snjl /* 145129692Snjl * If a system does not get lid events, it may make sense to change 146129692Snjl * the type to ACPI_ALL_NOTIFY. Some systems generate both a wake 147129692Snjl * and runtime notify in that case though. 148129692Snjl */ 149120308Snjl status = AcpiInstallNotifyHandler(sc->button_handle, 150120308Snjl ACPI_DEVICE_NOTIFY, acpi_button_notify_handler, sc); 151120308Snjl } 152118783Snjl if (ACPI_FAILURE(status)) { 153120308Snjl device_printf(sc->button_dev, "couldn't install notify handler - %s\n", 154118783Snjl AcpiFormatException(status)); 155118783Snjl return_VALUE (ENXIO); 15667761Smsmith } 157125679Snjl 158129783Snjl /* Enable the GPE for wake/runtime. */ 159129783Snjl acpi_wake_init(dev, ACPI_GPE_TYPE_WAKE_RUN); 160129783Snjl acpi_wake_set_enable(dev, 1); 161129783Snjl 162118783Snjl return_VALUE (0); 16367761Smsmith} 16467761Smsmith 165100497Siwasakistatic int 166100497Siwasakiacpi_button_suspend(device_t dev) 167100497Siwasaki{ 168129783Snjl struct acpi_softc *acpi_sc; 169100497Siwasaki 170129783Snjl acpi_sc = acpi_device_get_parent_softc(dev); 171129783Snjl acpi_wake_sleep_prep(dev, acpi_sc->acpi_sstate); 172100497Siwasaki return (0); 173100497Siwasaki} 174100497Siwasaki 175100497Siwasakistatic int 176100497Siwasakiacpi_button_resume(device_t dev) 177100497Siwasaki{ 178129805Snjl acpi_wake_run_prep(dev); 179100497Siwasaki return (0); 180100497Siwasaki} 181100497Siwasaki 18267761Smsmithstatic void 183125679Snjlacpi_button_notify_sleep(void *arg) 18467761Smsmith{ 18567761Smsmith struct acpi_button_softc *sc; 18667761Smsmith struct acpi_softc *acpi_sc; 18767761Smsmith 18896926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 18969744Smsmith 19067761Smsmith sc = (struct acpi_button_softc *)arg; 19167761Smsmith acpi_sc = acpi_device_get_parent_softc(sc->button_dev); 192118783Snjl if (acpi_sc == NULL) 19369744Smsmith return_VOID; 19467761Smsmith 195121493Snjl acpi_UserNotify("Button", sc->button_handle, sc->button_type); 196121493Snjl 19767761Smsmith switch (sc->button_type) { 19867761Smsmith case ACPI_POWER_BUTTON: 19997274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "power button pressed\n"); 200125679Snjl acpi_event_power_button_sleep(acpi_sc); 20167761Smsmith break; 20267761Smsmith case ACPI_SLEEP_BUTTON: 20397274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "sleep button pressed\n"); 204125679Snjl acpi_event_sleep_button_sleep(acpi_sc); 20567761Smsmith break; 20667761Smsmith default: 20769744Smsmith break; /* unknown button type */ 20867761Smsmith } 20967761Smsmith} 21067761Smsmith 21167761Smsmithstatic void 212125679Snjlacpi_button_notify_wakeup(void *arg) 21367761Smsmith{ 21467761Smsmith struct acpi_button_softc *sc; 21567761Smsmith struct acpi_softc *acpi_sc; 21667761Smsmith 21796926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 21869744Smsmith 21967761Smsmith sc = (struct acpi_button_softc *)arg; 22067761Smsmith acpi_sc = acpi_device_get_parent_softc(sc->button_dev); 221118783Snjl if (acpi_sc == NULL) 22269744Smsmith return_VOID; 22367761Smsmith 224121493Snjl acpi_UserNotify("Button", sc->button_handle, sc->button_type); 225121493Snjl 22667761Smsmith switch (sc->button_type) { 22767761Smsmith case ACPI_POWER_BUTTON: 22897274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by power button\n"); 229125679Snjl acpi_event_power_button_wake(acpi_sc); 23067761Smsmith break; 23167761Smsmith case ACPI_SLEEP_BUTTON: 23297274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by sleep button\n"); 233125679Snjl acpi_event_sleep_button_wake(acpi_sc); 23467761Smsmith break; 23567761Smsmith default: 23669744Smsmith break; /* unknown button type */ 23767761Smsmith } 23867761Smsmith} 23967761Smsmith 24067761Smsmithstatic void 24167761Smsmithacpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 24267761Smsmith{ 243129692Snjl struct acpi_button_softc *sc; 24467761Smsmith 24596926Speter ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 24669744Smsmith 247129692Snjl sc = (struct acpi_button_softc *)context; 24867761Smsmith switch (notify) { 24967761Smsmith case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP: 250118783Snjl AcpiOsQueueForExecution(OSD_PRIORITY_LO, 251125679Snjl acpi_button_notify_sleep, sc); 25267761Smsmith break; 25367761Smsmith case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP: 254118783Snjl AcpiOsQueueForExecution(OSD_PRIORITY_LO, 255125679Snjl acpi_button_notify_wakeup, sc); 25667761Smsmith break; 25767761Smsmith default: 258129692Snjl device_printf(sc->button_dev, "unknown notify %#x\n", notify); 259129692Snjl break; 26067761Smsmith } 26167761Smsmith} 262120308Snjl 263120308Snjlstatic ACPI_STATUS 264120308Snjlacpi_button_fixed_handler(void *context) 265120308Snjl{ 266120308Snjl struct acpi_button_softc *sc = (struct acpi_button_softc *)context; 267120308Snjl 268120327Snjl ACPI_FUNCTION_TRACE_PTR((char *)(uintptr_t)__func__, context); 269120317Sphk 270120308Snjl if (context == NULL) 271120308Snjl return_ACPI_STATUS (AE_BAD_PARAMETER); 272120308Snjl 273120308Snjl acpi_button_notify_handler(sc->button_handle, 274120308Snjl ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP, sc); 275120327Snjl return_ACPI_STATUS (AE_OK); 276120308Snjl} 277