1 /* $OpenBSD: acpiac.c,v 1.36 2022/04/06 18:59:27 naddy 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_activate(struct device *, int);
37 int acpiac_notify(struct aml_node *, int, void *);
38
39 void acpiac_refresh(void *);
40 int acpiac_getpsr(struct acpiac_softc *);
41
42 const struct cfattach acpiac_ca = {
43 sizeof(struct acpiac_softc),
44 acpiac_match,
45 acpiac_attach,
46 NULL,
47 acpiac_activate,
48 };
49
50 struct cfdriver acpiac_cd = {
51 NULL, "acpiac", DV_DULL
52 };
53
54 const char *acpiac_hids[] = {
55 ACPI_DEV_AC,
56 NULL
57 };
58
59 int
acpiac_match(struct device * parent,void * match,void * aux)60 acpiac_match(struct device *parent, void *match, void *aux)
61 {
62 struct acpi_attach_args *aa = aux;
63 struct cfdata *cf = match;
64
65 /* sanity */
66 return (acpi_matchhids(aa, acpiac_hids, cf->cf_driver->cd_name));
67 }
68
69 void
acpiac_attach(struct device * parent,struct device * self,void * aux)70 acpiac_attach(struct device *parent, struct device *self, void *aux)
71 {
72 struct acpiac_softc *sc = (struct acpiac_softc *)self;
73 extern int hw_power;
74 struct acpi_attach_args *aa = aux;
75
76 sc->sc_acpi = (struct acpi_softc *)parent;
77 sc->sc_devnode = aa->aaa_node;
78
79 acpiac_getpsr(sc);
80 printf(": AC unit ");
81 if (sc->sc_ac_stat == PSR_ONLINE)
82 printf("online\n");
83 else if (sc->sc_ac_stat == PSR_OFFLINE)
84 printf("offline\n");
85 else
86 printf("in unknown state\n");
87 hw_power = (sc->sc_ac_stat == PSR_ONLINE);
88
89 strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
90 sizeof(sc->sc_sensdev.xname));
91 strlcpy(sc->sc_sens[0].desc, "power supply",
92 sizeof(sc->sc_sens[0].desc));
93 sc->sc_sens[0].type = SENSOR_INDICATOR;
94 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[0]);
95 sensordev_install(&sc->sc_sensdev);
96 sc->sc_sens[0].value = sc->sc_ac_stat;
97
98 aml_register_notify(sc->sc_devnode, aa->aaa_dev,
99 acpiac_notify, sc, ACPIDEV_NOPOLL);
100 }
101
102 int
acpiac_activate(struct device * self,int act)103 acpiac_activate(struct device *self, int act)
104 {
105 struct acpiac_softc *sc = (struct acpiac_softc *)self;
106
107 switch (act) {
108 case DVACT_WAKEUP:
109 acpiac_refresh(sc);
110 dnprintf(10, "A/C status: %d\n", sc->sc_ac_stat);
111 break;
112 }
113
114 return (0);
115 }
116
117 void
acpiac_refresh(void * arg)118 acpiac_refresh(void *arg)
119 {
120 struct acpiac_softc *sc = arg;
121 extern int hw_power;
122
123 acpiac_getpsr(sc);
124 sc->sc_sens[0].value = sc->sc_ac_stat;
125 hw_power = (sc->sc_ac_stat == PSR_ONLINE);
126 }
127
128 int
acpiac_getpsr(struct acpiac_softc * sc)129 acpiac_getpsr(struct acpiac_softc *sc)
130 {
131 int64_t psr;
132
133 if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_PSR", 0, NULL, &psr)) {
134 dnprintf(10, "%s: no _PSR\n",
135 DEVNAME(sc));
136 return (1);
137 }
138 sc->sc_ac_stat = psr;
139
140 return (0);
141 }
142
143 int
acpiac_notify(struct aml_node * node,int notify_type,void * arg)144 acpiac_notify(struct aml_node *node, int notify_type, void *arg)
145 {
146 struct acpiac_softc *sc = arg;
147
148 dnprintf(10, "acpiac_notify: %.2x %s\n", notify_type,
149 DEVNAME(sc));
150
151 switch (notify_type) {
152 case 0x00:
153 case 0x01:
154 case 0x81:
155 /*
156 * XXX some sony vaio's use the wrong notify type
157 * work around it by honoring it as a 0x80
158 */
159 /* FALLTHROUGH */
160 case 0x80:
161 acpiac_refresh(sc);
162 acpi_record_event(sc->sc_acpi, APM_POWER_CHANGE);
163 dnprintf(10, "A/C status: %d\n", sc->sc_ac_stat);
164 break;
165 }
166 return (0);
167 }
168