1*8bd8e11fSthorpej /* $NetBSD: acpi_button.c,v 1.43 2021/01/29 15:24:00 thorpej Exp $ */
21a9d24bcSthorpej
31a9d24bcSthorpej /*
459ea64b6Sthorpej * Copyright 2001, 2003 Wasabi Systems, Inc.
51a9d24bcSthorpej * All rights reserved.
61a9d24bcSthorpej *
71a9d24bcSthorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc.
81a9d24bcSthorpej *
91a9d24bcSthorpej * Redistribution and use in source and binary forms, with or without
101a9d24bcSthorpej * modification, are permitted provided that the following conditions
111a9d24bcSthorpej * are met:
121a9d24bcSthorpej * 1. Redistributions of source code must retain the above copyright
131a9d24bcSthorpej * notice, this list of conditions and the following disclaimer.
141a9d24bcSthorpej * 2. Redistributions in binary form must reproduce the above copyright
151a9d24bcSthorpej * notice, this list of conditions and the following disclaimer in the
161a9d24bcSthorpej * documentation and/or other materials provided with the distribution.
171a9d24bcSthorpej * 3. All advertising materials mentioning features or use of this software
181a9d24bcSthorpej * must display the following acknowledgement:
191a9d24bcSthorpej * This product includes software developed for the NetBSD Project by
201a9d24bcSthorpej * Wasabi Systems, Inc.
211a9d24bcSthorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse
221a9d24bcSthorpej * or promote products derived from this software without specific prior
231a9d24bcSthorpej * written permission.
241a9d24bcSthorpej *
251a9d24bcSthorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
261a9d24bcSthorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
271a9d24bcSthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
281a9d24bcSthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
291a9d24bcSthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
301a9d24bcSthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
311a9d24bcSthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
321a9d24bcSthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
331a9d24bcSthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
341a9d24bcSthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
351a9d24bcSthorpej * POSSIBILITY OF SUCH DAMAGE.
361a9d24bcSthorpej */
371a9d24bcSthorpej
381a9d24bcSthorpej /*
391a9d24bcSthorpej * ACPI Button driver.
401a9d24bcSthorpej */
411a9d24bcSthorpej
4213ac4302Slukem #include <sys/cdefs.h>
43*8bd8e11fSthorpej __KERNEL_RCSID(0, "$NetBSD: acpi_button.c,v 1.43 2021/01/29 15:24:00 thorpej Exp $");
4413ac4302Slukem
451a9d24bcSthorpej #include <sys/param.h>
461a9d24bcSthorpej #include <sys/device.h>
4786c30149Sjruoho #include <sys/module.h>
485a425210Sjruoho #include <sys/systm.h>
491a9d24bcSthorpej
501a9d24bcSthorpej #include <dev/acpi/acpireg.h>
511a9d24bcSthorpej #include <dev/acpi/acpivar.h>
528bd40defSjruoho #include <dev/acpi/acpi_wakedev.h>
531a9d24bcSthorpej
54a86a8685Sjruoho #define _COMPONENT ACPI_BUTTON_COMPONENT
55a86a8685Sjruoho ACPI_MODULE_NAME ("acpi_button")
56a86a8685Sjruoho
57f04ee530Sjruoho #define ACPI_NOTIFY_BUTTON 0x80
58f04ee530Sjruoho
591a9d24bcSthorpej struct acpibut_softc {
603c39e810Sjruoho struct acpi_devnode *sc_node;
613c39e810Sjruoho struct sysmon_pswitch sc_smpsw;
621a9d24bcSthorpej };
631a9d24bcSthorpej
64*8bd8e11fSthorpej struct button_type {
65*8bd8e11fSthorpej const char *desc;
66*8bd8e11fSthorpej int type;
671055d5f7Skochi };
681055d5f7Skochi
69*8bd8e11fSthorpej static const struct button_type power_button_type = {
70*8bd8e11fSthorpej .desc = "Power",
71*8bd8e11fSthorpej .type = PSWITCH_TYPE_POWER
72*8bd8e11fSthorpej };
73*8bd8e11fSthorpej
74*8bd8e11fSthorpej static const struct button_type sleep_button_type = {
75*8bd8e11fSthorpej .desc = "Sleep",
76*8bd8e11fSthorpej .type = PSWITCH_TYPE_SLEEP
77*8bd8e11fSthorpej };
78*8bd8e11fSthorpej
79*8bd8e11fSthorpej static const struct device_compatible_entry compat_data[] = {
80*8bd8e11fSthorpej { .compat = "PNP0C0C", .data = &power_button_type },
81*8bd8e11fSthorpej { .compat = "PNP0C0E", .data = &sleep_button_type },
82*8bd8e11fSthorpej DEVICE_COMPAT_EOL
8384795bd3Skochi };
8484795bd3Skochi
85e5339e11Scegger static int acpibut_match(device_t, cfdata_t, void *);
86649a2156Sjoerg static void acpibut_attach(device_t, device_t, void *);
871aca5372Sjruoho static int acpibut_detach(device_t, int);
88beb4a7feSkochi static void acpibut_pressed_event(void *);
893c39e810Sjruoho static void acpibut_notify_handler(ACPI_HANDLE, uint32_t, void *);
901a9d24bcSthorpej
911aca5372Sjruoho CFATTACH_DECL_NEW(acpibut, sizeof(struct acpibut_softc),
921aca5372Sjruoho acpibut_match, acpibut_attach, acpibut_detach, NULL);
931aca5372Sjruoho
941a9d24bcSthorpej /*
951a9d24bcSthorpej * acpibut_match:
961a9d24bcSthorpej *
971a9d24bcSthorpej * Autoconfiguration `match' routine.
981a9d24bcSthorpej */
99beb4a7feSkochi static int
acpibut_match(device_t parent,cfdata_t match,void * aux)100e5339e11Scegger acpibut_match(device_t parent, cfdata_t match, void *aux)
1011a9d24bcSthorpej {
1021a9d24bcSthorpej struct acpi_attach_args *aa = aux;
1031a9d24bcSthorpej
104*8bd8e11fSthorpej return acpi_compatible_match(aa, compat_data);
1051a9d24bcSthorpej }
1061a9d24bcSthorpej
1071a9d24bcSthorpej /*
1081a9d24bcSthorpej * acpibut_attach:
1091a9d24bcSthorpej *
1101a9d24bcSthorpej * Autoconfiguration `attach' routine.
1111a9d24bcSthorpej */
112beb4a7feSkochi static void
acpibut_attach(device_t parent,device_t self,void * aux)113649a2156Sjoerg acpibut_attach(device_t parent, device_t self, void *aux)
1141a9d24bcSthorpej {
115649a2156Sjoerg struct acpibut_softc *sc = device_private(self);
1161a9d24bcSthorpej struct acpi_attach_args *aa = aux;
117*8bd8e11fSthorpej const struct device_compatible_entry *dce;
118*8bd8e11fSthorpej const struct button_type *type;
1198bd40defSjruoho struct acpi_wakedev *aw;
1201a9d24bcSthorpej
121649a2156Sjoerg sc->sc_smpsw.smpsw_name = device_xname(self);
12259ea64b6Sthorpej
123*8bd8e11fSthorpej dce = acpi_compatible_lookup(aa, compat_data);
124*8bd8e11fSthorpej KASSERT(dce != NULL);
125*8bd8e11fSthorpej type = dce->data;
1261a9d24bcSthorpej
127*8bd8e11fSthorpej sc->sc_smpsw.smpsw_type = type->type;
128*8bd8e11fSthorpej
129*8bd8e11fSthorpej aprint_naive(": ACPI %s Button\n", type->desc);
130*8bd8e11fSthorpej aprint_normal(": ACPI %s Button\n", type->desc);
1311a9d24bcSthorpej
1321a9d24bcSthorpej sc->sc_node = aa->aa_node;
1338bd40defSjruoho aw = sc->sc_node->ad_wakedev;
1348bd40defSjruoho
1358bd40defSjruoho /*
1368bd40defSjruoho * This GPE should always be enabled.
1378bd40defSjruoho */
1388bd40defSjruoho if (aw != NULL)
1398bd40defSjruoho (void)AcpiEnableGpe(aw->aw_handle, aw->aw_number);
1401a9d24bcSthorpej
141a087b17cSjruoho (void)pmf_device_register(self, NULL, NULL);
1423c39e810Sjruoho (void)sysmon_pswitch_register(&sc->sc_smpsw);
14355052ecaSjruoho (void)acpi_register_notify(sc->sc_node, acpibut_notify_handler);
1441a9d24bcSthorpej }
1451a9d24bcSthorpej
1461a9d24bcSthorpej /*
1471aca5372Sjruoho * acpibut_detach:
1481aca5372Sjruoho *
1491aca5372Sjruoho * Autoconfiguration `detach' routine.
1501aca5372Sjruoho */
1511aca5372Sjruoho static int
acpibut_detach(device_t self,int flags)1521aca5372Sjruoho acpibut_detach(device_t self, int flags)
1531aca5372Sjruoho {
1541aca5372Sjruoho struct acpibut_softc *sc = device_private(self);
1551aca5372Sjruoho
1561aca5372Sjruoho pmf_device_deregister(self);
15755052ecaSjruoho acpi_deregister_notify(sc->sc_node);
1581aca5372Sjruoho sysmon_pswitch_unregister(&sc->sc_smpsw);
1591aca5372Sjruoho
1601aca5372Sjruoho return 0;
1611aca5372Sjruoho }
1621aca5372Sjruoho
1631aca5372Sjruoho /*
16459ea64b6Sthorpej * acpibut_pressed_event:
1651a9d24bcSthorpej *
16659ea64b6Sthorpej * Deal with a button being pressed.
1671a9d24bcSthorpej */
168beb4a7feSkochi static void
acpibut_pressed_event(void * arg)16959ea64b6Sthorpej acpibut_pressed_event(void *arg)
1701a9d24bcSthorpej {
171649a2156Sjoerg device_t dv = arg;
172649a2156Sjoerg struct acpibut_softc *sc = device_private(dv);
1731a9d24bcSthorpej
1743c39e810Sjruoho aprint_debug_dev(dv, "button pressed\n");
1755a20f4beSthorpej sysmon_pswitch_event(&sc->sc_smpsw, PSWITCH_EVENT_PRESSED);
1761a9d24bcSthorpej }
1771a9d24bcSthorpej
1781a9d24bcSthorpej /*
1791a9d24bcSthorpej * acpibut_notify_handler:
1801a9d24bcSthorpej *
1811a9d24bcSthorpej * Callback from ACPI interrupt handler to notify us of an event.
1821a9d24bcSthorpej */
183beb4a7feSkochi static void
acpibut_notify_handler(ACPI_HANDLE handle,uint32_t notify,void * context)1843c39e810Sjruoho acpibut_notify_handler(ACPI_HANDLE handle, uint32_t notify, void *context)
1851a9d24bcSthorpej {
1863c39e810Sjruoho static const int handler = OSL_NOTIFY_HANDLER;
187649a2156Sjoerg device_t dv = context;
1881a9d24bcSthorpej
1891a9d24bcSthorpej switch (notify) {
1903c39e810Sjruoho
191f04ee530Sjruoho case ACPI_NOTIFY_BUTTON:
1923c39e810Sjruoho (void)AcpiOsExecute(handler, acpibut_pressed_event, dv);
1931a9d24bcSthorpej break;
1941a9d24bcSthorpej
195c5ec9c2cSjmcneill case ACPI_NOTIFY_DEVICE_WAKE:
196c5ec9c2cSjmcneill break;
197c5ec9c2cSjmcneill
1981a9d24bcSthorpej default:
1998c53a122Sjruoho aprint_debug_dev(dv, "unknown notify 0x%02X\n", notify);
2001a9d24bcSthorpej }
2011a9d24bcSthorpej }
20286c30149Sjruoho
20376a2f91aSpgoyette MODULE(MODULE_CLASS_DRIVER, acpibut, "sysmon_power");
20486c30149Sjruoho
2052b0b13f2Sjruoho #ifdef _MODULE
2062b0b13f2Sjruoho #include "ioconf.c"
2072b0b13f2Sjruoho #endif
20886c30149Sjruoho
20986c30149Sjruoho static int
acpibut_modcmd(modcmd_t cmd,void * aux)2102b0b13f2Sjruoho acpibut_modcmd(modcmd_t cmd, void *aux)
21186c30149Sjruoho {
2122b0b13f2Sjruoho int rv = 0;
21386c30149Sjruoho
21486c30149Sjruoho switch (cmd) {
21586c30149Sjruoho
21686c30149Sjruoho case MODULE_CMD_INIT:
21786c30149Sjruoho
2182b0b13f2Sjruoho #ifdef _MODULE
2192b0b13f2Sjruoho rv = config_init_component(cfdriver_ioconf_acpibut,
2202b0b13f2Sjruoho cfattach_ioconf_acpibut, cfdata_ioconf_acpibut);
2212b0b13f2Sjruoho #endif
2222b0b13f2Sjruoho break;
22386c30149Sjruoho
22486c30149Sjruoho case MODULE_CMD_FINI:
22586c30149Sjruoho
2262b0b13f2Sjruoho #ifdef _MODULE
2272b0b13f2Sjruoho rv = config_fini_component(cfdriver_ioconf_acpibut,
2282b0b13f2Sjruoho cfattach_ioconf_acpibut, cfdata_ioconf_acpibut);
2292b0b13f2Sjruoho #endif
2302b0b13f2Sjruoho break;
23186c30149Sjruoho
23286c30149Sjruoho default:
2332b0b13f2Sjruoho rv = ENOTTY;
23486c30149Sjruoho }
23586c30149Sjruoho
2362b0b13f2Sjruoho return rv;
2372b0b13f2Sjruoho }
238