Home | History | Annotate | Line # | Download | only in acpi
      1 /*	$NetBSD: acpi_lid.c,v 1.45 2021/01/29 15:49:55 thorpej Exp $	*/
      2 
      3 /*
      4  * Copyright 2001, 2003 Wasabi Systems, Inc.
      5  * All rights reserved.
      6  *
      7  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
      8  *
      9  * Redistribution and use in source and binary forms, with or without
     10  * modification, are permitted provided that the following conditions
     11  * are met:
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  * 2. Redistributions in binary form must reproduce the above copyright
     15  *    notice, this list of conditions and the following disclaimer in the
     16  *    documentation and/or other materials provided with the distribution.
     17  * 3. All advertising materials mentioning features or use of this software
     18  *    must display the following acknowledgement:
     19  *	This product includes software developed for the NetBSD Project by
     20  *	Wasabi Systems, Inc.
     21  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
     22  *    or promote products derived from this software without specific prior
     23  *    written permission.
     24  *
     25  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
     26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
     29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     35  * POSSIBILITY OF SUCH DAMAGE.
     36  */
     37 
     38 /*
     39  * ACPI Lid Switch driver.
     40  */
     41 
     42 #include <sys/cdefs.h>
     43 __KERNEL_RCSID(0, "$NetBSD: acpi_lid.c,v 1.45 2021/01/29 15:49:55 thorpej Exp $");
     44 
     45 #include <sys/param.h>
     46 #include <sys/device.h>
     47 #include <sys/module.h>
     48 #include <sys/systm.h>
     49 
     50 #include <dev/acpi/acpireg.h>
     51 #include <dev/acpi/acpivar.h>
     52 
     53 #define _COMPONENT		 ACPI_LID_COMPONENT
     54 ACPI_MODULE_NAME		 ("acpi_lid")
     55 
     56 #define ACPI_NOTIFY_LID		 0x80
     57 
     58 struct acpilid_softc {
     59 	struct acpi_devnode	*sc_node;
     60 	struct sysmon_pswitch	 sc_smpsw;
     61 	uint64_t		 sc_status;
     62 };
     63 
     64 static const struct device_compatible_entry compat_data[] = {
     65 	{ .compat = "PNP0C0D" },
     66 	DEVICE_COMPAT_EOL
     67 };
     68 
     69 static int	acpilid_match(device_t, cfdata_t, void *);
     70 static void	acpilid_attach(device_t, device_t, void *);
     71 static int	acpilid_detach(device_t, int);
     72 static void	acpilid_status_changed(void *);
     73 static void	acpilid_notify_handler(ACPI_HANDLE, uint32_t, void *);
     74 
     75 CFATTACH_DECL_NEW(acpilid, sizeof(struct acpilid_softc),
     76     acpilid_match, acpilid_attach, acpilid_detach, NULL);
     77 
     78 /*
     79  * acpilid_match:
     80  *
     81  *	Autoconfiguration `match' routine.
     82  */
     83 static int
     84 acpilid_match(device_t parent, cfdata_t match, void *aux)
     85 {
     86 	struct acpi_attach_args *aa = aux;
     87 
     88 	return acpi_compatible_match(aa, compat_data);
     89 }
     90 
     91 /*
     92  * acpilid_attach:
     93  *
     94  *	Autoconfiguration `attach' routine.
     95  */
     96 static void
     97 acpilid_attach(device_t parent, device_t self, void *aux)
     98 {
     99 	struct acpilid_softc *sc = device_private(self);
    100 	struct acpi_attach_args *aa = aux;
    101 
    102 	aprint_naive(": ACPI Lid Switch\n");
    103 	aprint_normal(": ACPI Lid Switch\n");
    104 
    105 	sc->sc_node = aa->aa_node;
    106 
    107 	sc->sc_smpsw.smpsw_name = device_xname(self);
    108 	sc->sc_smpsw.smpsw_type = PSWITCH_TYPE_LID;
    109 
    110 	(void)pmf_device_register(self, NULL, NULL);
    111 	(void)sysmon_pswitch_register(&sc->sc_smpsw);
    112 	(void)acpi_register_notify(sc->sc_node, acpilid_notify_handler);
    113 }
    114 
    115 static int
    116 acpilid_detach(device_t self, int flags)
    117 {
    118 	struct acpilid_softc *sc = device_private(self);
    119 
    120 	pmf_device_deregister(self);
    121 	acpi_deregister_notify(sc->sc_node);
    122 	sysmon_pswitch_unregister(&sc->sc_smpsw);
    123 
    124 	return 0;
    125 }
    126 
    127 /*
    128  * acpilid_status_changed:
    129  *
    130  *	Get, and possibly display, the lid status, and take action.
    131  */
    132 static void
    133 acpilid_status_changed(void *arg)
    134 {
    135 	device_t dv = arg;
    136 	struct acpilid_softc *sc = device_private(dv);
    137 	ACPI_STATUS rv;
    138 
    139 	rv = acpi_eval_integer(sc->sc_node->ad_handle, "_LID", &sc->sc_status);
    140 
    141 	if (ACPI_FAILURE(rv))
    142 		return;
    143 
    144 	sysmon_pswitch_event(&sc->sc_smpsw, (sc->sc_status == 0) ?
    145 	    PSWITCH_EVENT_PRESSED : PSWITCH_EVENT_RELEASED);
    146 }
    147 
    148 /*
    149  * acpilid_notify_handler:
    150  *
    151  *	Callback from ACPI interrupt handler to notify us of an event.
    152  */
    153 static void
    154 acpilid_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *context)
    155 {
    156 	static const int handler = OSL_NOTIFY_HANDLER;
    157 	device_t dv = context;
    158 
    159 	switch (notify) {
    160 
    161 	case ACPI_NOTIFY_LID:
    162 		(void)AcpiOsExecute(handler, acpilid_status_changed, dv);
    163 		break;
    164 
    165 	case ACPI_NOTIFY_DEVICE_WAKE:
    166 		break;
    167 
    168 	default:
    169 		aprint_debug_dev(dv, "unknown notify 0x%02X\n", notify);
    170 	}
    171 }
    172 
    173 MODULE(MODULE_CLASS_DRIVER, acpilid, "sysmon_power");
    174 
    175 #ifdef _MODULE
    176 #include "ioconf.c"
    177 #endif
    178 
    179 static int
    180 acpilid_modcmd(modcmd_t cmd, void *aux)
    181 {
    182 	int rv = 0;
    183 
    184 	switch (cmd) {
    185 
    186 	case MODULE_CMD_INIT:
    187 
    188 #ifdef _MODULE
    189 		rv = config_init_component(cfdriver_ioconf_acpilid,
    190 		    cfattach_ioconf_acpilid, cfdata_ioconf_acpilid);
    191 #endif
    192 		break;
    193 
    194 	case MODULE_CMD_FINI:
    195 
    196 #ifdef _MODULE
    197 		rv = config_fini_component(cfdriver_ioconf_acpilid,
    198 		    cfattach_ioconf_acpilid, cfdata_ioconf_acpilid);
    199 #endif
    200 		break;
    201 
    202 	default:
    203 		rv = ENOTTY;
    204 	}
    205 
    206 	return rv;
    207 }
    208