acpi_cmbat.c (139057) | acpi_cmbat.c (148352) |
---|---|
1/*- | 1/*- |
2 * Copyright (c) 2005 Nate Lawson |
|
2 * Copyright (c) 2000 Munehiro Matsuda 3 * Copyright (c) 2000 Takanori Watanabe 4 * Copyright (c) 2000 Mitsuru IWASAKI <iwasaki@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: --- 9 unchanged lines hidden (view full) --- 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. | 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: --- 9 unchanged lines hidden (view full) --- 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. |
27 * 28 * $FreeBSD: head/sys/dev/acpica/acpi_cmbat.c 139057 2004-12-20 05:03:41Z njl $ | |
29 */ 30 | 28 */ 29 |
30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: head/sys/dev/acpica/acpi_cmbat.c 148352 2005-07-23 19:36:00Z njl $"); 32 |
|
31#include "opt_acpi.h" 32#include <sys/param.h> 33#include <sys/kernel.h> 34#include <sys/module.h> 35#include <sys/bus.h> 36#include <sys/ioccom.h> 37 38#include <machine/bus.h> --- 16 unchanged lines hidden (view full) --- 55#define _COMPONENT ACPI_BATTERY 56ACPI_MODULE_NAME("BATTERY") 57 58#define ACPI_BATTERY_BST_CHANGE 0x80 59#define ACPI_BATTERY_BIF_CHANGE 0x81 60 61struct acpi_cmbat_softc { 62 device_t dev; | 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> --- 16 unchanged lines hidden (view full) --- 57#define _COMPONENT ACPI_BATTERY 58ACPI_MODULE_NAME("BATTERY") 59 60#define ACPI_BATTERY_BST_CHANGE 0x80 61#define ACPI_BATTERY_BIF_CHANGE 0x81 62 63struct acpi_cmbat_softc { 64 device_t dev; |
65 int flags; |
|
63 64 struct acpi_bif bif; 65 struct acpi_bst bst; 66 struct timespec bif_lastupdated; 67 struct timespec bst_lastupdated; | 66 67 struct acpi_bif bif; 68 struct acpi_bst bst; 69 struct timespec bif_lastupdated; 70 struct timespec bst_lastupdated; |
68 69 int flags; 70 int present; 71 int cap; 72 int min; 73 int full_charge_time; 74 int initializing; 75 int phys_unit; | |
76}; 77 | 71}; 72 |
78static struct timespec acpi_cmbat_info_lastupdated; | |
79ACPI_SERIAL_DECL(cmbat, "ACPI cmbat"); 80 | 73ACPI_SERIAL_DECL(cmbat, "ACPI cmbat"); 74 |
81/* XXX: devclass_get_maxunit() don't give us the current allocated units. */ 82static int acpi_cmbat_units = 0; | 75static int acpi_cmbat_probe(device_t dev); 76static int acpi_cmbat_attach(device_t dev); 77static int acpi_cmbat_detach(device_t dev); 78static int acpi_cmbat_resume(device_t dev); 79static void acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, 80 void *context); 81static int acpi_cmbat_info_expired(struct timespec *lastupdated); 82static void acpi_cmbat_info_updated(struct timespec *lastupdated); 83static void acpi_cmbat_get_bst(device_t dev); 84static void acpi_cmbat_get_bif(device_t dev); 85static int acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp); 86static int acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp); 87static void acpi_cmbat_init_battery(void *arg); |
83 | 88 |
84static int acpi_cmbat_info_expired(struct timespec *); 85static void acpi_cmbat_info_updated(struct timespec *); 86static void acpi_cmbat_get_bst(void *); 87static void acpi_cmbat_get_bif(void *); 88static void acpi_cmbat_notify_handler(ACPI_HANDLE, UINT32, void *); 89static int acpi_cmbat_probe(device_t); 90static int acpi_cmbat_attach(device_t); 91static int acpi_cmbat_detach(device_t); 92static int acpi_cmbat_resume(device_t); 93static int acpi_cmbat_ioctl(u_long, caddr_t, void *); 94static int acpi_cmbat_is_bst_valid(struct acpi_bst*); 95static int acpi_cmbat_is_bif_valid(struct acpi_bif*); 96static int acpi_cmbat_get_total_battinfo(struct acpi_battinfo *); 97static void acpi_cmbat_init_battery(void *); 98 | |
99static device_method_t acpi_cmbat_methods[] = { 100 /* Device interface */ 101 DEVMETHOD(device_probe, acpi_cmbat_probe), 102 DEVMETHOD(device_attach, acpi_cmbat_attach), 103 DEVMETHOD(device_detach, acpi_cmbat_detach), 104 DEVMETHOD(device_resume, acpi_cmbat_resume), 105 | 89static device_method_t acpi_cmbat_methods[] = { 90 /* Device interface */ 91 DEVMETHOD(device_probe, acpi_cmbat_probe), 92 DEVMETHOD(device_attach, acpi_cmbat_attach), 93 DEVMETHOD(device_detach, acpi_cmbat_detach), 94 DEVMETHOD(device_resume, acpi_cmbat_resume), 95 |
96 /* ACPI battery interface */ 97 DEVMETHOD(acpi_batt_get_info, acpi_cmbat_bif), 98 DEVMETHOD(acpi_batt_get_status, acpi_cmbat_bst), 99 |
|
106 {0, 0} 107}; 108 109static driver_t acpi_cmbat_driver = { | 100 {0, 0} 101}; 102 103static driver_t acpi_cmbat_driver = { |
110 "acpi_cmbat", | 104 "battery", |
111 acpi_cmbat_methods, 112 sizeof(struct acpi_cmbat_softc), 113}; 114 115static devclass_t acpi_cmbat_devclass; 116DRIVER_MODULE(acpi_cmbat, acpi, acpi_cmbat_driver, acpi_cmbat_devclass, 0, 0); 117MODULE_DEPEND(acpi_cmbat, acpi, 1, 1, 1); 118 119static int | 105 acpi_cmbat_methods, 106 sizeof(struct acpi_cmbat_softc), 107}; 108 109static devclass_t acpi_cmbat_devclass; 110DRIVER_MODULE(acpi_cmbat, acpi, acpi_cmbat_driver, acpi_cmbat_devclass, 0, 0); 111MODULE_DEPEND(acpi_cmbat, acpi, 1, 1, 1); 112 113static int |
114acpi_cmbat_probe(device_t dev) 115{ 116 static char *cmbat_ids[] = { "PNP0C0A", NULL }; 117 118 if (acpi_disabled("cmbat") || 119 ACPI_ID_PROBE(device_get_parent(dev), dev, cmbat_ids) == NULL) 120 return (ENXIO); 121 122 device_set_desc(dev, "ACPI Control Method Battery"); 123 return (0); 124} 125 126static int 127acpi_cmbat_attach(device_t dev) 128{ 129 int error; 130 ACPI_HANDLE handle; 131 struct acpi_cmbat_softc *sc; 132 133 sc = device_get_softc(dev); 134 handle = acpi_get_handle(dev); 135 sc->dev = dev; 136 137 timespecclear(&sc->bif_lastupdated); 138 timespecclear(&sc->bst_lastupdated); 139 140 error = acpi_battery_register(dev); 141 if (error != 0) { 142 device_printf(dev, "registering battery failed\n"); 143 return (error); 144 } 145 146 /* 147 * Install a system notify handler in addition to the device notify. 148 * Toshiba notebook uses this alternate notify for its battery. 149 */ 150 AcpiInstallNotifyHandler(handle, ACPI_ALL_NOTIFY, 151 acpi_cmbat_notify_handler, dev); 152 153 AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev); 154 155 return (0); 156} 157 158static int 159acpi_cmbat_detach(device_t dev) 160{ 161 162 acpi_battery_remove(dev); 163 return (0); 164} 165 166static int 167acpi_cmbat_resume(device_t dev) 168{ 169 170 AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev); 171 return (0); 172} 173 174static void 175acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 176{ 177 struct acpi_cmbat_softc *sc; 178 device_t dev; 179 180 dev = (device_t)context; 181 sc = device_get_softc(dev); 182 183 /* 184 * Clear the appropriate last updated time. The next call to retrieve 185 * the battery status will get the new value for us. We don't need to 186 * acquire a lock since we are only clearing the time stamp and since 187 * calling _BST/_BIF can trigger a notify, we could deadlock also. 188 */ 189 switch (notify) { 190 case ACPI_NOTIFY_DEVICE_CHECK: 191 case ACPI_BATTERY_BST_CHANGE: 192 timespecclear(&sc->bst_lastupdated); 193 break; 194 case ACPI_NOTIFY_BUS_CHECK: 195 case ACPI_BATTERY_BIF_CHANGE: 196 timespecclear(&sc->bif_lastupdated); 197 break; 198 } 199 200 acpi_UserNotify("CMBAT", h, notify); 201} 202 203static int |
|
120acpi_cmbat_info_expired(struct timespec *lastupdated) 121{ 122 struct timespec curtime; 123 124 ACPI_SERIAL_ASSERT(cmbat); 125 126 if (lastupdated == NULL) 127 return (TRUE); --- 12 unchanged lines hidden (view full) --- 140 141 ACPI_SERIAL_ASSERT(cmbat); 142 143 if (lastupdated != NULL) 144 getnanotime(lastupdated); 145} 146 147static void | 204acpi_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); --- 12 unchanged lines hidden (view full) --- 224 225 ACPI_SERIAL_ASSERT(cmbat); 226 227 if (lastupdated != NULL) 228 getnanotime(lastupdated); 229} 230 231static void |
148acpi_cmbat_get_bst(void *context) | 232acpi_cmbat_get_bst(device_t dev) |
149{ | 233{ |
150 device_t dev; | |
151 struct acpi_cmbat_softc *sc; 152 ACPI_STATUS as; 153 ACPI_OBJECT *res; 154 ACPI_HANDLE h; 155 ACPI_BUFFER bst_buffer; 156 157 ACPI_SERIAL_ASSERT(cmbat); 158 | 234 struct acpi_cmbat_softc *sc; 235 ACPI_STATUS as; 236 ACPI_OBJECT *res; 237 ACPI_HANDLE h; 238 ACPI_BUFFER bst_buffer; 239 240 ACPI_SERIAL_ASSERT(cmbat); 241 |
159 dev = context; | |
160 sc = device_get_softc(dev); 161 h = acpi_get_handle(dev); 162 bst_buffer.Pointer = NULL; 163 bst_buffer.Length = ACPI_ALLOCATE_BUFFER; 164 165 if (!acpi_cmbat_info_expired(&sc->bst_lastupdated)) 166 goto end; 167 --- 32 unchanged lines hidden (view full) --- 200 sc->flags &= ~ACPI_BATT_STAT_CRITICAL; 201 202end: 203 if (bst_buffer.Pointer != NULL) 204 AcpiOsFree(bst_buffer.Pointer); 205} 206 207static void | 242 sc = device_get_softc(dev); 243 h = acpi_get_handle(dev); 244 bst_buffer.Pointer = NULL; 245 bst_buffer.Length = ACPI_ALLOCATE_BUFFER; 246 247 if (!acpi_cmbat_info_expired(&sc->bst_lastupdated)) 248 goto end; 249 --- 32 unchanged lines hidden (view full) --- 282 sc->flags &= ~ACPI_BATT_STAT_CRITICAL; 283 284end: 285 if (bst_buffer.Pointer != NULL) 286 AcpiOsFree(bst_buffer.Pointer); 287} 288 289static void |
208acpi_cmbat_get_bif(void *context) | 290acpi_cmbat_get_bif(device_t dev) |
209{ | 291{ |
210 device_t dev; | |
211 struct acpi_cmbat_softc *sc; 212 ACPI_STATUS as; 213 ACPI_OBJECT *res; 214 ACPI_HANDLE h; 215 ACPI_BUFFER bif_buffer; 216 217 ACPI_SERIAL_ASSERT(cmbat); 218 | 292 struct acpi_cmbat_softc *sc; 293 ACPI_STATUS as; 294 ACPI_OBJECT *res; 295 ACPI_HANDLE h; 296 ACPI_BUFFER bif_buffer; 297 298 ACPI_SERIAL_ASSERT(cmbat); 299 |
219 dev = context; | |
220 sc = device_get_softc(dev); 221 h = acpi_get_handle(dev); 222 bif_buffer.Pointer = NULL; 223 bif_buffer.Length = ACPI_ALLOCATE_BUFFER; 224 225 if (!acpi_cmbat_info_expired(&sc->bif_lastupdated)) 226 goto end; 227 --- 40 unchanged lines hidden (view full) --- 268 goto end; 269 acpi_cmbat_info_updated(&sc->bif_lastupdated); 270 271end: 272 if (bif_buffer.Pointer != NULL) 273 AcpiOsFree(bif_buffer.Pointer); 274} 275 | 300 sc = device_get_softc(dev); 301 h = acpi_get_handle(dev); 302 bif_buffer.Pointer = NULL; 303 bif_buffer.Length = ACPI_ALLOCATE_BUFFER; 304 305 if (!acpi_cmbat_info_expired(&sc->bif_lastupdated)) 306 goto end; 307 --- 40 unchanged lines hidden (view full) --- 348 goto end; 349 acpi_cmbat_info_updated(&sc->bif_lastupdated); 350 351end: 352 if (bif_buffer.Pointer != NULL) 353 AcpiOsFree(bif_buffer.Pointer); 354} 355 |
276static void 277acpi_cmbat_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context) 278{ 279 device_t dev; 280 struct acpi_cmbat_softc *sc; 281 282 dev = (device_t)context; 283 sc = device_get_softc(dev); 284 285 acpi_UserNotify("CMBAT", h, notify); 286 287 /* 288 * Clear the appropriate last updated time. The next call to retrieve 289 * the battery status will get the new value for us. We don't need to 290 * acquire a lock since we are only clearing the time stamp and since 291 * calling _BST/_BIF can trigger a notify, we could deadlock also. 292 */ 293 switch (notify) { 294 case ACPI_NOTIFY_DEVICE_CHECK: 295 case ACPI_BATTERY_BST_CHANGE: 296 timespecclear(&sc->bst_lastupdated); 297 break; 298 case ACPI_NOTIFY_BUS_CHECK: 299 case ACPI_BATTERY_BIF_CHANGE: 300 timespecclear(&sc->bif_lastupdated); 301 break; 302 default: 303 break; 304 } 305} 306 | |
307static int | 356static int |
308acpi_cmbat_probe(device_t dev) | 357acpi_cmbat_bif(device_t dev, struct acpi_bif *bifp) |
309{ | 358{ |
310 static char *cmbat_ids[] = { "PNP0C0A", NULL }; 311 312 if (acpi_disabled("cmbat") || 313 ACPI_ID_PROBE(device_get_parent(dev), dev, cmbat_ids) == NULL) 314 return (ENXIO); 315 316 device_set_desc(dev, "Control Method Battery"); 317 return (0); 318} 319 320static int 321acpi_cmbat_attach(device_t dev) 322{ 323 int error; 324 ACPI_HANDLE handle; | |
325 struct acpi_cmbat_softc *sc; 326 327 sc = device_get_softc(dev); | 359 struct acpi_cmbat_softc *sc; 360 361 sc = device_get_softc(dev); |
328 handle = acpi_get_handle(dev); 329 sc->dev = dev; | |
330 | 362 |
331 /* 332 * Install a system notify handler in addition to the device notify. 333 * Toshiba notebook uses this alternate notify for its battery. 334 */ 335 AcpiInstallNotifyHandler(handle, ACPI_ALL_NOTIFY, 336 acpi_cmbat_notify_handler, dev); 337 | |
338 ACPI_SERIAL_BEGIN(cmbat); | 363 ACPI_SERIAL_BEGIN(cmbat); |
339 timespecclear(&sc->bif_lastupdated); 340 timespecclear(&sc->bst_lastupdated); 341 342 if (acpi_cmbat_units == 0) { 343 error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BIF, 344 acpi_cmbat_ioctl, NULL); 345 if (error != 0) { 346 device_printf(dev, "register bif ioctl failed\n"); 347 return (error); 348 } 349 error = acpi_register_ioctl(ACPIIO_CMBAT_GET_BST, 350 acpi_cmbat_ioctl, NULL); 351 if (error != 0) { 352 device_printf(dev, "register bst ioctl failed\n"); 353 return (error); 354 } 355 } 356 357 sc->phys_unit = acpi_cmbat_units; 358 error = acpi_battery_register(ACPI_BATT_TYPE_CMBAT, sc->phys_unit); 359 if (error != 0) { 360 device_printf(dev, "registering battery %d failed\n", sc->phys_unit); 361 return (error); 362 } 363 acpi_cmbat_units++; 364 timespecclear(&acpi_cmbat_info_lastupdated); | 364 acpi_cmbat_get_bif(dev); 365 bifp->units = sc->bif.units; 366 bifp->dcap = sc->bif.dcap; 367 bifp->lfcap = sc->bif.lfcap; 368 bifp->btech = sc->bif.btech; 369 bifp->dvol = sc->bif.dvol; 370 bifp->wcap = sc->bif.wcap; 371 bifp->lcap = sc->bif.lcap; 372 bifp->gra1 = sc->bif.gra1; 373 bifp->gra2 = sc->bif.gra2; 374 strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model)); 375 strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial)); 376 strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type)); 377 strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo)); |
365 ACPI_SERIAL_END(cmbat); 366 | 378 ACPI_SERIAL_END(cmbat); 379 |
367 AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev); 368 | |
369 return (0); 370} 371 372static int | 380 return (0); 381} 382 383static int |
373acpi_cmbat_detach(device_t dev) | 384acpi_cmbat_bst(device_t dev, struct acpi_bst *bstp) |
374{ 375 struct acpi_cmbat_softc *sc; 376 377 sc = device_get_softc(dev); | 385{ 386 struct acpi_cmbat_softc *sc; 387 388 sc = device_get_softc(dev); |
378 ACPI_SERIAL_BEGIN(cmbat); 379 acpi_battery_remove(ACPI_BATT_TYPE_CMBAT, sc->phys_unit); 380 acpi_cmbat_units--; 381 ACPI_SERIAL_END(cmbat); 382 return (0); 383} | |
384 | 389 |
385static int 386acpi_cmbat_resume(device_t dev) 387{ 388 AcpiOsQueueForExecution(OSD_PRIORITY_LO, acpi_cmbat_init_battery, dev); 389 return (0); 390} 391 392static int 393acpi_cmbat_ioctl(u_long cmd, caddr_t addr, void *arg) 394{ 395 device_t dev; 396 union acpi_battery_ioctl_arg *ioctl_arg; 397 struct acpi_cmbat_softc *sc; 398 struct acpi_bif *bifp; 399 struct acpi_bst *bstp; 400 401 ioctl_arg = (union acpi_battery_ioctl_arg *)addr; 402 dev = devclass_get_device(acpi_cmbat_devclass, ioctl_arg->unit); 403 if (dev == NULL) 404 return (ENXIO); 405 sc = device_get_softc(dev); 406 407 /* 408 * No security check required: information retrieval only. If 409 * new functions are added here, a check might be required. 410 */ | |
411 ACPI_SERIAL_BEGIN(cmbat); | 390 ACPI_SERIAL_BEGIN(cmbat); |
412 switch (cmd) { 413 case ACPIIO_CMBAT_GET_BIF: 414 acpi_cmbat_get_bif(dev); 415 bifp = &ioctl_arg->bif; 416 bifp->units = sc->bif.units; 417 bifp->dcap = sc->bif.dcap; 418 bifp->lfcap = sc->bif.lfcap; 419 bifp->btech = sc->bif.btech; 420 bifp->dvol = sc->bif.dvol; 421 bifp->wcap = sc->bif.wcap; 422 bifp->lcap = sc->bif.lcap; 423 bifp->gra1 = sc->bif.gra1; 424 bifp->gra2 = sc->bif.gra2; 425 strncpy(bifp->model, sc->bif.model, sizeof(sc->bif.model)); 426 strncpy(bifp->serial, sc->bif.serial, sizeof(sc->bif.serial)); 427 strncpy(bifp->type, sc->bif.type, sizeof(sc->bif.type)); 428 strncpy(bifp->oeminfo, sc->bif.oeminfo, sizeof(sc->bif.oeminfo)); 429 break; 430 case ACPIIO_CMBAT_GET_BST: 431 bstp = &ioctl_arg->bst; 432 if (acpi_BatteryIsPresent(dev)) { 433 acpi_cmbat_get_bst(dev); 434 bstp->state = sc->bst.state; 435 bstp->rate = sc->bst.rate; 436 bstp->cap = sc->bst.cap; 437 bstp->volt = sc->bst.volt; 438 } else { 439 bstp->state = ACPI_BATT_STAT_NOT_PRESENT; 440 } 441 break; 442 default: 443 break; 444 } | 391 if (acpi_BatteryIsPresent(dev)) { 392 acpi_cmbat_get_bst(dev); 393 bstp->state = sc->bst.state; 394 bstp->rate = sc->bst.rate; 395 bstp->cap = sc->bst.cap; 396 bstp->volt = sc->bst.volt; 397 } else 398 bstp->state = ACPI_BATT_STAT_NOT_PRESENT; |
445 ACPI_SERIAL_END(cmbat); 446 447 return (0); 448} 449 | 399 ACPI_SERIAL_END(cmbat); 400 401 return (0); 402} 403 |
450static int 451acpi_cmbat_is_bst_valid(struct acpi_bst *bst) 452{ 453 if (bst->state >= ACPI_BATT_STAT_MAX || bst->cap == 0xffffffff || 454 bst->volt == 0xffffffff) 455 return (FALSE); 456 else 457 return (TRUE); 458} 459 460static int 461acpi_cmbat_is_bif_valid(struct acpi_bif *bif) 462{ 463 if (bif->lfcap == 0) 464 return (FALSE); 465 else 466 return (TRUE); 467} 468 469static int 470acpi_cmbat_get_total_battinfo(struct acpi_battinfo *battinfo) 471{ 472 int i; 473 int error; 474 int batt_stat; 475 int valid_rate, valid_units; 476 int cap, min; 477 int total_cap, total_min, total_full; 478 struct acpi_cmbat_softc *sc; 479 480 ACPI_SERIAL_ASSERT(cmbat); 481 482 cap = min = -1; 483 batt_stat = ACPI_BATT_STAT_NOT_PRESENT; 484 error = 0; 485 486 /* Get battery status, valid rate and valid units */ 487 batt_stat = valid_rate = valid_units = 0; 488 for (i = 0; i < acpi_cmbat_units; i++) { 489 sc = devclass_get_softc(acpi_cmbat_devclass, i); 490 if (sc == NULL) 491 continue; 492 sc->present = acpi_BatteryIsPresent(sc->dev); 493 if (!sc->present) 494 continue; 495 acpi_cmbat_get_bst(sc->dev); 496 497 /* If battery not installed, we get strange values */ 498 if (!acpi_cmbat_is_bst_valid(&sc->bst) || 499 !acpi_cmbat_is_bif_valid(&sc->bif)) { 500 sc->present = FALSE; 501 continue; 502 } 503 504 valid_units++; 505 sc->cap = 100 * sc->bst.cap / sc->bif.lfcap; 506 507 /* 508 * Some laptops report the "design-capacity" instead of the 509 * "real-capacity" when the battery is fully charged. 510 * That breaks the above arithmetic as it needs to be 100% maximum. 511 */ 512 if (sc->cap > 100) 513 sc->cap = 100; 514 515 batt_stat |= sc->bst.state; 516 517 /* 518 * XXX Hack to calculate total battery time. 519 * 520 * On systems with more than one battery, they may get used 521 * sequentially, thus bst.rate may only signify the one in use. 522 * For the remaining batteries, bst.rate will be zero, which 523 * makes it impossible to calculate the remaining time. Some 524 * other systems may need the sum of all the bst.rate values 525 * when discharging. Therefore, we sum the bst.rate for valid 526 * batteries (ones in the discharging state) and use the sum 527 * to calculate the total remaining time. 528 */ 529 if (sc->bst.rate > 0) { 530 if (sc->bst.state & ACPI_BATT_STAT_DISCHARG) 531 valid_rate += sc->bst.rate; 532 } 533 } 534 535 /* Calculate total battery capacity and time */ 536 total_cap = total_min = total_full = 0; 537 for (i = 0; i < acpi_cmbat_units; i++) { 538 sc = devclass_get_softc(acpi_cmbat_devclass, i); 539 if (!sc->present) 540 continue; 541 542 /* 543 * If any batteries are discharging, use the sum of the bst.rate 544 * values. Otherwise, use the full charge time to estimate 545 * remaining time. If neither are available, assume no charge. 546 */ 547 if (valid_rate > 0) 548 sc->min = 60 * sc->bst.cap / valid_rate; 549 else if (sc->full_charge_time > 0) 550 sc->min = (sc->full_charge_time * sc->cap) / 100; 551 else 552 sc->min = 0; 553 total_min += sc->min; 554 total_cap += sc->cap; 555 total_full += sc->full_charge_time; 556 } 557 558 /* Battery life */ 559 if (valid_units == 0) { 560 cap = -1; 561 batt_stat = ACPI_BATT_STAT_NOT_PRESENT; 562 } else 563 cap = total_cap / valid_units; 564 565 /* Battery time */ 566 if (valid_units == 0) 567 min = -1; 568 else if (valid_rate == 0 || (batt_stat & ACPI_BATT_STAT_CHARGING)) { 569 if (total_full == 0) 570 min = -1; 571 else 572 min = (total_full * cap) / 100; 573 } else 574 min = total_min; 575 acpi_cmbat_info_updated(&acpi_cmbat_info_lastupdated); 576 577 battinfo->cap = cap; 578 battinfo->min = min; 579 battinfo->state = batt_stat; 580 581 return (error); 582} 583 | |
584static void 585acpi_cmbat_init_battery(void *arg) 586{ 587 struct acpi_cmbat_softc *sc; | 404static void 405acpi_cmbat_init_battery(void *arg) 406{ 407 struct acpi_cmbat_softc *sc; |
588 int retry; | 408 int retry, valid; |
589 device_t dev; 590 591 dev = (device_t)arg; 592 sc = device_get_softc(dev); 593 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 594 "battery initialization start\n"); 595 | 409 device_t dev; 410 411 dev = (device_t)arg; 412 sc = device_get_softc(dev); 413 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 414 "battery initialization start\n"); 415 |
416 /* 417 * Try repeatedly to get valid data from the battery. Since the 418 * embedded controller isn't always ready just after boot, we may have 419 * to wait a while. 420 */ |
|
596 for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) { | 421 for (retry = 0; retry < ACPI_CMBAT_RETRY_MAX; retry++, AcpiOsSleep(10000)) { |
597 sc->present = acpi_BatteryIsPresent(dev); 598 if (!sc->present) | 422 if (!acpi_BatteryIsPresent(dev)) |
599 continue; 600 601 ACPI_SERIAL_BEGIN(cmbat); 602 timespecclear(&sc->bst_lastupdated); 603 timespecclear(&sc->bif_lastupdated); 604 acpi_cmbat_get_bst(dev); 605 acpi_cmbat_get_bif(dev); | 423 continue; 424 425 ACPI_SERIAL_BEGIN(cmbat); 426 timespecclear(&sc->bst_lastupdated); 427 timespecclear(&sc->bif_lastupdated); 428 acpi_cmbat_get_bst(dev); 429 acpi_cmbat_get_bif(dev); |
430 valid = acpi_battery_bst_valid(&sc->bst) && 431 acpi_battery_bif_valid(&sc->bif); |
|
606 ACPI_SERIAL_END(cmbat); 607 | 432 ACPI_SERIAL_END(cmbat); 433 |
608 if (acpi_cmbat_is_bst_valid(&sc->bst) && 609 acpi_cmbat_is_bif_valid(&sc->bif)) | 434 if (valid) |
610 break; 611 } 612 613 if (retry == ACPI_CMBAT_RETRY_MAX) { 614 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 615 "battery initialization failed, giving up\n"); 616 } else { 617 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 618 "battery initialization done, tried %d times\n", retry + 1); 619 } 620} | 435 break; 436 } 437 438 if (retry == ACPI_CMBAT_RETRY_MAX) { 439 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 440 "battery initialization failed, giving up\n"); 441 } else { 442 ACPI_VPRINT(dev, acpi_device_get_parent_softc(dev), 443 "battery initialization done, tried %d times\n", retry + 1); 444 } 445} |
621 622/* 623 * Public interfaces. 624 */ 625int 626acpi_cmbat_get_battinfo(int unit, struct acpi_battinfo *battinfo) 627{ 628 int error; 629 struct acpi_cmbat_softc *sc; 630 631 ACPI_SERIAL_BEGIN(cmbat); 632 error = acpi_cmbat_get_total_battinfo(battinfo); 633 if (unit == -1 || error) 634 goto out; 635 636 error = ENXIO; 637 if (unit >= acpi_cmbat_units) 638 goto out; 639 if ((sc = devclass_get_softc(acpi_cmbat_devclass, unit)) == NULL) 640 goto out; 641 642 if (!sc->present) { 643 battinfo->cap = -1; 644 battinfo->min = -1; 645 battinfo->state = ACPI_BATT_STAT_NOT_PRESENT; 646 } else { 647 battinfo->cap = sc->cap; 648 battinfo->min = sc->min; 649 battinfo->state = sc->bst.state; 650 } 651 error = 0; 652 653out: 654 ACPI_SERIAL_END(cmbat); 655 return (error); 656} | |