Home | History | Annotate | Line # | Download | only in acpi
dalb_acpi.c revision 1.18.32.1
      1  1.18.32.1   thorpej /*	$NetBSD: dalb_acpi.c,v 1.18.32.1 2021/04/03 22:28:43 thorpej Exp $	*/
      2        1.1    cegger 
      3        1.1    cegger /*-
      4        1.1    cegger  * Copyright (c) 2008 Christoph Egger <cegger (at) netbsd.org>
      5        1.1    cegger  * Copyright (c) 2008 Jared D. McNeill <jmcneill (at) netbsd.org>
      6        1.1    cegger  * All rights reserved.
      7        1.1    cegger  *
      8        1.1    cegger  * Redistribution and use in source and binary forms, with or without
      9        1.1    cegger  * modification, are permitted provided that the following conditions
     10        1.1    cegger  * are met:
     11        1.1    cegger  * 1. Redistributions of source code must retain the above copyright
     12        1.1    cegger  *    notice, this list of conditions and the following disclaimer.
     13        1.1    cegger  * 2. Redistributions in binary form must reproduce the above copyright
     14        1.1    cegger  *    notice, this list of conditions and the following disclaimer in the
     15        1.1    cegger  *    documentation and/or other materials provided with the distribution.
     16        1.1    cegger  *
     17        1.1    cegger  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     18        1.1    cegger  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     19        1.1    cegger  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     20        1.1    cegger  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     21        1.1    cegger  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     22        1.1    cegger  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     23        1.1    cegger  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     24        1.1    cegger  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     25        1.1    cegger  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     26        1.1    cegger  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     27        1.1    cegger  * POSSIBILITY OF SUCH DAMAGE.
     28        1.1    cegger  */
     29        1.1    cegger #include <sys/cdefs.h>
     30  1.18.32.1   thorpej __KERNEL_RCSID(0, "$NetBSD: dalb_acpi.c,v 1.18.32.1 2021/04/03 22:28:43 thorpej Exp $");
     31        1.1    cegger 
     32        1.1    cegger /*
     33        1.1    cegger  * Direct Application Launch Button:
     34        1.1    cegger  * http://www.microsoft.com/whdc/system/vista/DirAppLaunch.mspx
     35        1.1    cegger  */
     36        1.1    cegger 
     37        1.1    cegger #include <sys/param.h>
     38        1.1    cegger #include <sys/device.h>
     39       1.16    jruoho #include <sys/module.h>
     40        1.9    jruoho #include <sys/systm.h>
     41        1.1    cegger 
     42        1.9    jruoho #include <dev/acpi/acpireg.h>
     43        1.1    cegger #include <dev/acpi/acpivar.h>
     44        1.3   mlelstv 
     45        1.3   mlelstv #define _COMPONENT          ACPI_RESOURCE_COMPONENT
     46        1.3   mlelstv ACPI_MODULE_NAME            ("dalb_acpi")
     47        1.1    cegger 
     48        1.1    cegger #define DALB_ID_INVALID		-1
     49        1.1    cegger 
     50        1.1    cegger struct acpi_dalb_softc {
     51        1.1    cegger 	device_t sc_dev;
     52        1.1    cegger 	struct acpi_devnode *sc_node;
     53        1.1    cegger 
     54        1.1    cegger 	ACPI_INTEGER sc_usageid;
     55        1.1    cegger 
     56        1.1    cegger 	/* There's one PNP0C32 ACPI device for each button.
     57        1.1    cegger 	 * Therefore, one instance is enough. */
     58        1.1    cegger 	struct sysmon_pswitch sc_smpsw;
     59        1.1    cegger 	bool sc_smpsw_valid;
     60        1.1    cegger };
     61        1.1    cegger 
     62        1.1    cegger static int	acpi_dalb_match(device_t, cfdata_t, void *);
     63        1.1    cegger static void	acpi_dalb_attach(device_t, device_t, void *);
     64        1.6    jruoho static int	acpi_dalb_detach(device_t, int);
     65       1.13    jruoho static void	acpi_dalb_notify_handler(ACPI_HANDLE, uint32_t, void *);
     66        1.7    dyoung static bool	acpi_dalb_resume(device_t, const pmf_qual_t *);
     67        1.1    cegger 
     68        1.1    cegger static void	acpi_dalb_get_wakeup_hotkeys(void *opaque);
     69        1.1    cegger static void	acpi_dalb_get_runtime_hotkeys(void *opaque);
     70        1.1    cegger 
     71        1.1    cegger CFATTACH_DECL_NEW(acpidalb, sizeof(struct acpi_dalb_softc),
     72        1.6    jruoho     acpi_dalb_match, acpi_dalb_attach, acpi_dalb_detach, NULL);
     73        1.1    cegger 
     74  1.18.32.1   thorpej static const struct device_compatible_entry compat_data[] = {
     75  1.18.32.1   thorpej         { .compat = "PNP0C32" }, /* Direct Application Launch Button */
     76  1.18.32.1   thorpej 	DEVICE_COMPAT_EOL
     77        1.1    cegger };
     78        1.1    cegger 
     79        1.1    cegger #define DALB_SYSTEM_WAKEUP	0x02
     80        1.1    cegger #define DALB_SYSTEM_RUNTIME	0x80
     81        1.1    cegger 
     82        1.1    cegger static int
     83        1.1    cegger acpi_dalb_match(device_t parent, cfdata_t match, void *aux)
     84        1.1    cegger {
     85        1.1    cegger 	struct acpi_attach_args *aa = aux;
     86        1.1    cegger 
     87  1.18.32.1   thorpej 	return acpi_compatible_match(aa, compat_data);
     88        1.1    cegger }
     89        1.1    cegger 
     90        1.1    cegger static void
     91        1.1    cegger acpi_dalb_sysmon_init(struct acpi_dalb_softc *sc)
     92        1.1    cegger {
     93        1.1    cegger 	sc->sc_smpsw_valid = true;
     94        1.1    cegger 	sc->sc_smpsw.smpsw_name = device_xname(sc->sc_dev);
     95        1.1    cegger 	sc->sc_smpsw.smpsw_type = PSWITCH_TYPE_HOTKEY;
     96        1.1    cegger 	if (sysmon_pswitch_register(&sc->sc_smpsw)) {
     97        1.1    cegger 		aprint_error_dev(sc->sc_dev,
     98        1.1    cegger 			"couldn't register sleep with sysmon\n");
     99        1.1    cegger 		sc->sc_smpsw_valid = false;
    100        1.1    cegger 	}
    101        1.1    cegger }
    102        1.1    cegger 
    103        1.1    cegger 
    104        1.1    cegger static void
    105        1.1    cegger acpi_dalb_init(device_t dev)
    106        1.1    cegger {
    107        1.1    cegger 	struct acpi_dalb_softc *sc = device_private(dev);
    108        1.1    cegger 	ACPI_OBJECT *obj;
    109        1.1    cegger 	ACPI_STATUS rv;
    110        1.1    cegger 	ACPI_BUFFER ret;
    111        1.1    cegger 
    112        1.4    jruoho 	rv = acpi_eval_struct(sc->sc_node->ad_handle, "GHID", &ret);
    113       1.12    jruoho 
    114        1.1    cegger 	if (ACPI_FAILURE(rv) || ret.Pointer == NULL) {
    115        1.1    cegger 		aprint_error_dev(dev,
    116        1.1    cegger 			"couldn't enable notify handler: (%s)\n",
    117        1.1    cegger 			AcpiFormatException(rv));
    118        1.1    cegger 		return;
    119        1.1    cegger 	}
    120        1.1    cegger 
    121       1.12    jruoho 	obj = ret.Pointer;
    122       1.12    jruoho 
    123        1.1    cegger 	if (obj->Type != ACPI_TYPE_BUFFER) {
    124        1.1    cegger 		sc->sc_usageid = DALB_ID_INVALID;
    125        1.8    jruoho 		aprint_debug_dev(dev, "invalid ACPI type: %u\n", obj->Type);
    126        1.1    cegger 		goto out;
    127        1.1    cegger 	}
    128        1.1    cegger 
    129        1.1    cegger 	switch (obj->Buffer.Length) {
    130        1.1    cegger 	case 1:
    131        1.1    cegger 		sc->sc_usageid = *(uint8_t *)obj->Buffer.Pointer;
    132        1.1    cegger 		break;
    133        1.1    cegger 	case 2:
    134        1.1    cegger 		sc->sc_usageid = le16toh(*(uint16_t *)obj->Buffer.Pointer);
    135        1.1    cegger 		break;
    136        1.1    cegger 	case 4:
    137        1.1    cegger 		sc->sc_usageid = le32toh(*(uint32_t *)obj->Buffer.Pointer);
    138        1.1    cegger 		break;
    139        1.1    cegger 	default:
    140        1.1    cegger 		aprint_debug_dev(dev, "unhandled ret.Length: 0x%lx\n",
    141        1.1    cegger 			(unsigned long)obj->Buffer.Length);
    142        1.1    cegger 		sc->sc_usageid = DALB_ID_INVALID;
    143        1.1    cegger 		break;
    144        1.1    cegger 	}
    145        1.1    cegger 
    146        1.1    cegger out:
    147        1.3   mlelstv 	ACPI_FREE(ret.Pointer);
    148        1.1    cegger }
    149        1.1    cegger 
    150        1.1    cegger static void
    151        1.1    cegger acpi_dalb_attach(device_t parent, device_t self, void *aux)
    152        1.1    cegger {
    153        1.1    cegger 	struct acpi_dalb_softc *sc = device_private(self);
    154        1.1    cegger 	struct acpi_attach_args *aa = aux;
    155        1.1    cegger 
    156        1.1    cegger 	aprint_naive("\n");
    157        1.1    cegger 	aprint_normal(": Direct Application Launch Button\n");
    158        1.1    cegger 
    159       1.14    jruoho 	sc->sc_dev = self;
    160        1.1    cegger 	sc->sc_node = aa->aa_node;
    161        1.1    cegger 
    162        1.1    cegger 	config_interrupts(self, acpi_dalb_init);
    163        1.1    cegger 
    164       1.14    jruoho 	(void)pmf_device_register(self, NULL, acpi_dalb_resume);
    165       1.14    jruoho 	(void)acpi_register_notify(sc->sc_node, acpi_dalb_notify_handler);
    166        1.1    cegger 
    167        1.1    cegger 	sc->sc_smpsw_valid = false;
    168        1.1    cegger 	acpi_dalb_sysmon_init(sc);
    169        1.1    cegger }
    170        1.1    cegger 
    171        1.6    jruoho static int
    172        1.6    jruoho acpi_dalb_detach(device_t self, int flags)
    173        1.6    jruoho {
    174        1.6    jruoho 	struct acpi_dalb_softc *sc = device_private(self);
    175        1.6    jruoho 
    176        1.6    jruoho 	pmf_device_deregister(self);
    177       1.14    jruoho 	acpi_deregister_notify(sc->sc_node);
    178        1.6    jruoho 	sysmon_pswitch_unregister(&sc->sc_smpsw);
    179        1.6    jruoho 
    180        1.6    jruoho 	return 0;
    181        1.6    jruoho }
    182        1.6    jruoho 
    183        1.1    cegger static void
    184       1.13    jruoho acpi_dalb_notify_handler(ACPI_HANDLE hdl, uint32_t notify, void *opaque)
    185        1.1    cegger {
    186        1.1    cegger 	device_t dev = opaque;
    187        1.1    cegger 	struct acpi_dalb_softc *sc = device_private(dev);
    188        1.1    cegger 	ACPI_STATUS rv;
    189        1.1    cegger 
    190        1.1    cegger 	switch (notify) {
    191        1.1    cegger 	case DALB_SYSTEM_WAKEUP:
    192        1.1    cegger 		rv = AcpiOsExecute(OSL_NOTIFY_HANDLER,
    193        1.1    cegger 			acpi_dalb_get_wakeup_hotkeys, dev);
    194        1.1    cegger 		break;
    195        1.1    cegger 	case DALB_SYSTEM_RUNTIME:
    196        1.1    cegger 		rv = AcpiOsExecute(OSL_NOTIFY_HANDLER,
    197        1.1    cegger 			acpi_dalb_get_runtime_hotkeys, dev);
    198       1.16    jruoho 		break;
    199        1.1    cegger 
    200        1.1    cegger 	default:
    201        1.1    cegger 		aprint_error_dev(dev,
    202        1.1    cegger 			"unknown notification event 0x%x from button 0x%x\n",
    203        1.1    cegger 			notify, (uint32_t)sc->sc_usageid);
    204        1.1    cegger 		return;
    205        1.1    cegger 	}
    206        1.1    cegger 
    207        1.1    cegger 	if (ACPI_FAILURE(rv))
    208        1.1    cegger 		aprint_error_dev(dev, "couldn't queue hotkey handler: %s\n",
    209        1.1    cegger 			AcpiFormatException(rv));
    210        1.1    cegger }
    211        1.1    cegger 
    212        1.1    cegger static void
    213        1.1    cegger acpi_dalb_get_wakeup_hotkeys(void *opaque)
    214        1.1    cegger {
    215        1.1    cegger 	device_t dev = opaque;
    216        1.1    cegger 	struct acpi_dalb_softc *sc = device_private(dev);
    217        1.1    cegger 
    218        1.1    cegger 	if (!sc->sc_smpsw_valid)
    219        1.1    cegger 		return;
    220       1.11    jruoho 
    221       1.11    jruoho 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
    222       1.15    jruoho 		"invoking %s (wakeup)\n", sc->sc_smpsw.smpsw_name));
    223       1.11    jruoho 
    224        1.1    cegger 	sysmon_pswitch_event(&sc->sc_smpsw, PSWITCH_EVENT_PRESSED);
    225        1.1    cegger }
    226        1.1    cegger 
    227        1.1    cegger static void
    228        1.1    cegger acpi_dalb_get_runtime_hotkeys(void *opaque)
    229        1.1    cegger {
    230        1.1    cegger 	device_t dev = opaque;
    231        1.1    cegger 	struct acpi_dalb_softc *sc = device_private(dev);
    232        1.1    cegger 
    233        1.1    cegger 	if (!sc->sc_smpsw_valid)
    234        1.1    cegger 		return;
    235       1.11    jruoho 
    236       1.11    jruoho 	ACPI_DEBUG_PRINT((ACPI_DB_INFO,
    237       1.15    jruoho 		"invoking %s (runtime)\n", sc->sc_smpsw.smpsw_name));
    238       1.11    jruoho 
    239        1.1    cegger 	sysmon_pswitch_event(&sc->sc_smpsw, PSWITCH_EVENT_PRESSED);
    240        1.1    cegger }
    241        1.1    cegger 
    242        1.1    cegger static bool
    243        1.7    dyoung acpi_dalb_resume(device_t dev, const pmf_qual_t *qual)
    244        1.1    cegger {
    245        1.2  jmcneill 	struct acpi_dalb_softc *sc = device_private(dev);
    246        1.2  jmcneill 	ACPI_STATUS rv;
    247        1.2  jmcneill 	ACPI_BUFFER ret;
    248        1.2  jmcneill 
    249        1.4    jruoho 	rv = acpi_eval_struct(sc->sc_node->ad_handle, "GHID", &ret);
    250        1.2  jmcneill 	if (ACPI_FAILURE(rv)) {
    251        1.2  jmcneill 		aprint_error_dev(dev, "couldn't evaluate GHID: %s\n",
    252        1.2  jmcneill 		    AcpiFormatException(rv));
    253        1.2  jmcneill 		return false;
    254        1.2  jmcneill 	}
    255        1.2  jmcneill 	if (ret.Pointer)
    256        1.3   mlelstv 		ACPI_FREE(ret.Pointer);
    257        1.2  jmcneill 
    258        1.1    cegger 	return true;
    259        1.1    cegger }
    260       1.16    jruoho 
    261       1.18  pgoyette MODULE(MODULE_CLASS_DRIVER, acpidalb, "sysmon_power");
    262       1.16    jruoho 
    263       1.17    jruoho #ifdef _MODULE
    264       1.16    jruoho #include "ioconf.c"
    265       1.17    jruoho #endif
    266       1.16    jruoho 
    267       1.16    jruoho static int
    268       1.17    jruoho acpidalb_modcmd(modcmd_t cmd, void *aux)
    269       1.16    jruoho {
    270       1.17    jruoho 	int rv = 0;
    271       1.16    jruoho 
    272       1.16    jruoho 	switch (cmd) {
    273       1.16    jruoho 
    274       1.16    jruoho 	case MODULE_CMD_INIT:
    275       1.17    jruoho 
    276       1.17    jruoho #ifdef _MODULE
    277       1.17    jruoho 		rv = config_init_component(cfdriver_ioconf_acpidalb,
    278       1.16    jruoho 		    cfattach_ioconf_acpidalb, cfdata_ioconf_acpidalb);
    279       1.17    jruoho #endif
    280       1.17    jruoho 		break;
    281       1.16    jruoho 
    282       1.16    jruoho 	case MODULE_CMD_FINI:
    283       1.17    jruoho 
    284       1.17    jruoho #ifdef _MODULE
    285       1.17    jruoho 		rv = config_fini_component(cfdriver_ioconf_acpidalb,
    286       1.16    jruoho 		    cfattach_ioconf_acpidalb, cfdata_ioconf_acpidalb);
    287       1.17    jruoho #endif
    288       1.17    jruoho 		break;
    289       1.16    jruoho 
    290       1.16    jruoho 	default:
    291       1.17    jruoho 		rv = ENOTTY;
    292       1.16    jruoho 	}
    293       1.17    jruoho 
    294       1.17    jruoho 	return rv;
    295       1.16    jruoho }
    296