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