Annotation of sys/dev/acpi/acpibat.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: acpibat.c,v 1.40 2007/03/20 15:17:21 mk 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/systm.h>
21: #include <sys/device.h>
22: #include <sys/malloc.h>
23: #include <sys/sensors.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: int acpibat_match(struct device *, void *, void *);
34: void acpibat_attach(struct device *, struct device *, void *);
35:
36: struct cfattach acpibat_ca = {
37: sizeof(struct acpibat_softc), acpibat_match, acpibat_attach
38: };
39:
40: struct cfdriver acpibat_cd = {
41: NULL, "acpibat", DV_DULL
42: };
43:
44: void acpibat_monitor(struct acpibat_softc *);
45: void acpibat_refresh(void *);
46: int acpibat_getbif(struct acpibat_softc *);
47: int acpibat_getbst(struct acpibat_softc *);
48: int acpibat_notify(struct aml_node *, int, void *);
49:
50: int
51: acpibat_match(struct device *parent, void *match, void *aux)
52: {
53: struct acpi_attach_args *aa = aux;
54: struct cfdata *cf = match;
55:
56: /* sanity */
57: if (aa->aaa_name == NULL ||
58: strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
59: aa->aaa_table != NULL)
60: return (0);
61:
62: return (1);
63: }
64:
65: void
66: acpibat_attach(struct device *parent, struct device *self, void *aux)
67: {
68: struct acpibat_softc *sc = (struct acpibat_softc *)self;
69: struct acpi_attach_args *aa = aux;
70: struct aml_value res;
71:
72: sc->sc_acpi = (struct acpi_softc *)parent;
73: sc->sc_devnode = aa->aaa_node->child;
74:
75: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &res)) {
76: dnprintf(10, "%s: no _STA\n", DEVNAME(sc));
77: return;
78: }
79:
80: if ((sc->sc_bat_present = aml_val2int(&res) & STA_BATTERY) != 0) {
81: acpibat_getbif(sc);
82: acpibat_getbst(sc);
83: printf(": %s: model: %s serial: %s type: %s oem: %s\n",
84: sc->sc_devnode->parent->name,
85: sc->sc_bif.bif_model,
86: sc->sc_bif.bif_serial,
87: sc->sc_bif.bif_type,
88: sc->sc_bif.bif_oem);
89: } else
90: printf(": %s: not present\n", sc->sc_devnode->parent->name);
91:
92: aml_freevalue(&res);
93:
94: /* create sensors */
95: acpibat_monitor(sc);
96:
97: /* populate sensors */
98: acpibat_refresh(sc);
99:
100: aml_register_notify(sc->sc_devnode->parent, aa->aaa_dev,
101: acpibat_notify, sc, ACPIDEV_POLL);
102: }
103:
104: void
105: acpibat_monitor(struct acpibat_softc *sc)
106: {
107: int type;
108:
109: /* assume _BIF and _BST have been called */
110: strlcpy(sc->sc_sensdev.xname, DEVNAME(sc),
111: sizeof(sc->sc_sensdev.xname));
112:
113: type = sc->sc_bif.bif_power_unit ? SENSOR_AMPHOUR : SENSOR_WATTHOUR;
114:
115: strlcpy(sc->sc_sens[0].desc, "last full capacity",
116: sizeof(sc->sc_sens[0].desc));
117: sc->sc_sens[0].type = type;
118: sensor_attach(&sc->sc_sensdev, &sc->sc_sens[0]);
119: sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity * 1000;
120:
121: strlcpy(sc->sc_sens[1].desc, "warning capacity",
122: sizeof(sc->sc_sens[1].desc));
123: sc->sc_sens[1].type = type;
124: sensor_attach(&sc->sc_sensdev, &sc->sc_sens[1]);
125: sc->sc_sens[1].value = sc->sc_bif.bif_warning * 1000;
126:
127: strlcpy(sc->sc_sens[2].desc, "low capacity",
128: sizeof(sc->sc_sens[2].desc));
129: sc->sc_sens[2].type = type;
130: sensor_attach(&sc->sc_sensdev, &sc->sc_sens[2]);
131: sc->sc_sens[2].value = sc->sc_bif.bif_low * 1000;
132:
133: strlcpy(sc->sc_sens[3].desc, "voltage", sizeof(sc->sc_sens[3].desc));
134: sc->sc_sens[3].type = SENSOR_VOLTS_DC;
135: sensor_attach(&sc->sc_sensdev, &sc->sc_sens[3]);
136: sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000;
137:
138: strlcpy(sc->sc_sens[4].desc, "battery unknown",
139: sizeof(sc->sc_sens[4].desc));
140: sc->sc_sens[4].type = SENSOR_INTEGER;
141: sensor_attach(&sc->sc_sensdev, &sc->sc_sens[4]);
142: sc->sc_sens[4].value = sc->sc_bst.bst_state;
143:
144: strlcpy(sc->sc_sens[5].desc, "rate", sizeof(sc->sc_sens[5].desc));
145: sc->sc_sens[5].type = SENSOR_INTEGER;
146: sensor_attach(&sc->sc_sensdev, &sc->sc_sens[5]);
147: sc->sc_sens[5].value = sc->sc_bst.bst_rate;
148:
149: strlcpy(sc->sc_sens[6].desc, "remaining capacity",
150: sizeof(sc->sc_sens[6].desc));
151: sc->sc_sens[6].type = type;
152: sensor_attach(&sc->sc_sensdev, &sc->sc_sens[6]);
153: sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000;
154:
155: strlcpy(sc->sc_sens[7].desc, "current voltage",
156: sizeof(sc->sc_sens[7].desc));
157: sc->sc_sens[7].type = SENSOR_VOLTS_DC;
158: sensor_attach(&sc->sc_sensdev, &sc->sc_sens[7]);
159: sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000;
160:
161: sensordev_install(&sc->sc_sensdev);
162: }
163:
164: void
165: acpibat_refresh(void *arg)
166: {
167: struct acpibat_softc *sc = arg;
168: int i;
169:
170: dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc),
171: sc->sc_devnode->parent->name);
172:
173: if (!sc->sc_bat_present) {
174: for (i = 0; i < 8; i++) {
175: sc->sc_sens[i].value = 0;
176: sc->sc_sens[i].status = SENSOR_S_UNSPEC;
177: sc->sc_sens[i].flags = SENSOR_FINVALID;
178: }
179: /* override state */
180: strlcpy(sc->sc_sens[4].desc, "battery removed",
181: sizeof(sc->sc_sens[4].desc));
182: return;
183: }
184:
185: /*
186: * XXX don't really need _BIF but keep it here in case we
187: * miss an insertion/removal event
188: */
189: acpibat_getbif(sc);
190: acpibat_getbst(sc);
191:
192: /* _BIF values are static, sensor 0..3 */
193: if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN) {
194: sc->sc_sens[0].value = 0;
195: sc->sc_sens[0].status = SENSOR_S_UNKNOWN;
196: sc->sc_sens[0].flags = SENSOR_FUNKNOWN;
197: } else {
198: sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity * 1000;
199: sc->sc_sens[0].status = SENSOR_S_UNSPEC;
200: sc->sc_sens[0].flags = 0;
201: }
202: sc->sc_sens[1].value = sc->sc_bif.bif_warning * 1000;
203: sc->sc_sens[1].flags = 0;
204: sc->sc_sens[2].value = sc->sc_bif.bif_low * 1000;
205: sc->sc_sens[2].flags = 0;
206: if (sc->sc_bif.bif_voltage == BIF_UNKNOWN) {
207: sc->sc_sens[3].value = 0;
208: sc->sc_sens[3].status = SENSOR_S_UNKNOWN;
209: sc->sc_sens[3].flags = SENSOR_FUNKNOWN;
210: } else {
211: sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000;
212: sc->sc_sens[3].status = SENSOR_S_UNSPEC;
213: sc->sc_sens[3].flags = 0;
214: }
215:
216: /* _BST values are dynamic, sensor 4..7 */
217: sc->sc_sens[4].status = SENSOR_S_OK;
218: sc->sc_sens[4].flags = 0;
219: if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN ||
220: sc->sc_bst.bst_capacity == BST_UNKNOWN) {
221: sc->sc_sens[4].status = SENSOR_S_UNKNOWN;
222: sc->sc_sens[4].flags = SENSOR_FUNKNOWN;
223: strlcpy(sc->sc_sens[4].desc, "battery unknown",
224: sizeof(sc->sc_sens[4].desc));
225: } else if (sc->sc_bst.bst_capacity >= sc->sc_bif.bif_last_capacity)
226: strlcpy(sc->sc_sens[4].desc, "battery full",
227: sizeof(sc->sc_sens[4].desc));
228: else if (sc->sc_bst.bst_state & BST_DISCHARGE)
229: strlcpy(sc->sc_sens[4].desc, "battery discharging",
230: sizeof(sc->sc_sens[4].desc));
231: else if (sc->sc_bst.bst_state & BST_CHARGE)
232: strlcpy(sc->sc_sens[4].desc, "battery charging",
233: sizeof(sc->sc_sens[4].desc));
234: else if (sc->sc_bst.bst_state & BST_CRITICAL) {
235: strlcpy(sc->sc_sens[4].desc, "battery critical",
236: sizeof(sc->sc_sens[4].desc));
237: sc->sc_sens[4].status = SENSOR_S_CRIT;
238: } else
239: strlcpy(sc->sc_sens[4].desc, "battery idle",
240: sizeof(sc->sc_sens[4].desc));
241: sc->sc_sens[4].value = sc->sc_bst.bst_state;
242:
243: if (sc->sc_bst.bst_rate == BST_UNKNOWN) {
244: sc->sc_sens[5].value = 0;
245: sc->sc_sens[5].status = SENSOR_S_UNKNOWN;
246: sc->sc_sens[5].flags = SENSOR_FUNKNOWN;
247: } else {
248: sc->sc_sens[5].value = sc->sc_bst.bst_rate;
249: sc->sc_sens[5].status = SENSOR_S_UNSPEC;
250: sc->sc_sens[5].flags = 0;
251: }
252:
253: if (sc->sc_bst.bst_capacity == BST_UNKNOWN) {
254: sc->sc_sens[6].value = 0;
255: sc->sc_sens[6].status = SENSOR_S_UNKNOWN;
256: sc->sc_sens[6].flags = SENSOR_FUNKNOWN;
257: } else {
258: sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000;
259: sc->sc_sens[6].flags = 0;
260:
261: if (sc->sc_bst.bst_capacity < sc->sc_bif.bif_low)
262: /* XXX we should shutdown the system */
263: sc->sc_sens[6].status = SENSOR_S_CRIT;
264: else if (sc->sc_bst.bst_capacity < sc->sc_bif.bif_warning)
265: sc->sc_sens[6].status = SENSOR_S_WARN;
266: else
267: sc->sc_sens[6].status = SENSOR_S_OK;
268: }
269:
270: if(sc->sc_bst.bst_voltage == BST_UNKNOWN) {
271: sc->sc_sens[7].value = 0;
272: sc->sc_sens[7].status = SENSOR_S_UNKNOWN;
273: sc->sc_sens[7].flags = SENSOR_FUNKNOWN;
274: } else {
275: sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000;
276: sc->sc_sens[7].status = SENSOR_S_UNSPEC;
277: sc->sc_sens[7].flags = 0;
278: }
279: }
280:
281: int
282: acpibat_getbif(struct acpibat_softc *sc)
283: {
284: struct aml_value res;
285: int rv = EINVAL;
286:
287: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_STA", 0, NULL, &res)) {
288: dnprintf(10, "%s: no _STA\n", DEVNAME(sc));
289: goto out;
290: }
291: aml_freevalue(&res);
292:
293: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BIF", 0, NULL, &res)) {
294: dnprintf(10, "%s: no _BIF\n", DEVNAME(sc));
295: goto out;
296: }
297:
298: if (res.length != 13) {
299: dnprintf(10, "%s: invalid _BIF, battery info not saved\n",
300: DEVNAME(sc));
301: goto out;
302: }
303:
304: memset(&sc->sc_bif, 0, sizeof sc->sc_bif);
305: sc->sc_bif.bif_power_unit = aml_val2int(res.v_package[0]);
306: sc->sc_bif.bif_capacity = aml_val2int(res.v_package[1]);
307: sc->sc_bif.bif_last_capacity = aml_val2int(res.v_package[2]);
308: sc->sc_bif.bif_technology = aml_val2int(res.v_package[3]);
309: sc->sc_bif.bif_voltage = aml_val2int(res.v_package[4]);
310: sc->sc_bif.bif_warning = aml_val2int(res.v_package[5]);
311: sc->sc_bif.bif_low = aml_val2int(res.v_package[6]);
312: sc->sc_bif.bif_cap_granu1 = aml_val2int(res.v_package[7]);
313: sc->sc_bif.bif_cap_granu2 = aml_val2int(res.v_package[8]);
314:
315: strlcpy(sc->sc_bif.bif_model, aml_strval(res.v_package[9]),
316: sizeof(sc->sc_bif.bif_model));
317: strlcpy(sc->sc_bif.bif_serial, aml_strval(res.v_package[10]),
318: sizeof(sc->sc_bif.bif_serial));
319: strlcpy(sc->sc_bif.bif_type, aml_strval(res.v_package[11]),
320: sizeof(sc->sc_bif.bif_type));
321: strlcpy(sc->sc_bif.bif_oem, aml_strval(res.v_package[12]),
322: sizeof(sc->sc_bif.bif_oem));
323:
324: dnprintf(60, "power_unit: %u capacity: %u last_cap: %u tech: %u "
325: "volt: %u warn: %u low: %u gran1: %u gran2: %d model: %s "
326: "serial: %s type: %s oem: %s\n",
327: sc->sc_bif.bif_power_unit,
328: sc->sc_bif.bif_capacity,
329: sc->sc_bif.bif_last_capacity,
330: sc->sc_bif.bif_technology,
331: sc->sc_bif.bif_voltage,
332: sc->sc_bif.bif_warning,
333: sc->sc_bif.bif_low,
334: sc->sc_bif.bif_cap_granu1,
335: sc->sc_bif.bif_cap_granu2,
336: sc->sc_bif.bif_model,
337: sc->sc_bif.bif_serial,
338: sc->sc_bif.bif_type,
339: sc->sc_bif.bif_oem);
340:
341: rv = 0;
342: out:
343: aml_freevalue(&res);
344: return (rv);
345: }
346:
347: int
348: acpibat_getbst(struct acpibat_softc *sc)
349: {
350: struct aml_value res;
351: int rv = EINVAL;
352:
353: if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BST", 0, NULL, &res)) {
354: dnprintf(10, "%s: no _BST\n", DEVNAME(sc));
355: goto out;
356: }
357:
358: if (res.length != 4) {
359: dnprintf(10, "%s: invalid _BST, battery status not saved\n",
360: DEVNAME(sc));
361: goto out;
362: }
363:
364: sc->sc_bst.bst_state = aml_val2int(res.v_package[0]);
365: sc->sc_bst.bst_rate = aml_val2int(res.v_package[1]);
366: sc->sc_bst.bst_capacity = aml_val2int(res.v_package[2]);
367: sc->sc_bst.bst_voltage = aml_val2int(res.v_package[3]);
368:
369: dnprintf(60, "state: %u rate: %u cap: %u volt: %u ",
370: sc->sc_bst.bst_state,
371: sc->sc_bst.bst_rate,
372: sc->sc_bst.bst_capacity,
373: sc->sc_bst.bst_voltage);
374:
375: rv = 0;
376: out:
377: aml_freevalue(&res);
378: return (rv);
379: }
380:
381: /* XXX it has been observed that some systems do not propagate battery
382: * insertion events up to the driver. What seems to happen is that DSDT
383: * does receive an interrupt however the originator bit is not set.
384: * This seems to happen when one inserts a 100% full battery. Removal
385: * of the power cord or insertion of a not 100% full battery breaks this
386: * behavior and all events will then be sent upwards. Currently there
387: * is no known work-around for it.
388: */
389:
390: int
391: acpibat_notify(struct aml_node *node, int notify_type, void *arg)
392: {
393: struct acpibat_softc *sc = arg;
394:
395: dnprintf(10, "acpibat_notify: %.2x %s\n", notify_type,
396: sc->sc_devnode->parent->name);
397:
398: switch (notify_type) {
399: case 0x80: /* _BST changed */
400: if (!sc->sc_bat_present) {
401: printf("%s: %s: inserted\n", DEVNAME(sc),
402: sc->sc_devnode->parent->name);
403: sc->sc_bat_present = 1;
404: }
405: break;
406: case 0x81: /* _BIF changed */
407: /* XXX consider this a device removal */
408: if (sc->sc_bat_present) {
409: printf("%s: %s: removed\n", DEVNAME(sc),
410: sc->sc_devnode->parent->name);
411: sc->sc_bat_present = 0;
412: }
413: break;
414: default:
415: break;
416: }
417:
418: acpibat_refresh(sc);
419:
420: return (0);
421: }
CVSweb