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