1 /* $OpenBSD: acpibtn.c,v 1.21 2009/02/19 21:02:05 marco Exp $ */ 2 /* 3 * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/proc.h> 20 #include <sys/signalvar.h> 21 #include <sys/systm.h> 22 #include <sys/device.h> 23 #include <sys/malloc.h> 24 25 #include <machine/bus.h> 26 27 #include <dev/acpi/acpireg.h> 28 #include <dev/acpi/acpivar.h> 29 #include <dev/acpi/acpidev.h> 30 #include <dev/acpi/amltypes.h> 31 #include <dev/acpi/dsdt.h> 32 33 #include <sys/sensors.h> 34 35 int acpibtn_match(struct device *, void *, void *); 36 void acpibtn_attach(struct device *, struct device *, void *); 37 int acpibtn_notify(struct aml_node *, int, void *); 38 39 struct acpibtn_softc { 40 struct device sc_dev; 41 42 bus_space_tag_t sc_iot; 43 bus_space_handle_t sc_ioh; 44 45 struct acpi_softc *sc_acpi; 46 struct aml_node *sc_devnode; 47 48 int sc_btn_type; 49 #define ACPIBTN_UNKNOWN -1 50 #define ACPIBTN_LID 0 51 #define ACPIBTN_POWER 1 52 #define ACPIBTN_SLEEP 2 53 }; 54 55 int acpibtn_getsta(struct acpibtn_softc *); 56 57 struct cfattach acpibtn_ca = { 58 sizeof(struct acpibtn_softc), acpibtn_match, acpibtn_attach 59 }; 60 61 struct cfdriver acpibtn_cd = { 62 NULL, "acpibtn", DV_DULL 63 }; 64 65 const char *acpibtn_hids[] = { ACPI_DEV_LD, ACPI_DEV_PBD, ACPI_DEV_SBD, 0 }; 66 67 int 68 acpibtn_match(struct device *parent, void *match, void *aux) 69 { 70 struct acpi_attach_args *aa = aux; 71 struct cfdata *cf = match; 72 73 /* sanity */ 74 return (acpi_matchhids(aa, acpibtn_hids, cf->cf_driver->cd_name)); 75 } 76 77 void 78 acpibtn_attach(struct device *parent, struct device *self, void *aux) 79 { 80 struct acpibtn_softc *sc = (struct acpibtn_softc *)self; 81 struct acpi_attach_args *aa = aux; 82 83 sc->sc_acpi = (struct acpi_softc *)parent; 84 sc->sc_devnode = aa->aaa_node; 85 86 if (!strcmp(aa->aaa_dev, ACPI_DEV_LD)) 87 sc->sc_btn_type = ACPIBTN_LID; 88 else if (!strcmp(aa->aaa_dev, ACPI_DEV_PBD)) 89 sc->sc_btn_type = ACPIBTN_POWER; 90 else if (!strcmp(aa->aaa_dev, ACPI_DEV_SBD)) 91 sc->sc_btn_type = ACPIBTN_SLEEP; 92 else 93 sc->sc_btn_type = ACPIBTN_UNKNOWN; 94 95 acpibtn_getsta(sc); 96 97 printf(": %s\n", sc->sc_devnode->name); 98 99 aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpibtn_notify, 100 sc, ACPIDEV_NOPOLL); 101 } 102 103 int 104 acpibtn_getsta(struct acpibtn_softc *sc) 105 { 106 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, NULL) != 0) { 107 dnprintf(20, "%s: no _STA\n", DEVNAME(sc)); 108 /* XXX not all buttons have _STA so FALLTROUGH */ 109 } 110 111 return (0); 112 } 113 114 int 115 acpibtn_notify(struct aml_node *node, int notify_type, void *arg) 116 { 117 struct acpibtn_softc *sc = arg; 118 119 dnprintf(10, "acpibtn_notify: %.2x %s\n", notify_type, 120 sc->sc_devnode->name); 121 122 switch (sc->sc_btn_type) { 123 case ACPIBTN_LID: 124 case ACPIBTN_SLEEP: 125 #ifdef ACPI_SLEEP_ENABLED 126 acpi_sleep_state(sc->sc_acpi, ACPI_STATE_S3); 127 #endif /* ACPI_SLEEP_ENABLED */ 128 break; 129 case ACPIBTN_POWER: 130 if (notify_type == 0x80) 131 psignal(initproc, SIGUSR2); 132 break; 133 default: 134 printf("%s: spurious acpi button interrupt %i\n", DEVNAME(sc), 135 sc->sc_btn_type); 136 break; 137 } 138 139 return (0); 140 } 141