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