1 /*- 2 * Copyright (c) 2005 Nate Lawson 3 * Copyright (c) 2000 Munehiro Matsuda 4 * Copyright (c) 2000 Takanori Watanabe 5 * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * 29 * $FreeBSD: head/sys/dev/acpica/acpi_cmbat.c 246128 2013-01-30 18:01:20Z sbz $ 30 */ 31 32 #include "opt_acpi.h" 33 #include <sys/param.h> 34 #include <sys/kernel.h> 35 #include <sys/module.h> 36 #include <sys/bus.h> 37 38 #include <sys/rman.h> 39 40 #include "acpi.h" 41 #include <dev/acpica/acpivar.h> 42 #include <dev/acpica/acpiio.h> 43 44 /* Number of times to retry initialization before giving up. */ 45 #define ACPI_CMBAT_RETRY_MAX 6 46 47 /* Check the battery once a minute. */ 48 #define CMBAT_POLLRATE (60 * hz) 49 50 /* Hooks for the ACPICA debugging infrastructure */ 51 #define _COMPONENT ACPI_BATTERY 52 ACPI_MODULE_NAME("BATTERY") 53 54 #define ACPI_BATTERY_BST_CHANGE 0x80 55 #define ACPI_BATTERY_BIF_CHANGE 0x81 56 57 struct acpi_cmbat_softc { 58 device_t dev; 59 int flags; 60 61 struct acpi_bif bif; 62 struct acpi_bst bst; 63 struct timespec bst_lastupdated; 64 }; 65 66 ACPI_SERIAL_DECL(cmbat, "ACPI cmbat"); 67 68 static int acpi_cmbat_probe(device_t dev); 69 static int acpi_cmbat_attach(device_t dev); 70 static int acpi_cmbat_detach(device_t dev); 71 static int acpi_cmbat_resume(device_t dev); 72 static void acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, 73 void *context); 74 static int acpi_cmbat_info_expired(struct timespec *lastupdated); 75 static void acpi_cmbat_info_updated(struct timespec *lastupdated); 76 static void acpi_cmbat_get_bst(void *arg); 77 static void acpi_cmbat_get_bif_task(void *arg); 78 static void acpi_cmbat_get_bif(void *arg); 79 static int acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp); 80 static int acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp); 81 static void acpi_cmbat_init_battery(void *arg); 82 83 static device_method_t acpi_cmbat_methods[] = { 84 /* Device interface */ 85 DEVMETHOD(device_probe, acpi_cmbat_probe), 86 DEVMETHOD(device_attach, acpi_cmbat_attach), 87 DEVMETHOD(device_detach, acpi_cmbat_detach), 88 DEVMETHOD(device_resume, acpi_cmbat_resume), 89 90 /* ACPI battery interface */ 91 DEVMETHOD(acpi_batt_get_info, acpi_cmbat_bif), 92 DEVMETHOD(acpi_batt_get_status, acpi_cmbat_bst), 93 94 DEVMETHOD_END 95 }; 96 97 static driver_t acpi_cmbat_driver = { 98 "battery", 99 acpi_cmbat_methods, 100 sizeof(struct acpi_cmbat_softc), 101 }; 102 103 static devclass_t acpi_cmbat_devclass; 104 DRIVER_MODULE(acpi_cmbat, acpi, acpi_cmbat_driver, acpi_cmbat_devclass, NULL, NULL); 105 MODULE_DEPEND(acpi_cmbat, acpi, 1, 1, 1); 106 107 static int 108 acpi_cmbat_probe(device_t dev) 109 { 110 static char *cmbat_ids[] = { "PNP0C0A", NULL }; 111 112 if (acpi_disabled("cmbat") || 113 ACPI_ID_PROBE(device_get_parent(dev), dev, cmbat_ids) == NULL) 114 return (ENXIO); 115 116 device_set_desc(dev, "ACPI Control Method Battery"); 117 return (0); 118 } 119 120 static int 121 acpi_cmbat_attach(device_t dev) 122 { 123 int error; 124 ACPI_HANDLE handle; 125 struct acpi_cmbat_softc *sc; 126 127 sc = device_get_softc(dev); 128 handle = acpi_get_handle(dev); 129 sc->dev = dev; 130 131 ACPI_SERIAL_INIT(cmbat); 132 133 timespecclear(&sc->bst_lastupdated); 134 135 error = acpi_battery_register(dev); 136 if (error != 0) { 137 device_printf(dev, "registering battery failed\n"); 138 return (error); 139 } 140 141 /* 142 * Install a system notify handler in addition to the device notify. 143 * Toshiba notebook uses this alternate notify for its battery. 144 */ 145 AcpiInstallNotifyHandler(handle, ACPI_ALL_NOTIFY, 146 acpi_cmbat_notify_handler, dev); 147 148 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_init_battery, dev); 149 150 return (0); 151 } 152 153 static int 154 acpi_cmbat_detach(device_t dev) 155 { 156 ACPI_HANDLE handle; 157 158 handle = acpi_get_handle(dev); 159 AcpiRemoveNotifyHandler(handle, ACPI_ALL_NOTIFY, acpi_cmbat_notify_handler); 160 acpi_battery_remove(dev); 161 return (0); 162 } 163 164 static int 165 acpi_cmbat_resume(device_t dev) 166 { 167 168 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_init_battery, dev); 169 return (0); 170 } 171 172 static void 173 acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 174 { 175 struct acpi_cmbat_softc *sc; 176 device_t dev; 177 178 dev = (device_t)context; 179 sc = device_get_softc(dev); 180 181 switch (notify) { 182 case ACPI_NOTIFY_DEVICE_CHECK: 183 case ACPI_BATTERY_BST_CHANGE: 184 /* 185 * Clear the last updated time. The next call to retrieve the 186 * battery status will get the new value for us. 187 */ 188 timespecclear(&sc->bst_lastupdated); 189 break; 190 case ACPI_NOTIFY_BUS_CHECK: 191 case ACPI_BATTERY_BIF_CHANGE: 192 /* 193 * Queue a callback to get the current battery info from thread 194 * context. It's not safe to block in a notify handler. 195 */ 196 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_get_bif_task, dev); 197 break; 198 } 199 200 acpi_UserNotify("CMBAT", h, notify); 201 } 202 203 static int 204 acpi_cmbat_info_expired(struct timespec *lastupdated) 205 { 206 struct timespec curtime; 207 208 ACPI_SERIAL_ASSERT(cmbat); 209 210 if (lastupdated == NULL) 211 return (TRUE); 212 if (!timespecisset(lastupdated)) 213 return (TRUE); 214 215 getnanotime(&curtime); 216 timespecsub(&curtime, lastupdated); 217 return (curtime.tv_sec < 0 || 218 curtime.tv_sec > acpi_battery_get_info_expire()); 219 } 220 221 static void 222 acpi_cmbat_info_updated(struct timespec *lastupdated) 223 { 224 225 ACPI_SERIAL_ASSERT(cmbat); 226 227 if (lastupdated != NULL) 228 getnanotime(lastupdated); 229 } 230 231 static void 232 acpi_cmbat_get_bst(void *arg) 233 { 234 struct acpi_cmbat_softc *sc; 235 ACPI_STATUS as; 236 ACPI_OBJECT *res; 237 ACPI_HANDLE h; 238 ACPI_BUFFER bst_buffer; 239 device_t dev; 240 241 ACPI_SERIAL_ASSERT(cmbat); 242 243 dev = arg; 244 sc = device_get_softc(dev); 245 h = acpi_get_handle(dev); 246 bst_buffer.Pointer = NULL; 247 bst_buffer.Length = ACPI_ALLOCATE_BUFFER; 248 249 if (!acpi_cmbat_info_expired(&sc->bst_lastupdated)) 250 goto end; 251 252 as = AcpiEvaluateObject(h, "_BST", NULL, &bst_buffer); 253 if (ACPI_FAILURE(as)) { 254 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 255 "error fetching current battery status -- %s\n", 256 AcpiFormatException(as)); 257 goto end; 258 } 259 260 res = (ACPI_OBJECT *)bst_buffer.Pointer; 261 if (!ACPI_PKG_VALID(res, 4)) { 262 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 263 "battery status corrupted\n"); 264 goto end; 265 } 266 267 if (acpi_PkgInt32(res, 0, &sc->bst.state) != 0) 268 goto end; 269 if (acpi_PkgInt32(res, 1, &sc->bst.rate) != 0) 270 goto end; 271 if (acpi_PkgInt32(res, 2, &sc->bst.cap) != 0) 272 goto end; 273 if (acpi_PkgInt32(res, 3, &sc->bst.volt) != 0) 274 goto end; 275 acpi_cmbat_info_updated(&sc->bst_lastupdated); 276 277 /* Clear out undefined/extended bits that might be set by hardware. */ 278 sc->bst.state &= ACPI_BATT_STAT_BST_MASK; 279 if ((sc->bst.state & ACPI_BATT_STAT_INVALID) == ACPI_BATT_STAT_INVALID) 280 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 281 "battery reports simultaneous charging and discharging\n"); 282 283 /* XXX If all batteries are critical, perhaps we should suspend. */ 284 if (sc->bst.state & ACPI_BATT_STAT_CRITICAL) { 285 if ((sc->flags & ACPI_BATT_STAT_CRITICAL) == 0) { 286 sc->flags |= ACPI_BATT_STAT_CRITICAL; 287 device_printf(dev, "critically low charge!\n"); 288 } 289 } else 290 sc->flags &= ~ACPI_BATT_STAT_CRITICAL; 291 292 end: 293 if (bst_buffer.Pointer != NULL) 294 AcpiOsFree(bst_buffer.Pointer); 295 } 296 297 /* XXX There should be a cleaner way to do this locking. */ 298 static void 299 acpi_cmbat_get_bif_task(void *arg) 300 { 301 302 ACPI_SERIAL_BEGIN(cmbat); 303 acpi_cmbat_get_bif(arg); 304 ACPI_SERIAL_END(cmbat); 305 } 306 307 static void 308 acpi_cmbat_get_bif(void *arg) 309 { 310 struct acpi_cmbat_softc *sc; 311 ACPI_STATUS as; 312 ACPI_OBJECT *res; 313 ACPI_HANDLE h; 314 ACPI_BUFFER bif_buffer; 315 device_t dev; 316 317 ACPI_SERIAL_ASSERT(cmbat); 318 319 dev = arg; 320 sc = device_get_softc(dev); 321 h = acpi_get_handle(dev); 322 bif_buffer.Pointer = NULL; 323 bif_buffer.Length = ACPI_ALLOCATE_BUFFER; 324 325 as = AcpiEvaluateObject(h, "_BIF", NULL, &bif_buffer); 326 if (ACPI_FAILURE(as)) { 327 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 328 "error fetching current battery info -- %s\n", 329 AcpiFormatException(as)); 330 goto end; 331 } 332 333 res = (ACPI_OBJECT *)bif_buffer.Pointer; 334 if (!ACPI_PKG_VALID(res, 13)) { 335 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 336 "battery info corrupted\n"); 337 goto end; 338 } 339 340 if (acpi_PkgInt32(res, 0, &sc->bif.units) != 0) 341 goto end; 342 if (acpi_PkgInt32(res, 1, &sc->bif.dcap) != 0) 343 goto end; 344 if (acpi_PkgInt32(res, 2, &sc->bif.lfcap) != 0) 345 goto end; 346 if (acpi_PkgInt32(res, 3, &sc->bif.btech) != 0) 347 goto end; 348 if (acpi_PkgInt32(res, 4, &sc->bif.dvol) != 0) 349 goto end; 350 if (acpi_PkgInt32(res, 5, &sc->bif.wcap) != 0) 351 goto end; 352 if (acpi_PkgInt32(res, 6, &sc->bif.lcap) != 0) 353 goto end; 354 if (acpi_PkgInt32(res, 7, &sc->bif.gra1) != 0) 355 goto end; 356 if (acpi_PkgInt32(res, 8, &sc->bif.gra2) != 0) 357 goto end; 358 if (acpi_PkgStr(res, 9, sc->bif.model, ACPI_CMBAT_MAXSTRLEN) != 0) 359 goto end; 360 if (acpi_PkgStr(res, 10, sc->bif.serial, ACPI_CMBAT_MAXSTRLEN) != 0) 361 goto end; 362 if (acpi_PkgStr(res, 11, sc->bif.type, ACPI_CMBAT_MAXSTRLEN) != 0) 363 goto end; 364 if (acpi_PkgStr(res, 12, sc->bif.oeminfo, ACPI_CMBAT_MAXSTRLEN) != 0) 365 goto end; 366 367 end: 368 if (bif_buffer.Pointer != NULL) 369 AcpiOsFree(bif_buffer.Pointer); 370 } 371 372 static int 373 acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp) 374 { 375 struct acpi_cmbat_softc *sc; 376 377 sc = device_get_softc(dev); 378 379 /* 380 * Just copy the data. The only value that should change is the 381 * last-full capacity, so we only update when we get a notify that says 382 * the info has changed. Many systems apparently take a long time to 383 * process a _BIF call so we avoid it if possible. 384 */ 385 ACPI_SERIAL_BEGIN(cmbat); 386 bifp->units = sc->bif.units; 387 bifp->dcap = sc->bif.dcap; 388 bifp->lfcap = sc->bif.lfcap; 389 bifp->btech = sc->bif.btech; 390 bifp->dvol = sc->bif.dvol; 391 bifp->wcap = sc->bif.wcap; 392 bifp->lcap = sc->bif.lcap; 393 bifp->gra1 = sc->bif.gra1; 394 bifp->gra2 = sc->bif.gra2; 395 strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model)); 396 strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial)); 397 strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type)); 398 strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo)); 399 ACPI_SERIAL_END(cmbat); 400 401 return (0); 402 } 403 404 static int 405 acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp) 406 { 407 struct acpi_cmbat_softc *sc; 408 409 sc = device_get_softc(dev); 410 411 ACPI_SERIAL_BEGIN(cmbat); 412 if (acpi_BatteryIsPresent(dev)) { 413 acpi_cmbat_get_bst(dev); 414 bstp->state = sc->bst.state; 415 bstp->rate = sc->bst.rate; 416 bstp->cap = sc->bst.cap; 417 bstp->volt = sc->bst.volt; 418 } else 419 bstp->state = ACPI_BATT_STAT_NOT_PRESENT; 420 ACPI_SERIAL_END(cmbat); 421 422 return (0); 423 } 424 425 static void 426 acpi_cmbat_init_battery(void *arg) 427 { 428 struct acpi_cmbat_softc *sc; 429 int retry, valid; 430 device_t dev; 431 432 dev = (device_t)arg; 433 sc = device_get_softc(dev); 434 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 435 "battery initialization start\n"); 436 437 /* 438 * Try repeatedly to get valid data from the battery. Since the 439 * embedded controller isn't always ready just after boot, we may have 440 * to wait a while. 441 */ 442 for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) { 443 /* batteries on DOCK can be ejected w/ DOCK during retrying */ 444 if (!device_is_attached(dev)) 445 return; 446 447 if (!acpi_BatteryIsPresent(dev)) 448 continue; 449 450 /* 451 * Only query the battery if this is the first try or the specific 452 * type of info is still invalid. 453 */ 454 ACPI_SERIAL_BEGIN(cmbat); 455 if (retry == 0 || !acpi_battery_bst_valid(&sc->bst)) { 456 timespecclear(&sc->bst_lastupdated); 457 acpi_cmbat_get_bst(dev); 458 } 459 if (retry == 0 || !acpi_battery_bif_valid(&sc->bif)) 460 acpi_cmbat_get_bif(dev); 461 462 valid = acpi_battery_bst_valid(&sc->bst) && 463 acpi_battery_bif_valid(&sc->bif); 464 ACPI_SERIAL_END(cmbat); 465 466 if (valid) 467 break; 468 } 469 470 if (retry == ACPI_CMBAT_RETRY_MAX) { 471 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 472 "battery initialization failed, giving up\n"); 473 } else { 474 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 475 "battery initialization done, tried %d times\n", retry + 1); 476 } 477 } 478