acpi_lid.c revision 1.35
11.35Sjruoho/* $NetBSD: acpi_lid.c,v 1.35 2010/02/28 17:22:41 jruoho Exp $ */ 21.1Sthorpej 31.1Sthorpej/* 41.7Sthorpej * Copyright 2001, 2003 Wasabi Systems, Inc. 51.1Sthorpej * All rights reserved. 61.1Sthorpej * 71.1Sthorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc. 81.1Sthorpej * 91.1Sthorpej * Redistribution and use in source and binary forms, with or without 101.1Sthorpej * modification, are permitted provided that the following conditions 111.1Sthorpej * are met: 121.1Sthorpej * 1. Redistributions of source code must retain the above copyright 131.1Sthorpej * notice, this list of conditions and the following disclaimer. 141.1Sthorpej * 2. Redistributions in binary form must reproduce the above copyright 151.1Sthorpej * notice, this list of conditions and the following disclaimer in the 161.1Sthorpej * documentation and/or other materials provided with the distribution. 171.1Sthorpej * 3. All advertising materials mentioning features or use of this software 181.1Sthorpej * must display the following acknowledgement: 191.1Sthorpej * This product includes software developed for the NetBSD Project by 201.1Sthorpej * Wasabi Systems, Inc. 211.1Sthorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse 221.1Sthorpej * or promote products derived from this software without specific prior 231.1Sthorpej * written permission. 241.1Sthorpej * 251.1Sthorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 261.1Sthorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 271.1Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 281.1Sthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 291.1Sthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 301.1Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 311.1Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 321.1Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 331.1Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 341.1Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 351.1Sthorpej * POSSIBILITY OF SUCH DAMAGE. 361.1Sthorpej */ 371.1Sthorpej 381.1Sthorpej/* 391.1Sthorpej * ACPI Lid Switch driver. 401.1Sthorpej */ 411.3Slukem 421.3Slukem#include <sys/cdefs.h> 431.35Sjruoho__KERNEL_RCSID(0, "$NetBSD: acpi_lid.c,v 1.35 2010/02/28 17:22:41 jruoho Exp $"); 441.1Sthorpej 451.1Sthorpej#include <sys/param.h> 461.1Sthorpej#include <sys/systm.h> 471.1Sthorpej#include <sys/device.h> 481.35Sjruoho#include <sys/module.h> 491.1Sthorpej 501.1Sthorpej#include <dev/acpi/acpica.h> 511.1Sthorpej#include <dev/acpi/acpireg.h> 521.1Sthorpej#include <dev/acpi/acpivar.h> 531.1Sthorpej 541.7Sthorpej#include <dev/sysmon/sysmonvar.h> 551.7Sthorpej 561.34Sjruoho#define _COMPONENT ACPI_LID_COMPONENT 571.34SjruohoACPI_MODULE_NAME ("acpi_lid") 581.32Sjruoho 591.1Sthorpejstruct acpilid_softc { 601.34Sjruoho struct acpi_devnode *sc_node; 611.34Sjruoho struct sysmon_pswitch sc_smpsw; 621.34Sjruoho uint64_t sc_status; 631.1Sthorpej}; 641.1Sthorpej 651.10Skochistatic const char * const lid_hid[] = { 661.10Skochi "PNP0C0D", 671.10Skochi NULL 681.10Skochi}; 691.10Skochi 701.25Sxtraemestatic int acpilid_match(device_t, cfdata_t, void *); 711.25Sxtraemestatic void acpilid_attach(device_t, device_t, void *); 721.26Sdyoungstatic int acpilid_detach(device_t, int); 731.15Skochistatic void acpilid_status_changed(void *); 741.18Skochistatic void acpilid_notify_handler(ACPI_HANDLE, UINT32, void *); 751.25Sxtraemestatic void acpilid_wake_event(device_t, bool); 761.33Sdyoungstatic bool acpilid_suspend(device_t, const pmf_qual_t *); 771.22Sjmcneill 781.34SjruohoCFATTACH_DECL_NEW(acpilid, sizeof(struct acpilid_softc), 791.34Sjruoho acpilid_match, acpilid_attach, acpilid_detach, NULL); 801.34Sjruoho 811.1Sthorpej/* 821.1Sthorpej * acpilid_match: 831.1Sthorpej * 841.1Sthorpej * Autoconfiguration `match' routine. 851.1Sthorpej */ 861.15Skochistatic int 871.25Sxtraemeacpilid_match(device_t parent, cfdata_t match, void *aux) 881.1Sthorpej{ 891.1Sthorpej struct acpi_attach_args *aa = aux; 901.1Sthorpej 911.1Sthorpej if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) 921.14Skochi return 0; 931.1Sthorpej 941.14Skochi return acpi_match_hid(aa->aa_node->ad_devinfo, lid_hid); 951.1Sthorpej} 961.1Sthorpej 971.1Sthorpej/* 981.1Sthorpej * acpilid_attach: 991.1Sthorpej * 1001.1Sthorpej * Autoconfiguration `attach' routine. 1011.1Sthorpej */ 1021.15Skochistatic void 1031.25Sxtraemeacpilid_attach(device_t parent, device_t self, void *aux) 1041.1Sthorpej{ 1051.25Sxtraeme struct acpilid_softc *sc = device_private(self); 1061.1Sthorpej struct acpi_attach_args *aa = aux; 1071.1Sthorpej ACPI_STATUS rv; 1081.1Sthorpej 1091.19Skochi aprint_naive(": ACPI Lid Switch\n"); 1101.19Skochi aprint_normal(": ACPI Lid Switch\n"); 1111.1Sthorpej 1121.1Sthorpej sc->sc_node = aa->aa_node; 1131.1Sthorpej 1141.25Sxtraeme sc->sc_smpsw.smpsw_name = device_xname(self); 1151.8Sthorpej sc->sc_smpsw.smpsw_type = PSWITCH_TYPE_LID; 1161.34Sjruoho 1171.34Sjruoho (void)sysmon_pswitch_register(&sc->sc_smpsw); 1181.34Sjruoho (void)pmf_device_register(self, acpilid_suspend, NULL); 1191.7Sthorpej 1201.1Sthorpej rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle, 1211.25Sxtraeme ACPI_DEVICE_NOTIFY, acpilid_notify_handler, self); 1221.16Skochi 1231.34Sjruoho if (ACPI_FAILURE(rv)) 1241.34Sjruoho aprint_error_dev(self, "failed to register notify handler\n"); 1251.22Sjmcneill} 1261.22Sjmcneill 1271.26Sdyoungstatic int 1281.26Sdyoungacpilid_detach(device_t self, int flags) 1291.26Sdyoung{ 1301.26Sdyoung struct acpilid_softc *sc = device_private(self); 1311.26Sdyoung ACPI_STATUS rv; 1321.26Sdyoung 1331.26Sdyoung rv = AcpiRemoveNotifyHandler(sc->sc_node->ad_handle, 1341.26Sdyoung ACPI_DEVICE_NOTIFY, acpilid_notify_handler); 1351.34Sjruoho 1361.34Sjruoho if (ACPI_FAILURE(rv)) 1371.26Sdyoung return EBUSY; 1381.26Sdyoung 1391.26Sdyoung pmf_device_deregister(self); 1401.26Sdyoung sysmon_pswitch_unregister(&sc->sc_smpsw); 1411.26Sdyoung 1421.26Sdyoung return 0; 1431.26Sdyoung} 1441.26Sdyoung 1451.22Sjmcneillstatic void 1461.25Sxtraemeacpilid_wake_event(device_t dv, bool enable) 1471.22Sjmcneill{ 1481.25Sxtraeme struct acpilid_softc *sc = device_private(dv); 1491.30Sjruoho ACPI_OBJECT_LIST arg; 1501.30Sjruoho ACPI_OBJECT obj[3]; 1511.30Sjruoho ACPI_STATUS rv; 1521.30Sjruoho 1531.30Sjruoho /* 1541.30Sjruoho * First try to call the Device Sleep Wake control method, _DSW. 1551.30Sjruoho * Only if this is not available, resort to to the Power State 1561.30Sjruoho * Wake control method, _PSW, which was deprecated in ACPI 3.0. 1571.30Sjruoho */ 1581.30Sjruoho obj[0].Integer.Value = enable ? 1 : 0; 1591.30Sjruoho obj[1].Integer.Value = obj[2].Integer.Value = 0; 1601.30Sjruoho obj[0].Type = obj[1].Type = obj[2].Type = ACPI_TYPE_INTEGER; 1611.30Sjruoho 1621.30Sjruoho arg.Count = 3; 1631.30Sjruoho arg.Pointer = obj; 1641.30Sjruoho 1651.30Sjruoho rv = AcpiEvaluateObject(sc->sc_node->ad_handle, "_DSW", &arg, NULL); 1661.30Sjruoho 1671.30Sjruoho if (ACPI_SUCCESS(rv)) 1681.30Sjruoho return; 1691.25Sxtraeme 1701.30Sjruoho if (rv != AE_NOT_FOUND) 1711.30Sjruoho goto fail; 1721.22Sjmcneill 1731.29Scegger rv = acpi_eval_set_integer(sc->sc_node->ad_handle, "_PSW", 1741.29Scegger enable ? 1 : 0); 1751.30Sjruoho 1761.22Sjmcneill if (ACPI_FAILURE(rv) && rv != AE_NOT_FOUND) 1771.30Sjruoho goto fail; 1781.30Sjruoho 1791.30Sjruoho return; 1801.30Sjruoho 1811.30Sjruohofail: 1821.30Sjruoho aprint_error_dev(dv, "unable to evaluate wake control method: %s\n", 1831.30Sjruoho AcpiFormatException(rv)); 1841.1Sthorpej} 1851.1Sthorpej 1861.1Sthorpej/* 1871.1Sthorpej * acpilid_status_changed: 1881.1Sthorpej * 1891.1Sthorpej * Get, and possibly display, the lid status, and take action. 1901.1Sthorpej */ 1911.15Skochistatic void 1921.1Sthorpejacpilid_status_changed(void *arg) 1931.1Sthorpej{ 1941.34Sjruoho device_t dv = arg; 1951.34Sjruoho struct acpilid_softc *sc = device_private(dv); 1961.12Smycroft ACPI_STATUS rv; 1971.1Sthorpej 1981.34Sjruoho rv = acpi_eval_integer(sc->sc_node->ad_handle, "_LID", &sc->sc_status); 1991.34Sjruoho 2001.12Smycroft if (ACPI_FAILURE(rv)) 2011.1Sthorpej return; 2021.1Sthorpej 2031.34Sjruoho sysmon_pswitch_event(&sc->sc_smpsw, (sc->sc_status == 0) ? 2041.8Sthorpej PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED); 2051.1Sthorpej} 2061.1Sthorpej 2071.1Sthorpej/* 2081.1Sthorpej * acpilid_notify_handler: 2091.1Sthorpej * 2101.1Sthorpej * Callback from ACPI interrupt handler to notify us of an event. 2111.1Sthorpej */ 2121.15Skochistatic void 2131.34Sjruohoacpilid_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *context) 2141.1Sthorpej{ 2151.34Sjruoho static const int handler = OSL_NOTIFY_HANDLER; 2161.25Sxtraeme device_t dv = context; 2171.1Sthorpej 2181.1Sthorpej switch (notify) { 2191.34Sjruoho 2201.1Sthorpej case ACPI_NOTIFY_LidStatusChanged: 2211.34Sjruoho (void)AcpiOsExecute(handler, acpilid_status_changed, dv); 2221.1Sthorpej break; 2231.1Sthorpej 2241.1Sthorpej default: 2251.34Sjruoho aprint_error_dev(dv, "unknown notify 0x%02X\n", notify); 2261.1Sthorpej } 2271.1Sthorpej} 2281.22Sjmcneill 2291.22Sjmcneillstatic bool 2301.33Sdyoungacpilid_suspend(device_t dv, const pmf_qual_t *qual) 2311.22Sjmcneill{ 2321.22Sjmcneill struct acpilid_softc *sc = device_private(dv); 2331.22Sjmcneill 2341.34Sjruoho acpilid_wake_event(dv, sc->sc_status == 0); 2351.22Sjmcneill 2361.22Sjmcneill return true; 2371.22Sjmcneill} 2381.35Sjruoho 2391.35Sjruoho#ifdef _MODULE 2401.35Sjruoho 2411.35SjruohoMODULE(MODULE_CLASS_DRIVER, acpilid, NULL); 2421.35SjruohoCFDRIVER_DECL(acpilid, DV_DULL, NULL); 2431.35Sjruoho 2441.35Sjruohostatic int acpilidloc[] = { -1 }; 2451.35Sjruohoextern struct cfattach acpilid_ca; 2461.35Sjruoho 2471.35Sjruohostatic struct cfparent acpiparent = { 2481.35Sjruoho "acpinodebus", NULL, DVUNIT_ANY 2491.35Sjruoho}; 2501.35Sjruoho 2511.35Sjruohostatic struct cfdata acpilid_cfdata[] = { 2521.35Sjruoho { 2531.35Sjruoho .cf_name = "acpilid", 2541.35Sjruoho .cf_atname = "acpilid", 2551.35Sjruoho .cf_unit = 0, 2561.35Sjruoho .cf_fstate = FSTATE_STAR, 2571.35Sjruoho .cf_loc = acpilidloc, 2581.35Sjruoho .cf_flags = 0, 2591.35Sjruoho .cf_pspec = &acpiparent, 2601.35Sjruoho }, 2611.35Sjruoho 2621.35Sjruoho { NULL } 2631.35Sjruoho}; 2641.35Sjruoho 2651.35Sjruohostatic int 2661.35Sjruohoacpilid_modcmd(modcmd_t cmd, void *context) 2671.35Sjruoho{ 2681.35Sjruoho int err; 2691.35Sjruoho 2701.35Sjruoho switch (cmd) { 2711.35Sjruoho 2721.35Sjruoho case MODULE_CMD_INIT: 2731.35Sjruoho 2741.35Sjruoho err = config_cfdriver_attach(&acpilid_cd); 2751.35Sjruoho 2761.35Sjruoho if (err != 0) 2771.35Sjruoho return err; 2781.35Sjruoho 2791.35Sjruoho err = config_cfattach_attach("acpilid", &acpilid_ca); 2801.35Sjruoho 2811.35Sjruoho if (err != 0) { 2821.35Sjruoho config_cfdriver_detach(&acpilid_cd); 2831.35Sjruoho return err; 2841.35Sjruoho } 2851.35Sjruoho 2861.35Sjruoho err = config_cfdata_attach(acpilid_cfdata, 1); 2871.35Sjruoho 2881.35Sjruoho if (err != 0) { 2891.35Sjruoho config_cfattach_detach("acpilid", &acpilid_ca); 2901.35Sjruoho config_cfdriver_detach(&acpilid_cd); 2911.35Sjruoho return err; 2921.35Sjruoho } 2931.35Sjruoho 2941.35Sjruoho return 0; 2951.35Sjruoho 2961.35Sjruoho case MODULE_CMD_FINI: 2971.35Sjruoho 2981.35Sjruoho err = config_cfdata_detach(acpilid_cfdata); 2991.35Sjruoho 3001.35Sjruoho if (err != 0) 3011.35Sjruoho return err; 3021.35Sjruoho 3031.35Sjruoho config_cfattach_detach("acpilid", &acpilid_ca); 3041.35Sjruoho config_cfdriver_detach(&acpilid_cd); 3051.35Sjruoho 3061.35Sjruoho return 0; 3071.35Sjruoho 3081.35Sjruoho default: 3091.35Sjruoho return ENOTTY; 3101.35Sjruoho } 3111.35Sjruoho} 3121.35Sjruoho 3131.35Sjruoho#endif /* _MODULE */ 314