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