acpi_button.c revision 131282
1295367Sdes/*- 257429Smarkm * Copyright (c) 2000 Mitsaru IWASAKI <iwasaki@jp.freebsd.org> 357429Smarkm * Copyright (c) 2000 Michael Smith <msmith@freebsd.org> 457429Smarkm * Copyright (c) 2000 BSDi 557429Smarkm * All rights reserved. 657429Smarkm * 757429Smarkm * Redistribution and use in source and binary forms, with or without 857429Smarkm * modification, are permitted provided that the following conditions 960576Skris * are met: 1065674Skris * 1. Redistributions of source code must retain the above copyright 1165674Skris * notice, this list of conditions and the following disclaimer. 1265674Skris * 2. Redistributions in binary form must reproduce the above copyright 1365674Skris * notice, this list of conditions and the following disclaimer in the 1465674Skris * documentation and/or other materials provided with the distribution. 1557429Smarkm * 1657429Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1757429Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1857429Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19295367Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20295367Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21162856Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22162856Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23162856Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2476262Sgreen * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2576262Sgreen * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26162856Sdes * SUCH DAMAGE. 27162856Sdes * 28162856Sdes * $FreeBSD: head/sys/dev/acpica/acpi_button.c 131282 2004-06-29 19:02:27Z njl $ 29162856Sdes */ 30162856Sdes 31162856Sdes#include "opt_acpi.h" 3257429Smarkm#include <sys/param.h> 3357429Smarkm#include <sys/kernel.h> 3476262Sgreen#include <sys/module.h> 3557429Smarkm#include <sys/bus.h> 3658585Skris 37162856Sdes#include "acpi.h" 3876262Sgreen#include <dev/acpica/acpivar.h> 3976262Sgreen 40295367Sdes/* Hooks for the ACPI CA debugging infrastructure */ 4157429Smarkm#define _COMPONENT ACPI_BUTTON 42162856SdesACPI_MODULE_NAME("BUTTON") 43215116Sdes 44162856Sdesstruct acpi_button_softc { 4576262Sgreen device_t button_dev; 46162856Sdes ACPI_HANDLE button_handle; 47162856Sdes boolean_t button_type; 48162856Sdes#define ACPI_POWER_BUTTON 0 4998684Sdes#define ACPI_SLEEP_BUTTON 1 5098684Sdes boolean_t fixed; 5157429Smarkm}; 52264377Sdes 53264377Sdes#define ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP 0x80 5469591Sgreen#define ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP 0x02 5569591Sgreen 5669591Sgreenstatic int acpi_button_probe(device_t dev); 5757429Smarkmstatic int acpi_button_attach(device_t dev); 5857429Smarkmstatic int acpi_button_suspend(device_t dev); 5957429Smarkmstatic int acpi_button_resume(device_t dev); 6057429Smarkmstatic void acpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, 6176262Sgreen void *context); 6257429Smarkmstatic ACPI_STATUS 6357429Smarkm acpi_button_fixed_handler(void *context); 6457429Smarkmstatic void acpi_button_notify_sleep(void *arg); 6557429Smarkmstatic void acpi_button_notify_wakeup(void *arg); 6657429Smarkm 6757429Smarkmstatic char *btn_ids[] = { 6857429Smarkm "PNP0C0C", "ACPI_FPB", "PNP0C0E", "ACPI_FSB", 69147005Sdes NULL 7057429Smarkm}; 7157429Smarkm 7257429Smarkmstatic device_method_t acpi_button_methods[] = { 7398684Sdes /* Device interface */ 7498684Sdes DEVMETHOD(device_probe, acpi_button_probe), 7598684Sdes DEVMETHOD(device_attach, acpi_button_attach), 7698684Sdes DEVMETHOD(device_suspend, acpi_button_suspend), 7798684Sdes DEVMETHOD(device_shutdown, acpi_button_suspend), 7898684Sdes DEVMETHOD(device_resume, acpi_button_resume), 7998684Sdes 8098684Sdes {0, 0} 8198684Sdes}; 82164149Sdes 83164149Sdesstatic driver_t acpi_button_driver = { 8498684Sdes "acpi_button", 85164149Sdes acpi_button_methods, 86164149Sdes sizeof(struct acpi_button_softc), 87164149Sdes}; 8898684Sdes 8998684Sdesstatic devclass_t acpi_button_devclass; 9098684SdesDRIVER_MODULE(acpi_button, acpi, acpi_button_driver, acpi_button_devclass, 9198684Sdes 0, 0); 9298684SdesMODULE_DEPEND(acpi_button, acpi, 1, 1, 1); 9398684Sdes 9498684Sdesstatic int 9598684Sdesacpi_button_probe(device_t dev) 9698684Sdes{ 97264377Sdes struct acpi_button_softc *sc; 9898684Sdes char *str; 9998684Sdes 10098684Sdes if (acpi_disabled("button") || 10198684Sdes (str = ACPI_ID_PROBE(device_get_parent(dev), dev, btn_ids)) == NULL) 102264377Sdes return (ENXIO); 103264377Sdes 10498684Sdes sc = device_get_softc(dev); 10598684Sdes if (strcmp(str, "PNP0C0C") == 0) { 10698684Sdes device_set_desc(dev, "Power Button"); 10798684Sdes sc->button_type = ACPI_POWER_BUTTON; 10898684Sdes } else if (strcmp(str, "ACPI_FPB") == 0) { 10998684Sdes device_set_desc(dev, "Power Button (fixed)"); 11098684Sdes sc->button_type = ACPI_POWER_BUTTON; 111264377Sdes sc->fixed = 1; 11298684Sdes } else if (strcmp(str, "PNP0C0E") == 0) { 11398684Sdes device_set_desc(dev, "Sleep Button"); 114264377Sdes sc->button_type = ACPI_SLEEP_BUTTON; 115264377Sdes } else if (strcmp(str, "ACPI_FSB") == 0) { 116264377Sdes device_set_desc(dev, "Sleep Button (fixed)"); 117264377Sdes sc->button_type = ACPI_SLEEP_BUTTON; 118264377Sdes sc->fixed = 1; 119264377Sdes } 12098684Sdes 12198684Sdes return (0); 122215116Sdes} 12398684Sdes 12498684Sdesstatic int 12598684Sdesacpi_button_attach(device_t dev) 12698684Sdes{ 12798684Sdes struct acpi_button_softc *sc; 12898684Sdes ACPI_STATUS status; 12998684Sdes int event; 13057429Smarkm 13157429Smarkm ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 13257429Smarkm 13357429Smarkm sc = device_get_softc(dev); 13457429Smarkm sc->button_dev = dev; 13557429Smarkm sc->button_handle = acpi_get_handle(dev); 13657429Smarkm event = (sc->button_type == ACPI_SLEEP_BUTTON) ? 13798684Sdes ACPI_EVENT_SLEEP_BUTTON : ACPI_EVENT_POWER_BUTTON; 13857429Smarkm 13957429Smarkm /* 14098684Sdes * Install the new handler. We could remove any fixed handlers added 14198684Sdes * from the FADT once we have a duplicate from the AML but some systems 14257429Smarkm * only return events on one or the other so we have to keep both. 14392559Sdes */ 14492559Sdes if (sc->fixed) { 14557429Smarkm AcpiClearEvent(event); 14698684Sdes status = AcpiInstallFixedEventHandler(event, 14757429Smarkm acpi_button_fixed_handler, sc); 14857429Smarkm } else { 149295367Sdes /* 150295367Sdes * If a system does not get lid events, it may make sense to change 15157429Smarkm * the type to ACPI_ALL_NOTIFY. Some systems generate both a wake 15257429Smarkm * and runtime notify in that case though. 15357429Smarkm */ 15457429Smarkm status = AcpiInstallNotifyHandler(sc->button_handle, 15557429Smarkm ACPI_DEVICE_NOTIFY, acpi_button_notify_handler, sc); 15657429Smarkm } 15757429Smarkm if (ACPI_FAILURE(status)) { 15857429Smarkm device_printf(sc->button_dev, "couldn't install notify handler - %s\n", 15957429Smarkm AcpiFormatException(status)); 16092559Sdes return_VALUE (ENXIO); 16157429Smarkm } 162162856Sdes 16392559Sdes /* Enable the GPE for wake/runtime. */ 16457429Smarkm acpi_wake_init(dev, ACPI_GPE_TYPE_WAKE_RUN); 16598684Sdes acpi_wake_set_enable(dev, 1); 16657429Smarkm 16798684Sdes return_VALUE (0); 16857429Smarkm} 16957429Smarkm 170226046Sdesstatic int 171226046Sdesacpi_button_suspend(device_t dev) 172226046Sdes{ 17357429Smarkm struct acpi_softc *acpi_sc; 174255767Sdes 175255767Sdes acpi_sc = acpi_device_get_parent_softc(dev); 17657429Smarkm acpi_wake_sleep_prep(dev, acpi_sc->acpi_sstate); 17776262Sgreen return (0); 17892559Sdes} 17957429Smarkm 18092559Sdesstatic int 181226046Sdesacpi_button_resume(device_t dev) 182226046Sdes{ 18357429Smarkm acpi_wake_run_prep(dev); 18457429Smarkm return (0); 18557429Smarkm} 18657429Smarkm 18757429Smarkmstatic void 18857429Smarkmacpi_button_notify_sleep(void *arg) 189226046Sdes{ 190147005Sdes struct acpi_button_softc *sc; 19157429Smarkm struct acpi_softc *acpi_sc; 192137019Sdes 193149753Sdes ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 19457429Smarkm 19557429Smarkm sc = (struct acpi_button_softc *)arg; 19657429Smarkm acpi_sc = acpi_device_get_parent_softc(sc->button_dev); 19757429Smarkm if (acpi_sc == NULL) 19857429Smarkm return_VOID; 19957429Smarkm 20057429Smarkm acpi_UserNotify("Button", sc->button_handle, sc->button_type); 20157429Smarkm 20257429Smarkm switch (sc->button_type) { 20357429Smarkm case ACPI_POWER_BUTTON: 20457429Smarkm ACPI_VPRINT(sc->button_dev, acpi_sc, "power button pressed\n"); 20557429Smarkm acpi_event_power_button_sleep(acpi_sc); 20657429Smarkm break; 20757429Smarkm case ACPI_SLEEP_BUTTON: 20857429Smarkm ACPI_VPRINT(sc->button_dev, acpi_sc, "sleep button pressed\n"); 209137019Sdes acpi_event_sleep_button_sleep(acpi_sc); 21057429Smarkm break; 21157429Smarkm default: 21257429Smarkm break; /* unknown button type */ 21357429Smarkm } 21457429Smarkm} 21557429Smarkm 21657429Smarkmstatic void 217137019Sdesacpi_button_notify_wakeup(void *arg) 21857429Smarkm{ 21957429Smarkm struct acpi_button_softc *sc; 22092559Sdes struct acpi_softc *acpi_sc; 22192559Sdes 22276262Sgreen ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); 22357429Smarkm 22457429Smarkm sc = (struct acpi_button_softc *)arg; 22557429Smarkm acpi_sc = acpi_device_get_parent_softc(sc->button_dev); 22657429Smarkm if (acpi_sc == NULL) 227226046Sdes return_VOID; 228226046Sdes 229226046Sdes acpi_UserNotify("Button", sc->button_handle, sc->button_type); 230226046Sdes 23192559Sdes switch (sc->button_type) { 23257429Smarkm case ACPI_POWER_BUTTON: 23357429Smarkm ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by power button\n"); 23457429Smarkm acpi_event_power_button_wake(acpi_sc); 235149753Sdes break; 236255767Sdes case ACPI_SLEEP_BUTTON: 237124211Sdes ACPI_VPRINT(sc->button_dev, acpi_sc, "wakeup by sleep button\n"); 23857429Smarkm acpi_event_sleep_button_wake(acpi_sc); 23992559Sdes break; 24057429Smarkm default: 241295367Sdes break; /* unknown button type */ 242295367Sdes } 243295367Sdes} 244255767Sdes 245255767Sdesstatic void 246255767Sdesacpi_button_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 247255767Sdes{ 248221420Sdes struct acpi_button_softc *sc; 249221420Sdes 250221420Sdes ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, notify); 251221420Sdes 25257429Smarkm sc = (struct acpi_button_softc *)context; 25376262Sgreen switch (notify) { 25476262Sgreen case ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP: 25576262Sgreen AcpiOsQueueForExecution(OSD_PRIORITY_LO, 25676262Sgreen acpi_button_notify_sleep, sc); 257137019Sdes break; 25876262Sgreen case ACPI_NOTIFY_BUTTON_PRESSED_FOR_WAKEUP: 259215116Sdes AcpiOsQueueForExecution(OSD_PRIORITY_LO, 260215116Sdes acpi_button_notify_wakeup, sc); 26198684Sdes break; 26298684Sdes default: 26369591Sgreen device_printf(sc->button_dev, "unknown notify %#x\n", notify); 26457429Smarkm break; 26557429Smarkm } 26657429Smarkm} 26757429Smarkm 26857429Smarkmstatic ACPI_STATUS 26998684Sdesacpi_button_fixed_handler(void *context) 27098684Sdes{ 27198684Sdes struct acpi_button_softc *sc = (struct acpi_button_softc *)context; 27298684Sdes 27398684Sdes ACPI_FUNCTION_TRACE_PTR((char *)(uintptr_t)__func__, context); 274226046Sdes 275226046Sdes if (context == NULL) 27698684Sdes return_ACPI_STATUS (AE_BAD_PARAMETER); 27757429Smarkm 27898684Sdes acpi_button_notify_handler(sc->button_handle, 279226046Sdes ACPI_NOTIFY_BUTTON_PRESSED_FOR_SLEEP, sc); 280226046Sdes return_ACPI_STATUS (AE_OK); 281226046Sdes} 282226046Sdes