acpi_button.c revision 129879
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 129879 2004-05-30 20:08:47Z phk $ 2967761Smsmith */ 3067761Smsmith 3167761Smsmith#include "opt_acpi.h" 3267761Smsmith#include <sys/param.h> 3367761Smsmith#include <sys/kernel.h> 34129879Sphk#include <sys/module.h> 3567761Smsmith#include <sys/bus.h> 3667761Smsmith 3767761Smsmith#include "acpi.h" 3867761Smsmith#include <dev/acpica/acpivar.h> 3967761Smsmith 40118783Snjl/* Hooks for the ACPI CA debugging infrastructure */ 4177432Smsmith#define _COMPONENT ACPI_BUTTON 4291123SmsmithACPI_MODULE_NAME("BUTTON") 4369744Smsmith 4467761Smsmithstruct acpi_button_softc { 4567761Smsmith device_t button_dev; 4667761Smsmith ACPI_HANDLE button_handle; 47120308Snjl boolean_t button_type; 48118783Snjl#define ACPI_POWER_BUTTON 0 49118783Snjl#define ACPI_SLEEP_BUTTON 1 50120308Snjl boolean_t fixed; 5167761Smsmith}; 5267761Smsmith 53118783Snjl#define ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP 0x80 54118783Snjl#define ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP 0x02 55118783Snjl 5667761Smsmithstatic int acpi_button_probe(device_t dev); 5767761Smsmithstatic int acpi_button_attach(device_t dev); 58100497Siwasakistatic int acpi_button_suspend(device_t dev); 59100497Siwasakistatic int acpi_button_resume(device_t dev); 60118783Snjlstatic void acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, 61118783Snjl void *context); 62120308Snjlstatic ACPI_STATUS 63120308Snjl acpi_button_fixed_handler(void *context); 64125679Snjlstatic void acpi_button_notify_sleep(void *arg); 65125679Snjlstatic void acpi_button_notify_wakeup(void *arg); 6667761Smsmith 6767761Smsmithstatic device_method_t acpi_button_methods[] = { 6867761Smsmith /* Device interface */ 6967761Smsmith DEVMETHOD(device_probe, acpi_button_probe), 7067761Smsmith DEVMETHOD(device_attach, acpi_button_attach), 71100497Siwasaki DEVMETHOD(device_suspend, acpi_button_suspend), 72118049Stakawata DEVMETHOD(device_shutdown, acpi_button_suspend), 73100497Siwasaki DEVMETHOD(device_resume, acpi_button_resume), 7467761Smsmith 7567761Smsmith {0, 0} 7667761Smsmith}; 7767761Smsmith 7867761Smsmithstatic driver_t acpi_button_driver = { 7967761Smsmith "acpi_button", 8067761Smsmith acpi_button_methods, 8167761Smsmith sizeof(struct acpi_button_softc), 8267761Smsmith}; 8367761Smsmith 8489054Smsmithstatic devclass_t acpi_button_devclass; 85118783SnjlDRIVER_MODULE(acpi_button, acpi, acpi_button_driver, acpi_button_devclass, 86118783Snjl 0, 0); 87128071SnjlMODULE_DEPEND(acpi_button, acpi, 1, 1, 1); 8867761Smsmith 8967761Smsmithstatic int 9067761Smsmithacpi_button_probe(device_t dev) 9167761Smsmith{ 9267761Smsmith struct acpi_button_softc *sc; 93120308Snjl int ret = ENXIO; 9467761Smsmith 9567761Smsmith sc = device_get_softc(dev); 96120308Snjl if (acpi_get_type(dev) == ACPI_TYPE_DEVICE && !acpi_disabled("button")) { 97120308Snjl if (acpi_MatchHid(dev, "PNP0C0C")) { 98120308Snjl device_set_desc(dev, "Power Button"); 99120308Snjl sc->button_type = ACPI_POWER_BUTTON; 100120308Snjl ret = 0; 101120308Snjl } else if (acpi_MatchHid(dev, "ACPI_FPB")) { 102120308Snjl device_set_desc(dev, "Power Button (fixed)"); 103120308Snjl sc->button_type = ACPI_POWER_BUTTON; 104120308Snjl sc->fixed = 1; 105120308Snjl ret = 0; 106120308Snjl } else if (acpi_MatchHid(dev, "PNP0C0E")) { 107120308Snjl device_set_desc(dev, "Sleep Button"); 108120308Snjl sc->button_type = ACPI_SLEEP_BUTTON; 109120308Snjl ret = 0; 110120308Snjl } else if (acpi_MatchHid(dev, "ACPI_FSB")) { 111120308Snjl device_set_desc(dev, "Sleep Button (fixed)"); 112120308Snjl sc->button_type = ACPI_SLEEP_BUTTON; 113120308Snjl sc->fixed = 1; 114120308Snjl ret = 0; 11567761Smsmith } 11667761Smsmith } 117120308Snjl return (ret); 11867761Smsmith} 11967761Smsmith 12067761Smsmithstatic int 12167761Smsmithacpi_button_attach(device_t dev) 12267761Smsmith{ 12367761Smsmith struct acpi_button_softc *sc; 12467761Smsmith ACPI_STATUS status; 125120308Snjl int event; 12667761Smsmith 12796926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 12869744Smsmith 12967761Smsmith sc = device_get_softc(dev); 13067761Smsmith sc->button_dev = dev; 13167761Smsmith sc->button_handle = acpi_get_handle(dev); 132125679Snjl event = (sc->button_type == ACPI_SLEEP_BUTTON) ? 133125679Snjl ACPI_EVENT_SLEEP_BUTTON : ACPI_EVENT_POWER_BUTTON; 13467761Smsmith 135126014Snjl /* 136126014Snjl * Install the new handler. We could remove any fixed handlers added 137126014Snjl * from the FADT once we have a duplicate from the AML but some systems 138126014Snjl * only return events on one or the other so we have to keep both. 139126014Snjl */ 140120308Snjl if (sc->fixed) { 141125679Snjl AcpiClearEvent(event); 142120308Snjl status = AcpiInstallFixedEventHandler(event, 143120308Snjl acpi_button_fixed_handler, sc); 144120308Snjl } else { 145129692Snjl /* 146129692Snjl * If a system does not get lid events, it may make sense to change 147129692Snjl * the type to ACPI_ALL_NOTIFY. Some systems generate both a wake 148129692Snjl * and runtime notify in that case though. 149129692Snjl */ 150120308Snjl status = AcpiInstallNotifyHandler(sc->button_handle, 151120308Snjl ACPI_DEVICE_NOTIFY, acpi_button_notify_handler, sc); 152120308Snjl } 153118783Snjl if (ACPI_FAILURE(status)) { 154120308Snjl device_printf(sc->button_dev, "couldn't install notify handler - %s\n", 155118783Snjl AcpiFormatException(status)); 156118783Snjl return_VALUE (ENXIO); 15767761Smsmith } 158125679Snjl 159129783Snjl /* Enable the GPE for wake/runtime. */ 160129783Snjl acpi_wake_init(dev, ACPI_GPE_TYPE_WAKE_RUN); 161129783Snjl acpi_wake_set_enable(dev, 1); 162129783Snjl 163118783Snjl return_VALUE (0); 16467761Smsmith} 16567761Smsmith 166100497Siwasakistatic int 167100497Siwasakiacpi_button_suspend(device_t dev) 168100497Siwasaki{ 169129783Snjl struct acpi_softc *acpi_sc; 170100497Siwasaki 171129783Snjl acpi_sc = acpi_device_get_parent_softc(dev); 172129783Snjl acpi_wake_sleep_prep(dev, acpi_sc->acpi_sstate); 173100497Siwasaki return (0); 174100497Siwasaki} 175100497Siwasaki 176100497Siwasakistatic int 177100497Siwasakiacpi_button_resume(device_t dev) 178100497Siwasaki{ 179129805Snjl acpi_wake_run_prep(dev); 180100497Siwasaki return (0); 181100497Siwasaki} 182100497Siwasaki 18367761Smsmithstatic void 184125679Snjlacpi_button_notify_sleep(void *arg) 18567761Smsmith{ 18667761Smsmith struct acpi_button_softc *sc; 18767761Smsmith struct acpi_softc *acpi_sc; 18867761Smsmith 18996926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 19069744Smsmith 19167761Smsmith sc = (struct acpi_button_softc *)arg; 19267761Smsmith acpi_sc = acpi_device_get_parent_softc(sc->button_dev); 193118783Snjl if (acpi_sc == NULL) 19469744Smsmith return_VOID; 19567761Smsmith 196121493Snjl acpi_UserNotify("Button", sc->button_handle, sc->button_type); 197121493Snjl 19867761Smsmith switch (sc->button_type) { 19967761Smsmith case ACPI_POWER_BUTTON: 20097274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "power button pressed\n"); 201125679Snjl acpi_event_power_button_sleep(acpi_sc); 20267761Smsmith break; 20367761Smsmith case ACPI_SLEEP_BUTTON: 20497274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "sleep button pressed\n"); 205125679Snjl acpi_event_sleep_button_sleep(acpi_sc); 20667761Smsmith break; 20767761Smsmith default: 20869744Smsmith break; /* unknown button type */ 20967761Smsmith } 21067761Smsmith} 21167761Smsmith 21267761Smsmithstatic void 213125679Snjlacpi_button_notify_wakeup(void *arg) 21467761Smsmith{ 21567761Smsmith struct acpi_button_softc *sc; 21667761Smsmith struct acpi_softc *acpi_sc; 21767761Smsmith 21896926Speter ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 21969744Smsmith 22067761Smsmith sc = (struct acpi_button_softc *)arg; 22167761Smsmith acpi_sc = acpi_device_get_parent_softc(sc->button_dev); 222118783Snjl if (acpi_sc == NULL) 22369744Smsmith return_VOID; 22467761Smsmith 225121493Snjl acpi_UserNotify("Button", sc->button_handle, sc->button_type); 226121493Snjl 22767761Smsmith switch (sc->button_type) { 22867761Smsmith case ACPI_POWER_BUTTON: 22997274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by power button\n"); 230125679Snjl acpi_event_power_button_wake(acpi_sc); 23167761Smsmith break; 23267761Smsmith case ACPI_SLEEP_BUTTON: 23397274Sbde ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by sleep button\n"); 234125679Snjl acpi_event_sleep_button_wake(acpi_sc); 23567761Smsmith break; 23667761Smsmith default: 23769744Smsmith break; /* unknown button type */ 23867761Smsmith } 23967761Smsmith} 24067761Smsmith 24167761Smsmithstatic void 24267761Smsmithacpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 24367761Smsmith{ 244129692Snjl struct acpi_button_softc *sc; 24567761Smsmith 24696926Speter ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 24769744Smsmith 248129692Snjl sc = (struct acpi_button_softc *)context; 24967761Smsmith switch (notify) { 25067761Smsmith case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP: 251118783Snjl AcpiOsQueueForExecution(OSD_PRIORITY_LO, 252125679Snjl acpi_button_notify_sleep, sc); 25367761Smsmith break; 25467761Smsmith case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP: 255118783Snjl AcpiOsQueueForExecution(OSD_PRIORITY_LO, 256125679Snjl acpi_button_notify_wakeup, sc); 25767761Smsmith break; 25867761Smsmith default: 259129692Snjl device_printf(sc->button_dev, "unknown notify %#x\n", notify); 260129692Snjl break; 26167761Smsmith } 26267761Smsmith} 263120308Snjl 264120308Snjlstatic ACPI_STATUS 265120308Snjlacpi_button_fixed_handler(void *context) 266120308Snjl{ 267120308Snjl struct acpi_button_softc *sc = (struct acpi_button_softc *)context; 268120308Snjl 269120327Snjl ACPI_FUNCTION_TRACE_PTR((char *)(uintptr_t)__func__, context); 270120317Sphk 271120308Snjl if (context == NULL) 272120308Snjl return_ACPI_STATUS (AE_BAD_PARAMETER); 273120308Snjl 274120308Snjl acpi_button_notify_handler(sc->button_handle, 275120308Snjl ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP, sc); 276120327Snjl return_ACPI_STATUS (AE_OK); 277120308Snjl} 278