1 /* $OpenBSD: acpiac.c,v 1.30 2015/07/17 20:15:52 jcs 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/event.h> 20 #include <sys/systm.h> 21 #include <sys/device.h> 22 #include <sys/malloc.h> 23 24 #include <machine/bus.h> 25 #include <machine/apmvar.h> 26 27 #include <dev/acpi/acpireg.h> 28 #include <dev/acpi/acpivar.h> 29 #include <dev/acpi/acpidev.h> 30 #include <dev/acpi/dsdt.h> 31 32 #include <sys/sensors.h> 33 34 int acpiac_match(struct device *, void *, void *); 35 void acpiac_attach(struct device *, struct device *, void *); 36 int acpiac_notify(struct aml_node *, int, void *); 37 38 void acpiac_refresh(void *); 39 int acpiac_getsta(struct acpiac_softc *); 40 41 struct cfattach acpiac_ca = { 42 sizeof(struct acpiac_softc), acpiac_match, acpiac_attach 43 }; 44 45 struct cfdriver acpiac_cd = { 46 NULL, "acpiac", DV_DULL 47 }; 48 49 const char *acpiac_hids[] = { ACPI_DEV_AC, 0 }; 50 51 int 52 acpiac_match(struct device *parent, void *match, void *aux) 53 { 54 struct acpi_attach_args *aa = aux; 55 struct cfdata *cf = match; 56 57 /* sanity */ 58 return (acpi_matchhids(aa, acpiac_hids, cf->cf_driver->cd_name)); 59 } 60 61 void 62 acpiac_attach(struct device *parent, struct device *self, void *aux) 63 { 64 struct acpiac_softc *sc = (struct acpiac_softc *)self; 65 struct acpi_attach_args *aa = aux; 66 67 sc->sc_acpi = (struct acpi_softc *)parent; 68 sc->sc_devnode = aa->aaa_node; 69 70 acpiac_getsta(sc); 71 printf(": AC unit "); 72 if (sc->sc_ac_stat == PSR_ONLINE) 73 printf("online\n"); 74 else if (sc->sc_ac_stat == PSR_OFFLINE) 75 printf("offline\n"); 76 else 77 printf("in unknown state\n"); 78 79 strlcpy(sc->sc_sensdev.xname, DEVNAME(sc), 80 sizeof(sc->sc_sensdev.xname)); 81 strlcpy(sc->sc_sens[0].desc, "power supply", 82 sizeof(sc->sc_sens[0].desc)); 83 sc->sc_sens[0].type = SENSOR_INDICATOR; 84 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[0]); 85 sensordev_install(&sc->sc_sensdev); 86 sc->sc_sens[0].value = sc->sc_ac_stat; 87 88 aml_register_notify(sc->sc_devnode, aa->aaa_dev, 89 acpiac_notify, sc, ACPIDEV_NOPOLL); 90 } 91 92 void 93 acpiac_refresh(void *arg) 94 { 95 struct acpiac_softc *sc = arg; 96 97 acpiac_getsta(sc); 98 sc->sc_sens[0].value = sc->sc_ac_stat; 99 acpi_record_event(sc->sc_acpi, APM_POWER_CHANGE); 100 } 101 102 int 103 acpiac_getsta(struct acpiac_softc *sc) 104 { 105 int64_t sta; 106 107 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, NULL)) { 108 dnprintf(10, "%s: no _STA\n", 109 DEVNAME(sc)); 110 } 111 112 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_PSR", 0, NULL, &sta)) { 113 dnprintf(10, "%s: no _PSR\n", 114 DEVNAME(sc)); 115 return (1); 116 } 117 sc->sc_ac_stat = sta; 118 return (0); 119 } 120 121 int 122 acpiac_notify(struct aml_node *node, int notify_type, void *arg) 123 { 124 struct acpiac_softc *sc = arg; 125 126 dnprintf(10, "acpiac_notify: %.2x %s\n", notify_type, 127 DEVNAME(sc)); 128 129 switch (notify_type) { 130 case 0x00: 131 case 0x01: 132 case 0x81: 133 /* 134 * XXX some sony vaio's use the wrong notify type 135 * work around it by honoring it as a 0x80 136 */ 137 /* FALLTHROUGH */ 138 case 0x80: 139 acpiac_refresh(sc); 140 dnprintf(10, "A/C status: %d\n", sc->sc_ac_stat); 141 break; 142 } 143 return (0); 144 } 145