Annotation of sys/dev/acpi/acpitz.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: acpitz.c,v 1.17 2007/03/26 12:30:48 marco Exp $ */
2: /*
3: * Copyright (c) 2006 Can Erkin Acar <canacar@openbsd.org>
4: * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
19: #include <sys/param.h>
20: #include <sys/proc.h>
21: #include <sys/signalvar.h>
22: #include <sys/systm.h>
23: #include <sys/device.h>
24: #include <sys/malloc.h>
25:
26: #include <machine/bus.h>
27:
28: #include <dev/acpi/acpireg.h>
29: #include <dev/acpi/acpivar.h>
30: #include <dev/acpi/acpidev.h>
31: #include <dev/acpi/amltypes.h>
32: #include <dev/acpi/dsdt.h>
33:
34: #include <sys/sensors.h>
35:
36: #define ACPITZ_MAX_AC 10
37:
38: struct acpitz_softc {
39: struct device sc_dev;
40:
41: struct acpi_softc *sc_acpi;
42: struct aml_node *sc_devnode;
43:
44: int sc_tmp;
45: int sc_crt;
46: int sc_hot;
47: int sc_ac[ACPITZ_MAX_AC];
48: int sc_ac_stat[ACPITZ_MAX_AC];
49: int sc_pse;
50: int sc_psv;
51: int sc_tc1;
52: int sc_tc2;
53: int sc_lasttmp;
54: struct ksensor sc_sens;
55: struct ksensordev sc_sensdev;
56: };
57:
58: int acpitz_match(struct device *, void *, void *);
59: void acpitz_attach(struct device *, struct device *, void *);
60:
61: struct cfattach acpitz_ca = {
62: sizeof(struct acpitz_softc), acpitz_match, acpitz_attach
63: };
64:
65: struct cfdriver acpitz_cd = {
66: NULL, "acpitz", DV_DULL
67: };
68:
69: void acpitz_monitor(struct acpitz_softc *);
70: void acpitz_refresh(void *);
71: int acpitz_notify(struct aml_node *, int, void *);
72: int acpitz_getreading(struct acpitz_softc *, char *);
73: int acpitz_setfan(struct acpitz_softc *, int, char *);
74: int acpitz_setcpu(struct acpitz_softc *, int);
75:
76: int
77: acpitz_match(struct device *parent, void *match, void *aux)
78: {
79: struct acpi_attach_args *aa = aux;
80: struct cfdata *cf = match;
81:
82: /* sanity */
83: if (aa->aaa_name == NULL ||
84: strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
85: aa->aaa_table != NULL)
86: return (0);
87:
88: if (aa->aaa_node->value->type != AML_OBJTYPE_THERMZONE)
89: return (0);
90:
91: return (1);
92: }
93:
94: void
95: acpitz_attach(struct device *parent, struct device *self, void *aux)
96: {
97: struct acpitz_softc *sc = (struct acpitz_softc *)self;
98: struct acpi_attach_args *aa = aux;
99: int i;
100: char name[8];
101:
102: sc->sc_acpi = (struct acpi_softc *)parent;
103: sc->sc_devnode = aa->aaa_node->child;
104:
105: sc->sc_lasttmp = -1;
106: if ((sc->sc_tmp = acpitz_getreading(sc, "_TMP")) == -1) {
107: printf(", failed to read _TMP\n");
108: return;
109: }
110:
111: if ((sc->sc_crt = acpitz_getreading(sc, "_CRT")) == -1) {
112: printf(", no critical temperature defined!\n");
113: sc->sc_crt = 0;
114: } else
115: printf(", critical temperature: %d degC\n",
116: (sc->sc_crt - 2732) / 10);
117:
118: for (i = 0; i < ACPITZ_MAX_AC; i++) {
119: snprintf(name, sizeof name, "_AC%d", i);
120: sc->sc_ac[i] = acpitz_getreading(sc, name);
121: sc->sc_ac_stat[0] = -1;
122: }
123:
124: sc->sc_hot = acpitz_getreading(sc, "_HOT");
125: sc->sc_tc1 = acpitz_getreading(sc, "_TC1");
126: sc->sc_tc2 = acpitz_getreading(sc, "_TC2");
127: sc->sc_psv = acpitz_getreading(sc, "_PSV");
128:
129: strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
130: sizeof(sc->sc_sensdev.xname));
131: strlcpy(sc->sc_sens.desc, "zone temperature",
132: sizeof(sc->sc_sens.desc));
133: sc->sc_sens.type = SENSOR_TEMP;
134: sensor_attach(&sc->sc_sensdev, &sc->sc_sens);
135: sensordev_install(&sc->sc_sensdev);
136: sc->sc_sens.value = 0;
137:
138: aml_register_notify(sc->sc_devnode->parent, NULL,
139: acpitz_notify, sc, ACPIDEV_POLL);
140: }
141:
142: int
143: acpitz_setcpu(struct acpitz_softc *sc, int trend)
144: {
145: struct aml_value res0, *ref;
146: int x;
147:
148: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_PSL", 0, NULL, &res0)) {
149: printf("%s: _PSL failed\n", DEVNAME(sc));
150: goto out;
151: }
152: if (res0.type != AML_OBJTYPE_PACKAGE) {
153: printf("%s: not a package\n", DEVNAME(sc));
154: goto out;
155: }
156: for (x = 0; x < res0.length; x++) {
157: if (res0.v_package[x]->type != AML_OBJTYPE_OBJREF) {
158: printf("%s: _PSL[%d] not a object ref\n", DEVNAME(sc), x);
159: continue;
160: }
161: ref = res0.v_package[x]->v_objref.ref;
162: if (ref->type != AML_OBJTYPE_PROCESSOR)
163: printf("%s: _PSL[%d] not a CPU\n", DEVNAME(sc), x);
164: }
165: out:
166: aml_freevalue(&res0);
167: return (0);
168: }
169:
170: int
171: acpitz_setfan(struct acpitz_softc *sc, int i, char *method)
172: {
173: struct aml_value res0, res1, res2, *ref;
174: char name[8];
175: int rv = 1, x, y;
176:
177: dnprintf(20, "%s: acpitz_setfan(%d, %s)\n", DEVNAME(sc), i, method);
178:
179: snprintf(name, sizeof name, "_AL%d", i);
180: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, name, 0, NULL, &res0)) {
181: dnprintf(20, "%s: %s failed\n", DEVNAME(sc), name);
182: goto out;
183: }
184:
185: if (res0.type != AML_OBJTYPE_PACKAGE) {
186: printf("%s: %s not a package\n", DEVNAME(sc), name);
187: goto out;
188: }
189:
190: for (x = 0; x < res0.length; x++) {
191: if (res0.v_package[x]->type != AML_OBJTYPE_OBJREF) {
192: printf("%s: %s[%d] not a object ref\n", DEVNAME(sc),
193: name, x);
194: continue;
195: }
196: ref = res0.v_package[x]->v_objref.ref;
197: if (aml_evalname(sc->sc_acpi, ref->node, "_PR0",0 , NULL,
198: &res1)) {
199: printf("%s: %s[%d] _PR0 failed\n", DEVNAME(sc),
200: name, x);
201: aml_freevalue(&res1);
202: continue;
203: }
204: if (res1.type != AML_OBJTYPE_PACKAGE) {
205: printf("%s: %s[%d] _PR0 not a package\n", DEVNAME(sc),
206: name, x);
207: aml_freevalue(&res1);
208: continue;
209: }
210: for (y = 0; y < res1.length; y++) {
211: if (res1.v_package[y]->type != AML_OBJTYPE_OBJREF) {
212: printf("%s: %s[%d.%d] _PR0 not a package\n",
213: DEVNAME(sc), name, x, y);
214: continue;
215: }
216: ref = res1.v_package[y]->v_objref.ref;
217: if (aml_evalname(sc->sc_acpi, ref->node, method, 0,
218: NULL, NULL))
219: printf("%s: %s[%d.%d] %s fails\n",
220: DEVNAME(sc), name, x, y, method);
221:
222: /* save off status of fan */
223: if (aml_evalname(sc->sc_acpi, ref->node, "_STA", 0,
224: NULL, &res2))
225: printf("%s: %s[%d.%d] _STA fails\n",
226: DEVNAME(sc), name, x, y);
227: else {
228: sc->sc_ac_stat[i] = aml_val2int(&res2);
229: aml_freevalue(&res2);
230: }
231: }
232: aml_freevalue(&res1);
233: }
234: rv = 0;
235: out:
236: aml_freevalue(&res0);
237: return (rv);
238: }
239:
240: void
241: acpitz_refresh(void *arg)
242: {
243: struct acpitz_softc *sc = arg;
244: int i, trend;
245: extern int acpi_s5;
246:
247: dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc),
248: sc->sc_devnode->parent->name);
249:
250: if (-1 == (sc->sc_tmp = acpitz_getreading(sc, "_TMP"))) {
251: dnprintf(30, "%s: %s: failed to read temp!\n", DEVNAME(sc),
252: sc->sc_devnode->parent->name);
253: sc->sc_tmp = 0; /* XXX */
254: }
255:
256: if (sc->sc_crt != -1 && sc->sc_crt <= sc->sc_tmp) {
257: /* Do critical shutdown */
258: printf("%s: Critical temperature, shutting down!\n",
259: DEVNAME(sc));
260: acpi_s5 = 1;
261: psignal(initproc, SIGUSR1);
262: }
263: if (sc->sc_hot != -1 && sc->sc_hot <= sc->sc_tmp)
264: printf("%s: _HOT temperature\n", DEVNAME(sc));
265:
266: if (sc->sc_lasttmp != -1 && sc->sc_tc1 != -1 && sc->sc_tc2 != -1 &&
267: sc->sc_psv != -1) {
268: if (sc->sc_psv <= sc->sc_tmp) {
269: sc->sc_pse = 1;
270: trend = sc->sc_tc1 * (sc->sc_tmp - sc->sc_lasttmp) +
271: sc->sc_tc2 * (sc->sc_tmp - sc->sc_psv);
272: /* printf("_TZ trend = %d\n", trend); */
273: } else if (sc->sc_pse)
274: sc->sc_pse = 0;
275: }
276: sc->sc_lasttmp = sc->sc_tmp;
277:
278: for (i = 0; i < ACPITZ_MAX_AC; i++) {
279: if (sc->sc_ac[i] != -1 && sc->sc_ac[i] <= sc->sc_tmp) {
280: /* turn on fan i */
281: if (sc->sc_ac_stat[i] <= 0)
282: acpitz_setfan(sc, i, "_ON_");
283: } else if (sc->sc_ac[i] != -1) {
284: /* turn off fan i */
285: if (sc->sc_ac_stat[i] > 0)
286: acpitz_setfan(sc, i, "_OFF");
287: }
288: }
289: sc->sc_sens.value = sc->sc_tmp * 100000;
290: }
291:
292: int
293: acpitz_getreading(struct acpitz_softc *sc, char *name)
294: {
295: struct aml_value res;
296: int rv = -1;
297:
298: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, name, 0, NULL, &res)) {
299: dnprintf(10, "%s: no %s\n", DEVNAME(sc), name);
300: goto out;
301: }
302: rv = aml_val2int(&res);
303: out:
304: aml_freevalue(&res);
305: return (rv);
306: }
307:
308: int
309: acpitz_notify(struct aml_node *node, int notify_type, void *arg)
310: {
311: struct acpitz_softc *sc = arg;
312: u_int64_t crt;
313:
314: dnprintf(10, "%s notify: %.2x %s\n", DEVNAME(sc), notify_type,
315: sc->sc_devnode->parent->name);
316:
317: switch (notify_type) {
318: case 0x81: /* Operating Points changed */
319: sc->sc_psv = acpitz_getreading(sc, "_PSV");
320: crt = sc->sc_crt;
321: sc->sc_crt = acpitz_getreading(sc, "_CRT");
322: if (crt != sc->sc_crt)
323: printf("%s: critical temperature: %u degC",
324: DEVNAME(sc), (sc->sc_crt - 2732) / 10);
325: break;
326: default:
327: break;
328: }
329: acpitz_refresh(sc);
330: return (0);
331: }
CVSweb