1 /* $OpenBSD: acpibat.c,v 1.60 2014/05/23 19:17:39 landry 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 = 150 sc->sc_bif.bif_power_unit ? SENSOR_AMPS : SENSOR_WATTS; 151 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[5]); 152 sc->sc_sens[5].value = sc->sc_bst.bst_rate * 1000; 153 154 strlcpy(sc->sc_sens[6].desc, "remaining capacity", 155 sizeof(sc->sc_sens[6].desc)); 156 sc->sc_sens[6].type = type; 157 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[6]); 158 sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000; 159 160 strlcpy(sc->sc_sens[7].desc, "current voltage", 161 sizeof(sc->sc_sens[7].desc)); 162 sc->sc_sens[7].type = SENSOR_VOLTS_DC; 163 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[7]); 164 sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000; 165 166 strlcpy(sc->sc_sens[8].desc, "design capacity", 167 sizeof(sc->sc_sens[8].desc)); 168 sc->sc_sens[8].type = type; 169 sensor_attach(&sc->sc_sensdev, &sc->sc_sens[8]); 170 sc->sc_sens[8].value = sc->sc_bif.bif_capacity * 1000; 171 172 sensordev_install(&sc->sc_sensdev); 173 } 174 175 void 176 acpibat_refresh(void *arg) 177 { 178 struct acpibat_softc *sc = arg; 179 int i; 180 181 dnprintf(30, "%s: %s: refresh\n", DEVNAME(sc), 182 sc->sc_devnode->name); 183 184 if (!sc->sc_bat_present) { 185 for (i = 0; i < 9; i++) { 186 sc->sc_sens[i].value = 0; 187 sc->sc_sens[i].status = SENSOR_S_UNSPEC; 188 sc->sc_sens[i].flags = SENSOR_FINVALID; 189 } 190 /* override state */ 191 strlcpy(sc->sc_sens[4].desc, "battery removed", 192 sizeof(sc->sc_sens[4].desc)); 193 return; 194 } 195 196 /* _BIF values are static, sensor 0..3 */ 197 if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN) { 198 sc->sc_sens[0].value = 0; 199 sc->sc_sens[0].status = SENSOR_S_UNKNOWN; 200 sc->sc_sens[0].flags = SENSOR_FUNKNOWN; 201 } else { 202 sc->sc_sens[0].value = sc->sc_bif.bif_last_capacity * 1000; 203 sc->sc_sens[0].status = SENSOR_S_UNSPEC; 204 sc->sc_sens[0].flags = 0; 205 } 206 sc->sc_sens[1].value = sc->sc_bif.bif_warning * 1000; 207 sc->sc_sens[1].flags = 0; 208 sc->sc_sens[2].value = sc->sc_bif.bif_low * 1000; 209 sc->sc_sens[2].flags = 0; 210 if (sc->sc_bif.bif_voltage == BIF_UNKNOWN) { 211 sc->sc_sens[3].value = 0; 212 sc->sc_sens[3].status = SENSOR_S_UNKNOWN; 213 sc->sc_sens[3].flags = SENSOR_FUNKNOWN; 214 } else { 215 sc->sc_sens[3].value = sc->sc_bif.bif_voltage * 1000; 216 sc->sc_sens[3].status = SENSOR_S_UNSPEC; 217 sc->sc_sens[3].flags = 0; 218 } 219 220 /* _BST values are dynamic, sensor 4..7 */ 221 sc->sc_sens[4].status = SENSOR_S_OK; 222 sc->sc_sens[4].flags = 0; 223 if (sc->sc_bif.bif_last_capacity == BIF_UNKNOWN || 224 sc->sc_bst.bst_capacity == BST_UNKNOWN) { 225 sc->sc_sens[4].status = SENSOR_S_UNKNOWN; 226 sc->sc_sens[4].flags = SENSOR_FUNKNOWN; 227 strlcpy(sc->sc_sens[4].desc, "battery unknown", 228 sizeof(sc->sc_sens[4].desc)); 229 } else if (sc->sc_bst.bst_capacity >= sc->sc_bif.bif_last_capacity) 230 strlcpy(sc->sc_sens[4].desc, "battery full", 231 sizeof(sc->sc_sens[4].desc)); 232 else if (sc->sc_bst.bst_state & BST_DISCHARGE) 233 strlcpy(sc->sc_sens[4].desc, "battery discharging", 234 sizeof(sc->sc_sens[4].desc)); 235 else if (sc->sc_bst.bst_state & BST_CHARGE) 236 strlcpy(sc->sc_sens[4].desc, "battery charging", 237 sizeof(sc->sc_sens[4].desc)); 238 else if (sc->sc_bst.bst_state & BST_CRITICAL) { 239 strlcpy(sc->sc_sens[4].desc, "battery critical", 240 sizeof(sc->sc_sens[4].desc)); 241 sc->sc_sens[4].status = SENSOR_S_CRIT; 242 } else 243 strlcpy(sc->sc_sens[4].desc, "battery idle", 244 sizeof(sc->sc_sens[4].desc)); 245 sc->sc_sens[4].value = sc->sc_bst.bst_state; 246 247 if (sc->sc_bst.bst_rate == BST_UNKNOWN) { 248 sc->sc_sens[5].value = 0; 249 sc->sc_sens[5].status = SENSOR_S_UNKNOWN; 250 sc->sc_sens[5].flags = SENSOR_FUNKNOWN; 251 } else { 252 sc->sc_sens[5].value = sc->sc_bst.bst_rate * 1000; 253 sc->sc_sens[5].status = SENSOR_S_UNSPEC; 254 sc->sc_sens[5].flags = 0; 255 } 256 257 if (sc->sc_bst.bst_capacity == BST_UNKNOWN) { 258 sc->sc_sens[6].value = 0; 259 sc->sc_sens[6].status = SENSOR_S_UNKNOWN; 260 sc->sc_sens[6].flags = SENSOR_FUNKNOWN; 261 } else { 262 sc->sc_sens[6].value = sc->sc_bst.bst_capacity * 1000; 263 sc->sc_sens[6].flags = 0; 264 265 if (sc->sc_bst.bst_capacity < sc->sc_bif.bif_low) 266 /* XXX we should shutdown the system */ 267 sc->sc_sens[6].status = SENSOR_S_CRIT; 268 else if (sc->sc_bst.bst_capacity < sc->sc_bif.bif_warning) 269 sc->sc_sens[6].status = SENSOR_S_WARN; 270 else 271 sc->sc_sens[6].status = SENSOR_S_OK; 272 } 273 274 if (sc->sc_bst.bst_voltage == BST_UNKNOWN) { 275 sc->sc_sens[7].value = 0; 276 sc->sc_sens[7].status = SENSOR_S_UNKNOWN; 277 sc->sc_sens[7].flags = SENSOR_FUNKNOWN; 278 } else { 279 sc->sc_sens[7].value = sc->sc_bst.bst_voltage * 1000; 280 sc->sc_sens[7].status = SENSOR_S_UNSPEC; 281 sc->sc_sens[7].flags = 0; 282 } 283 284 if (sc->sc_bif.bif_capacity == BIF_UNKNOWN) { 285 sc->sc_sens[8].value = 0; 286 sc->sc_sens[8].status = SENSOR_S_UNKNOWN; 287 sc->sc_sens[8].flags = SENSOR_FUNKNOWN; 288 } else { 289 sc->sc_sens[8].value = sc->sc_bif.bif_capacity * 1000; 290 sc->sc_sens[8].status = SENSOR_S_UNSPEC; 291 sc->sc_sens[8].flags = 0; 292 } 293 acpi_record_event(sc->sc_acpi, APM_POWER_CHANGE); 294 } 295 296 int 297 acpibat_getbif(struct acpibat_softc *sc) 298 { 299 struct aml_value res; 300 int rv = EINVAL; 301 302 if (!sc->sc_bat_present) { 303 memset(&sc->sc_bif, 0, sizeof(sc->sc_bif)); 304 return (0); 305 } 306 307 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BIF", 0, NULL, &res)) { 308 dnprintf(10, "%s: no _BIF\n", DEVNAME(sc)); 309 goto out; 310 } 311 312 if (res.length != 13) { 313 dnprintf(10, "%s: invalid _BIF, battery info not saved\n", 314 DEVNAME(sc)); 315 goto out; 316 } 317 318 sc->sc_bif.bif_power_unit = aml_val2int(res.v_package[0]); 319 sc->sc_bif.bif_capacity = aml_val2int(res.v_package[1]); 320 sc->sc_bif.bif_last_capacity = aml_val2int(res.v_package[2]); 321 sc->sc_bif.bif_technology = aml_val2int(res.v_package[3]); 322 sc->sc_bif.bif_voltage = aml_val2int(res.v_package[4]); 323 sc->sc_bif.bif_warning = aml_val2int(res.v_package[5]); 324 sc->sc_bif.bif_low = aml_val2int(res.v_package[6]); 325 sc->sc_bif.bif_cap_granu1 = aml_val2int(res.v_package[7]); 326 sc->sc_bif.bif_cap_granu2 = aml_val2int(res.v_package[8]); 327 328 strlcpy(sc->sc_bif.bif_model, aml_val_to_string(res.v_package[9]), 329 sizeof(sc->sc_bif.bif_model)); 330 strlcpy(sc->sc_bif.bif_serial, aml_val_to_string(res.v_package[10]), 331 sizeof(sc->sc_bif.bif_serial)); 332 strlcpy(sc->sc_bif.bif_type, aml_val_to_string(res.v_package[11]), 333 sizeof(sc->sc_bif.bif_type)); 334 strlcpy(sc->sc_bif.bif_oem, aml_val_to_string(res.v_package[12]), 335 sizeof(sc->sc_bif.bif_oem)); 336 337 dnprintf(60, "power_unit: %u capacity: %u last_cap: %u tech: %u " 338 "volt: %u warn: %u low: %u gran1: %u gran2: %d model: %s " 339 "serial: %s type: %s oem: %s\n", 340 sc->sc_bif.bif_power_unit, 341 sc->sc_bif.bif_capacity, 342 sc->sc_bif.bif_last_capacity, 343 sc->sc_bif.bif_technology, 344 sc->sc_bif.bif_voltage, 345 sc->sc_bif.bif_warning, 346 sc->sc_bif.bif_low, 347 sc->sc_bif.bif_cap_granu1, 348 sc->sc_bif.bif_cap_granu2, 349 sc->sc_bif.bif_model, 350 sc->sc_bif.bif_serial, 351 sc->sc_bif.bif_type, 352 sc->sc_bif.bif_oem); 353 354 rv = 0; 355 out: 356 aml_freevalue(&res); 357 return (rv); 358 } 359 360 int 361 acpibat_getbst(struct acpibat_softc *sc) 362 { 363 struct aml_value res; 364 int rv = EINVAL; 365 366 if (!sc->sc_bat_present) { 367 memset(&sc->sc_bst, 0, sizeof(sc->sc_bst)); 368 return (0); 369 } 370 371 if (aml_evalname(sc->sc_acpi, sc->sc_devnode, "_BST", 0, NULL, &res)) { 372 dnprintf(10, "%s: no _BST\n", DEVNAME(sc)); 373 goto out; 374 } 375 376 if (res.length != 4) { 377 dnprintf(10, "%s: invalid _BST, battery status not saved\n", 378 DEVNAME(sc)); 379 goto out; 380 } 381 382 sc->sc_bst.bst_state = aml_val2int(res.v_package[0]); 383 sc->sc_bst.bst_rate = aml_val2int(res.v_package[1]); 384 sc->sc_bst.bst_capacity = aml_val2int(res.v_package[2]); 385 sc->sc_bst.bst_voltage = aml_val2int(res.v_package[3]); 386 387 dnprintf(60, "state: %u rate: %u cap: %u volt: %u ", 388 sc->sc_bst.bst_state, 389 sc->sc_bst.bst_rate, 390 sc->sc_bst.bst_capacity, 391 sc->sc_bst.bst_voltage); 392 393 rv = 0; 394 out: 395 aml_freevalue(&res); 396 return (rv); 397 } 398 399 /* 400 * XXX it has been observed that some systems do not propagate battery 401 * insertion events up to the driver. What seems to happen is that DSDT 402 * does receive an interrupt however the originator bit is not set. 403 * This seems to happen when one inserts a 100% full battery. Removal 404 * of the power cord or insertion of a not 100% full battery breaks this 405 * behavior and all events will then be sent upwards. Currently there 406 * is no known work-around for it. 407 */ 408 409 int 410 acpibat_notify(struct aml_node *node, int notify_type, void *arg) 411 { 412 struct acpibat_softc *sc = arg; 413 int64_t sta; 414 415 dnprintf(10, "acpibat_notify: %.2x %s\n", notify_type, 416 sc->sc_devnode->name); 417 418 /* Check if installed state of battery has changed */ 419 if (aml_evalinteger(sc->sc_acpi, node, "_STA", 0, NULL, &sta) == 0) { 420 if (sta & STA_BATTERY) 421 sc->sc_bat_present = 1; 422 else 423 sc->sc_bat_present = 0; 424 } 425 426 switch (notify_type) { 427 case 0x00: /* Poll sensors */ 428 case 0x80: /* _BST changed */ 429 acpibat_getbst(sc); 430 break; 431 case 0x81: /* _BIF changed */ 432 acpibat_getbif(sc); 433 break; 434 default: 435 break; 436 } 437 438 acpibat_refresh(sc); 439 440 return (0); 441 } 442