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 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include "opt_acpi.h" 34 #include <sys/param.h> 35 #include <sys/kernel.h> 36 #include <sys/module.h> 37 #include <sys/bus.h> 38 #include <sys/ioccom.h> 39 40 #include <machine/bus.h> 41 #include <sys/rman.h> 42 #include <sys/malloc.h> 43 44 #include <contrib/dev/acpica/include/acpi.h> 45 46 #include <dev/acpica/acpivar.h> 47 #include <dev/acpica/acpiio.h> 48 49 static MALLOC_DEFINE(M_ACPICMBAT, "acpicmbat", 50 "ACPI control method battery data"); 51 52 /* Number of times to retry initialization before giving up. */ 53 #define ACPI_CMBAT_RETRY_MAX 6 54 55 /* Check the battery once a minute. */ 56 #define CMBAT_POLLRATE (60 * hz) 57 58 /* Hooks for the ACPI CA debugging infrastructure */ 59 #define _COMPONENT ACPI_BATTERY 60 ACPI_MODULE_NAME("BATTERY") 61 62 #define ACPI_BATTERY_BST_CHANGE 0x80 63 #define ACPI_BATTERY_BIF_CHANGE 0x81 64 65 struct acpi_cmbat_softc { 66 device_t dev; 67 int flags; 68 69 struct acpi_bif bif; 70 struct acpi_bst bst; 71 struct timespec bst_lastupdated; 72 }; 73 74 ACPI_SERIAL_DECL(cmbat, "ACPI cmbat"); 75 76 static int acpi_cmbat_probe(device_t dev); 77 static int acpi_cmbat_attach(device_t dev); 78 static int acpi_cmbat_detach(device_t dev); 79 static int acpi_cmbat_resume(device_t dev); 80 static void acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, 81 void *context); 82 static int acpi_cmbat_info_expired(struct timespec *lastupdated); 83 static void acpi_cmbat_info_updated(struct timespec *lastupdated); 84 static void acpi_cmbat_get_bst(void *arg); 85 static void acpi_cmbat_get_bif_task(void *arg); 86 static void acpi_cmbat_get_bif(void *arg); 87 static int acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp); 88 static int acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp); 89 static void acpi_cmbat_init_battery(void *arg); 90 91 static device_method_t acpi_cmbat_methods[] = { 92 /* Device interface */ 93 DEVMETHOD(device_probe, acpi_cmbat_probe), 94 DEVMETHOD(device_attach, acpi_cmbat_attach), 95 DEVMETHOD(device_detach, acpi_cmbat_detach), 96 DEVMETHOD(device_resume, acpi_cmbat_resume), 97 98 /* ACPI battery interface */ 99 DEVMETHOD(acpi_batt_get_info, acpi_cmbat_bif), 100 DEVMETHOD(acpi_batt_get_status, acpi_cmbat_bst), 101 102 DEVMETHOD_END 103 }; 104 105 static driver_t acpi_cmbat_driver = { 106 "battery", 107 acpi_cmbat_methods, 108 sizeof(struct acpi_cmbat_softc), 109 }; 110 111 static devclass_t acpi_cmbat_devclass; 112 DRIVER_MODULE(acpi_cmbat, acpi, acpi_cmbat_driver, acpi_cmbat_devclass, 0, 0); 113 MODULE_DEPEND(acpi_cmbat, acpi, 1, 1, 1); 114 115 static int 116 acpi_cmbat_probe(device_t dev) 117 { 118 static char *cmbat_ids[] = { "PNP0C0A", NULL }; 119 int rv; 120 121 if (acpi_disabled("cmbat")) 122 return (ENXIO); 123 rv = ACPI_ID_PROBE(device_get_parent(dev), dev, cmbat_ids, NULL); 124 if (rv <= 0) 125 device_set_desc(dev, "ACPI Control Method Battery"); 126 return (rv); 127 } 128 129 static int 130 acpi_cmbat_attach(device_t dev) 131 { 132 int error; 133 ACPI_HANDLE handle; 134 struct acpi_cmbat_softc *sc; 135 136 sc = device_get_softc(dev); 137 handle = acpi_get_handle(dev); 138 sc->dev = dev; 139 140 timespecclear(&sc->bst_lastupdated); 141 142 error = acpi_battery_register(dev); 143 if (error != 0) { 144 device_printf(dev, "registering battery failed\n"); 145 return (error); 146 } 147 148 /* 149 * Install a system notify handler in addition to the device notify. 150 * Toshiba notebook uses this alternate notify for its battery. 151 */ 152 AcpiInstallNotifyHandler(handle, ACPI_ALL_NOTIFY, 153 acpi_cmbat_notify_handler, dev); 154 155 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_init_battery, dev); 156 157 return (0); 158 } 159 160 static int 161 acpi_cmbat_detach(device_t dev) 162 { 163 ACPI_HANDLE handle; 164 165 handle = acpi_get_handle(dev); 166 AcpiRemoveNotifyHandler(handle, ACPI_ALL_NOTIFY, acpi_cmbat_notify_handler); 167 acpi_battery_remove(dev); 168 169 /* 170 * Force any pending notification handler calls to complete by 171 * requesting cmbat serialisation while freeing and clearing the 172 * softc pointer: 173 */ 174 ACPI_SERIAL_BEGIN(cmbat); 175 device_set_softc(dev, NULL); 176 ACPI_SERIAL_END(cmbat); 177 178 return (0); 179 } 180 181 static int 182 acpi_cmbat_resume(device_t dev) 183 { 184 185 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_init_battery, dev); 186 return (0); 187 } 188 189 static void 190 acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 191 { 192 struct acpi_cmbat_softc *sc; 193 device_t dev; 194 195 dev = (device_t)context; 196 sc = device_get_softc(dev); 197 198 switch (notify) { 199 case ACPI_NOTIFY_DEVICE_CHECK: 200 case ACPI_BATTERY_BST_CHANGE: 201 /* 202 * Clear the last updated time. The next call to retrieve the 203 * battery status will get the new value for us. 204 */ 205 timespecclear(&sc->bst_lastupdated); 206 break; 207 case ACPI_NOTIFY_BUS_CHECK: 208 case ACPI_BATTERY_BIF_CHANGE: 209 /* 210 * Queue a callback to get the current battery info from thread 211 * context. It's not safe to block in a notify handler. 212 */ 213 AcpiOsExecute(OSL_NOTIFY_HANDLER, acpi_cmbat_get_bif_task, dev); 214 break; 215 } 216 217 acpi_UserNotify("CMBAT", h, notify); 218 } 219 220 static int 221 acpi_cmbat_info_expired(struct timespec *lastupdated) 222 { 223 struct timespec curtime; 224 225 ACPI_SERIAL_ASSERT(cmbat); 226 227 if (lastupdated == NULL) 228 return (TRUE); 229 if (!timespecisset(lastupdated)) 230 return (TRUE); 231 232 getnanotime(&curtime); 233 timespecsub(&curtime, lastupdated, &curtime); 234 return (curtime.tv_sec < 0 || 235 curtime.tv_sec > acpi_battery_get_info_expire()); 236 } 237 238 static void 239 acpi_cmbat_info_updated(struct timespec *lastupdated) 240 { 241 242 ACPI_SERIAL_ASSERT(cmbat); 243 244 if (lastupdated != NULL) 245 getnanotime(lastupdated); 246 } 247 248 static void 249 acpi_cmbat_get_bst(void *arg) 250 { 251 struct acpi_cmbat_softc *sc; 252 ACPI_STATUS as; 253 ACPI_OBJECT *res; 254 ACPI_HANDLE h; 255 ACPI_BUFFER bst_buffer; 256 device_t dev; 257 258 ACPI_SERIAL_ASSERT(cmbat); 259 260 dev = arg; 261 sc = device_get_softc(dev); 262 h = acpi_get_handle(dev); 263 bst_buffer.Pointer = NULL; 264 bst_buffer.Length = ACPI_ALLOCATE_BUFFER; 265 266 if (!acpi_cmbat_info_expired(&sc->bst_lastupdated)) 267 goto end; 268 269 as = AcpiEvaluateObject(h, "_BST", NULL, &bst_buffer); 270 if (ACPI_FAILURE(as)) { 271 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 272 "error fetching current battery status -- %s\n", 273 AcpiFormatException(as)); 274 goto end; 275 } 276 277 res = (ACPI_OBJECT *)bst_buffer.Pointer; 278 if (!ACPI_PKG_VALID(res, 4)) { 279 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 280 "battery status corrupted\n"); 281 goto end; 282 } 283 284 if (acpi_PkgInt32(res, 0, &sc->bst.state) != 0) 285 goto end; 286 if (acpi_PkgInt32(res, 1, &sc->bst.rate) != 0) 287 goto end; 288 if (acpi_PkgInt32(res, 2, &sc->bst.cap) != 0) 289 goto end; 290 if (acpi_PkgInt32(res, 3, &sc->bst.volt) != 0) 291 goto end; 292 acpi_cmbat_info_updated(&sc->bst_lastupdated); 293 294 /* Clear out undefined/extended bits that might be set by hardware. */ 295 sc->bst.state &= ACPI_BATT_STAT_BST_MASK; 296 if ((sc->bst.state & ACPI_BATT_STAT_INVALID) == ACPI_BATT_STAT_INVALID) 297 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 298 "battery reports simultaneous charging and discharging\n"); 299 300 /* XXX If all batteries are critical, perhaps we should suspend. */ 301 if (sc->bst.state & ACPI_BATT_STAT_CRITICAL) { 302 if ((sc->flags & ACPI_BATT_STAT_CRITICAL) == 0) { 303 sc->flags |= ACPI_BATT_STAT_CRITICAL; 304 device_printf(dev, "critically low charge!\n"); 305 } 306 } else 307 sc->flags &= ~ACPI_BATT_STAT_CRITICAL; 308 309 end: 310 if (bst_buffer.Pointer != NULL) 311 AcpiOsFree(bst_buffer.Pointer); 312 } 313 314 /* XXX There should be a cleaner way to do this locking. */ 315 static void 316 acpi_cmbat_get_bif_task(void *arg) 317 { 318 319 ACPI_SERIAL_BEGIN(cmbat); 320 acpi_cmbat_get_bif(arg); 321 ACPI_SERIAL_END(cmbat); 322 } 323 324 static void 325 acpi_cmbat_get_bif(void *arg) 326 { 327 struct acpi_cmbat_softc *sc; 328 ACPI_STATUS as; 329 ACPI_OBJECT *res; 330 ACPI_HANDLE h; 331 ACPI_BUFFER bif_buffer; 332 device_t dev; 333 334 ACPI_SERIAL_ASSERT(cmbat); 335 336 dev = arg; 337 sc = device_get_softc(dev); 338 h = acpi_get_handle(dev); 339 bif_buffer.Pointer = NULL; 340 bif_buffer.Length = ACPI_ALLOCATE_BUFFER; 341 342 as = AcpiEvaluateObject(h, "_BIF", NULL, &bif_buffer); 343 if (ACPI_FAILURE(as)) { 344 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 345 "error fetching current battery info -- %s\n", 346 AcpiFormatException(as)); 347 goto end; 348 } 349 350 res = (ACPI_OBJECT *)bif_buffer.Pointer; 351 if (!ACPI_PKG_VALID(res, 13)) { 352 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 353 "battery info corrupted\n"); 354 goto end; 355 } 356 357 if (acpi_PkgInt32(res, 0, &sc->bif.units) != 0) 358 goto end; 359 if (acpi_PkgInt32(res, 1, &sc->bif.dcap) != 0) 360 goto end; 361 if (acpi_PkgInt32(res, 2, &sc->bif.lfcap) != 0) 362 goto end; 363 if (acpi_PkgInt32(res, 3, &sc->bif.btech) != 0) 364 goto end; 365 if (acpi_PkgInt32(res, 4, &sc->bif.dvol) != 0) 366 goto end; 367 if (acpi_PkgInt32(res, 5, &sc->bif.wcap) != 0) 368 goto end; 369 if (acpi_PkgInt32(res, 6, &sc->bif.lcap) != 0) 370 goto end; 371 if (acpi_PkgInt32(res, 7, &sc->bif.gra1) != 0) 372 goto end; 373 if (acpi_PkgInt32(res, 8, &sc->bif.gra2) != 0) 374 goto end; 375 if (acpi_PkgStr(res, 9, sc->bif.model, ACPI_CMBAT_MAXSTRLEN) != 0) 376 goto end; 377 if (acpi_PkgStr(res, 10, sc->bif.serial, ACPI_CMBAT_MAXSTRLEN) != 0) 378 goto end; 379 if (acpi_PkgStr(res, 11, sc->bif.type, ACPI_CMBAT_MAXSTRLEN) != 0) 380 goto end; 381 if (acpi_PkgStr(res, 12, sc->bif.oeminfo, ACPI_CMBAT_MAXSTRLEN) != 0) 382 goto end; 383 384 end: 385 if (bif_buffer.Pointer != NULL) 386 AcpiOsFree(bif_buffer.Pointer); 387 } 388 389 static int 390 acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp) 391 { 392 struct acpi_cmbat_softc *sc; 393 394 sc = device_get_softc(dev); 395 396 /* 397 * Just copy the data. The only value that should change is the 398 * last-full capacity, so we only update when we get a notify that says 399 * the info has changed. Many systems apparently take a long time to 400 * process a _BIF call so we avoid it if possible. 401 */ 402 ACPI_SERIAL_BEGIN(cmbat); 403 bifp->units = sc->bif.units; 404 bifp->dcap = sc->bif.dcap; 405 bifp->lfcap = sc->bif.lfcap; 406 bifp->btech = sc->bif.btech; 407 bifp->dvol = sc->bif.dvol; 408 bifp->wcap = sc->bif.wcap; 409 bifp->lcap = sc->bif.lcap; 410 bifp->gra1 = sc->bif.gra1; 411 bifp->gra2 = sc->bif.gra2; 412 strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model)); 413 strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial)); 414 strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type)); 415 strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo)); 416 ACPI_SERIAL_END(cmbat); 417 418 return (0); 419 } 420 421 static int 422 acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp) 423 { 424 struct acpi_cmbat_softc *sc; 425 426 sc = device_get_softc(dev); 427 428 ACPI_SERIAL_BEGIN(cmbat); 429 if (acpi_BatteryIsPresent(dev)) { 430 acpi_cmbat_get_bst(dev); 431 bstp->state = sc->bst.state; 432 bstp->rate = sc->bst.rate; 433 bstp->cap = sc->bst.cap; 434 bstp->volt = sc->bst.volt; 435 } else 436 bstp->state = ACPI_BATT_STAT_NOT_PRESENT; 437 ACPI_SERIAL_END(cmbat); 438 439 return (0); 440 } 441 442 static void 443 acpi_cmbat_init_battery(void *arg) 444 { 445 struct acpi_cmbat_softc *sc; 446 int retry, valid; 447 device_t dev; 448 449 dev = (device_t)arg; 450 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 451 "battery initialization start\n"); 452 453 /* 454 * Try repeatedly to get valid data from the battery. Since the 455 * embedded controller isn't always ready just after boot, we may have 456 * to wait a while. 457 */ 458 for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) { 459 /* 460 * Batteries on DOCK can be ejected w/ DOCK during retrying. 461 * 462 * If there is a valid softc pointer the device may be in 463 * attaching, attached or detaching state. If the state is 464 * different from attached retry getting the device state 465 * until it becomes stable. This solves a race if the ACPI 466 * notification handler is called during attach, because 467 * device_is_attached() doesn't return non-zero until after 468 * the attach code has been executed. 469 */ 470 ACPI_SERIAL_BEGIN(cmbat); 471 sc = device_get_softc(dev); 472 if (sc == NULL) { 473 ACPI_SERIAL_END(cmbat); 474 return; 475 } 476 477 if (!acpi_BatteryIsPresent(dev) || !device_is_attached(dev)) { 478 ACPI_SERIAL_END(cmbat); 479 continue; 480 } 481 482 /* 483 * Only query the battery if this is the first try or the specific 484 * type of info is still invalid. 485 */ 486 if (retry == 0 || !acpi_battery_bst_valid(&sc->bst)) { 487 timespecclear(&sc->bst_lastupdated); 488 acpi_cmbat_get_bst(dev); 489 } 490 if (retry == 0 || !acpi_battery_bif_valid(&sc->bif)) 491 acpi_cmbat_get_bif(dev); 492 493 valid = acpi_battery_bst_valid(&sc->bst) && 494 acpi_battery_bif_valid(&sc->bif); 495 ACPI_SERIAL_END(cmbat); 496 497 if (valid) 498 break; 499 } 500 501 if (retry == ACPI_CMBAT_RETRY_MAX) { 502 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 503 "battery initialization failed, giving up\n"); 504 } else { 505 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 506 "battery initialization done, tried %d times\n", retry + 1); 507 } 508 } 509