xref: /openbsd/sys/dev/acpi/acpiac.c (revision 771fbea0)
1 /* $OpenBSD: acpiac.c,v 1.33 2020/06/10 22:26:40 jca 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 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
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
70 acpiac_attach(struct device *parent, struct device *self, void *aux)
71 {
72 	struct acpiac_softc *sc = (struct acpiac_softc *)self;
73 	struct acpi_attach_args *aa = aux;
74 
75 	sc->sc_acpi = (struct acpi_softc *)parent;
76 	sc->sc_devnode = aa->aaa_node;
77 
78 	acpiac_getpsr(sc);
79 	printf(": AC unit ");
80 	if (sc->sc_ac_stat == PSR_ONLINE)
81 		printf("online\n");
82 	else if (sc->sc_ac_stat == PSR_OFFLINE)
83 		printf("offline\n");
84 	else
85 		printf("in unknown state\n");
86 
87 	strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
88 	    sizeof(sc->sc_sensdev.xname));
89 	strlcpy(sc->sc_sens[0].desc, "power supply",
90 	    sizeof(sc->sc_sens[0].desc));
91 	sc->sc_sens[0].type = SENSOR_INDICATOR;
92 	sensor_attach(&sc->sc_sensdev, &sc->sc_sens[0]);
93 	sensordev_install(&sc->sc_sensdev);
94 	sc->sc_sens[0].value = sc->sc_ac_stat;
95 
96 	aml_register_notify(sc->sc_devnode, aa->aaa_dev,
97 	    acpiac_notify, sc, ACPIDEV_NOPOLL);
98 }
99 
100 int
101 acpiac_activate(struct device *self, int act)
102 {
103 	struct acpiac_softc *sc = (struct acpiac_softc *)self;
104 
105 	switch (act) {
106 	case DVACT_WAKEUP:
107 		acpiac_refresh(sc);
108 		dnprintf(10, "A/C status: %d\n", sc->sc_ac_stat);
109 		break;
110 	}
111 
112 	return (0);
113 }
114 
115 void
116 acpiac_refresh(void *arg)
117 {
118 	struct acpiac_softc *sc = arg;
119 
120 	acpiac_getpsr(sc);
121 	sc->sc_sens[0].value = sc->sc_ac_stat;
122 }
123 
124 int
125 acpiac_getpsr(struct acpiac_softc *sc)
126 {
127 	int64_t psr;
128 
129 	if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_PSR", 0, NULL, &psr)) {
130 		dnprintf(10, "%s: no _PSR\n",
131 		    DEVNAME(sc));
132 		return (1);
133 	}
134 	sc->sc_ac_stat = psr;
135 
136 	return (0);
137 }
138 
139 int
140 acpiac_notify(struct aml_node *node, int notify_type, void *arg)
141 {
142 	struct acpiac_softc *sc = arg;
143 
144 	dnprintf(10, "acpiac_notify: %.2x %s\n", notify_type,
145 	    DEVNAME(sc));
146 
147 	switch (notify_type) {
148 	case 0x00:
149 	case 0x01:
150 	case 0x81:
151 		/*
152 		 * XXX some sony vaio's use the wrong notify type
153 		 * work around it by honoring it as a 0x80
154 		 */
155 		/* FALLTHROUGH */
156 	case 0x80:
157 		acpiac_refresh(sc);
158 		acpi_record_event(sc->sc_acpi, APM_POWER_CHANGE);
159 		dnprintf(10, "A/C status: %d\n", sc->sc_ac_stat);
160 		break;
161 	}
162 	return (0);
163 }
164