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