1/* 2 * Copyright (c) 2005 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include <IOKit/IOService.h> 25#include <IOKit/IOWorkLoop.h> 26#include <IOKit/IOTimerEventSource.h> 27#include <IOKit/pwr_mgt/RootDomain.h> 28#include <IOKit/pwr_mgt/IOPMPrivate.h> 29#include <libkern/c++/OSObject.h> 30#include <kern/clock.h> 31#include "AppleSmartBatteryManager.h" 32#include "AppleSmartBattery.h" 33 34 35// Retry attempts on SMBus command failure 36enum { 37 kRetryAttempts = 5, 38 kInitialPollCountdown = 5, 39 kIncompleteReadRetryMax = 10 40}; 41 42enum { 43 kSecondsUntilValidOnWake = 30, 44 kPostChargeWaitSeconds = 120, 45 kPostDischargeWaitSeconds = 120 46}; 47 48 49 50// This bit lets us distinguish between reads & writes in the transactionCompletion switch statement 51#define kStage2 0x8000 52 53// Argument to transactionCompletion indicating we should start/re-start polling 54#define kTransactionRestart 0x9999 55 56#define kErrorRetryAttemptsExceeded "Read Retry Attempts Exceeded" 57#define kErrorOverallTimeoutExpired "Overall Read Timeout Expired" 58#define kErrorZeroCapacity "Capacity Read Zero" 59#define kErrorPermanentFailure "Permanent Battery Failure" 60#define kErrorNonRecoverableStatus "Non-recoverable status failure" 61#define kErrorClearBattery "Clear Battery" 62 63static const uint32_t kBatteryReadAllTimeout = 10000; // 10 seconds 64 65// Delays to use on subsequent SMBus re-read failures. 66// In microseconds. 67static const uint32_t microSecDelayTable[kRetryAttempts] = 68 { 10, 100, 1000, 10000, 250000 }; 69 70/* The union of the errors listed in STATUS_ERROR_NEEDS_RETRY 71 * and STATUS_ERROR_NON_RECOVERABLE should equal the entirety of 72 * SMBus errors listed in IOSMBusController.h 73 */ 74#define STATUS_ERROR_NEEDS_RETRY(err) \ 75 ((kIOSMBusStatusDeviceAddressNotAcknowledged == err) \ 76 || (kIOSMBusStatusDeviceCommandAccessDenied == err) \ 77 || (kIOSMBusStatusDeviceAccessDenied == err) \ 78 || (kIOSMBusStatusUnknownHostError == err) \ 79 || (kIOSMBusStatusUnknownFailure == err) \ 80 || (kIOSMBusStatusDeviceError == err) \ 81 || (kIOSMBusStatusTimeout == err) \ 82 || (kIOSMBusStatusBusy == err)) 83 84#define STATUS_ERROR_NON_RECOVERABLE(err) \ 85 ((kIOSMBusStatusHostUnsupportedProtocol == err) \ 86 || (kIOSMBusStatusPECError == err)) 87 88 89// Keys we use to publish battery state in our IOPMPowerSource::properties array 90static const OSSymbol *_MaxErrSym = OSSymbol::withCString(kIOPMPSMaxErrKey); 91static const OSSymbol *_DeviceNameSym = OSSymbol::withCString(kIOPMDeviceNameKey); 92static const OSSymbol *_FullyChargedSym = OSSymbol::withCString(kIOPMFullyChargedKey); 93static const OSSymbol *_AvgTimeToEmptySym = OSSymbol::withCString("AvgTimeToEmpty"); 94static const OSSymbol *_InstantTimeToEmptySym = OSSymbol::withCString("InstantTimeToEmpty"); 95static const OSSymbol *_InstantAmperageSym = OSSymbol::withCString("InstantAmperage"); 96static const OSSymbol *_AvgTimeToFullSym = OSSymbol::withCString("AvgTimeToFull"); 97static const OSSymbol *_ManfDateSym = OSSymbol::withCString(kIOPMPSManufactureDateKey); 98static const OSSymbol *_DesignCapacitySym = OSSymbol::withCString(kIOPMPSDesignCapacityKey); 99static const OSSymbol *_TemperatureSym = OSSymbol::withCString("Temperature"); 100static const OSSymbol *_CellVoltageSym = OSSymbol::withCString("CellVoltage"); 101static const OSSymbol *_ManufacturerDataSym = OSSymbol::withCString("ManufacturerData"); 102static const OSSymbol *_PFStatusSym = OSSymbol::withCString("PermanentFailureStatus"); 103static const OSSymbol *_DesignCycleCount70Sym = OSSymbol::withCString("DesignCycleCount70"); 104static const OSSymbol *_DesignCycleCount9CSym = OSSymbol::withCString("DesignCycleCount9C"); 105static const OSSymbol *_PackReserveSym = OSSymbol::withCString("PackReserve"); 106static const OSSymbol *_OpStatusSym = OSSymbol::withCString("OperationStatus"); 107static const OSSymbol *_PermanentFailureSym = OSSymbol::withCString(kErrorPermanentFailure); 108/* _SerialNumberSym represents the manufacturer's 16-bit serial number in 109 numeric format. 110 */ 111static const OSSymbol *_SerialNumberSym = OSSymbol::withCString("FirmwareSerialNumber"); 112/* _HardwareSerialSym == AppleSoftwareSerial 113 represents the Apple-defined 12+ character string in firmware. 114 */ 115static const OSSymbol *_HardwareSerialSym = OSSymbol::withCString("BatterySerialNumber"); 116 117// CommandMachine::pathBits 118enum { 119 kUseLastPath = 0, 120 kBoot = 1, 121 kFull = 2, 122 kUserVis = 4, 123}; 124typedef int MachinePath; 125 126#define kBootPathKey "BootPathUpdated" 127#define kFullPathKey "FullPathUpdated" 128#define kUserVisPathKey "UserVisiblePathUpdated" 129 130// CommandMachine::protocol 131#define kWord kIOSMBusProtocolReadWord 132#define kBlock kIOSMBusProtocolReadBlock 133#define kBlockData (kIOSMBusProtocolReadBlock | 0x1000) 134#define kWriteWord kIOSMBusProtocolWriteWord 135#define kBatt kSMBusBatteryAddr 136#define kMgr kSMBusManagerAddr 137 138#define kFinishPolling 0xF1 139 140 141#define super IOPMPowerSource 142 143OSDefineMetaClassAndStructors(AppleSmartBattery,IOPMPowerSource) 144 145/****************************************************************************** 146 * AppleSmartBattery::smartBattery 147 * 148 ******************************************************************************/ 149 150AppleSmartBattery * 151AppleSmartBattery::smartBattery(void) 152{ 153 AppleSmartBattery *me; 154 me = new AppleSmartBattery; 155 156 if (me && !me->init()) { 157 me->release(); 158 return NULL; 159 } 160 161 return me; 162} 163 164/****************************************************************************** 165 * AppleSmartBattery::init 166 * 167 ******************************************************************************/ 168 169bool AppleSmartBattery::init(void) 170{ 171 if (!super::init()) { 172 return false; 173 } 174 175 fProvider = NULL; 176 fWorkLoop = NULL; 177 178 return true; 179} 180 181 182/****************************************************************************** 183 * AppleSmartBattery::start 184 * 185 ******************************************************************************/ 186 187bool AppleSmartBattery::start(IOService *provider) 188{ 189 IORegistryEntry *p = NULL; 190 191 BattLog("AppleSmartBattery loading...\n"); 192 193 fProvider = OSDynamicCast(AppleSmartBatteryManager, provider); 194 195 if (!fProvider || !super::start(provider)) { 196 return false; 197 } 198 199 fPollingNow = false; 200 fCancelPolling = false; 201 fRetryAttempts = 0; 202 fPermanentFailure = false; 203 fFullyDischarged = false; 204 fFullyCharged = false; 205 fBatteryPresent = -1; 206 fACConnected = -1; 207 fAvgCurrent = 0; 208 fInflowDisabled = false; 209 fRebootPolling = false; 210 fCellVoltages = NULL; 211 fSystemSleeping = false; 212 fPowerServiceToAck = NULL; 213 214 fIncompleteReadRetries = kIncompleteReadRetryMax; 215 216 initializeCommands(); 217 218 // Make sure that we read battery state at least 5 times at 30 second intervals 219 // after system boot. 220 fInitialPollCountdown = kInitialPollCountdown; 221 222 fWorkLoop = getWorkLoop(); 223 224 fBatteryReadAllTimer = IOTimerEventSource::timerEventSource(this, 225 OSMemberFunctionCast(IOTimerEventSource::Action, 226 this, &AppleSmartBattery::incompleteReadTimeOut)); 227 228 if (!fWorkLoop 229 || (kIOReturnSuccess != fWorkLoop->addEventSource(fBatteryReadAllTimer))) 230 { 231 return false; 232 } 233 234 // Find an object of class IOACPIPlatformDevice in my parent's 235 // IORegistry service plane ancsetry. 236 fACPIProvider = NULL; 237 p = this; 238 while (p) { 239 p = p->getParentEntry(gIOServicePlane); 240 if (OSDynamicCast(IOACPIPlatformDevice, p)) { 241 fACPIProvider = (IOACPIPlatformDevice *)p; 242 break; 243 } 244 } 245 246 247 // Publish the intended period in seconds that our "time remaining" 248 // estimate is wildly inaccurate after wake from sleep. 249 setProperty(kIOPMPSInvalidWakeSecondsKey, kSecondsUntilValidOnWake, 32); 250 251 // Publish the necessary time period (in seconds) that a battery 252 // calibrating tool must wait to allow the battery to settle after 253 // charge and after discharge. 254 setProperty(kIOPMPSPostChargeWaitSecondsKey, kPostChargeWaitSeconds, 32); 255 setProperty(kIOPMPSPostDishargeWaitSecondsKey, kPostDischargeWaitSeconds, 32); 256 257 258 // zero out battery state with argument (do_update == true) 259 clearBatteryState(false); 260 261 BattLog("AppleSmartBattery::start(). Initiating a full poll.\n"); 262 263 // Kick off the 30 second timer and do an initial poll 264 pollBatteryState(kBoot); 265 266 return true; 267} 268 269/****************************************************************************** 270 * AppleSmartBattery::initializeCommands 271 * 272 ******************************************************************************/ 273void AppleSmartBattery::initializeCommands(void) 274{ 275 CommandStruct local_cmd[] = 276 { 277 {kTransactionRestart, 0, 0, 0, NULL, kBoot | kFull | kUserVis}, 278 {kMStateContCmd, kMgr, kWord, 0, NULL, kBoot | kFull | kUserVis}, 279 {kMStateCmd, kMgr, kWord, 0, NULL, kBoot | kFull | kUserVis}, 280 {kBBatteryStatusCmd, kBatt, kWord, 0, NULL, kBoot | kFull | kUserVis}, 281 {kBExtendedPFStatusCmd, kBatt, kWriteWord, 0, NULL, kBoot | kFull}, 282 {kStage2 | kBExtendedPFStatusCmd, kBatt, kWord, 0, _PFStatusSym, kBoot | kFull}, 283 {kBExtendedOperationStatusCmd, kBatt, kWriteWord, 0, NULL, kBoot | kFull}, 284 {kStage2 | kBExtendedOperationStatusCmd, kBatt, kWord, 0, _OpStatusSym, kBoot | kFull}, 285 {kBManufactureNameCmd, kBatt, kBlock, 0, manufacturerKey, kBoot}, 286 {kBManufactureDataCmd, kBatt, kBlockData, 0, _ManufacturerDataSym, kBoot}, 287 {kBManufacturerInfoCmd, kBatt, kBlock, 0, NULL, kBoot}, 288 {kBDeviceNameCmd, kBatt, kBlock, 0, _DeviceNameSym, kBoot}, 289 {kBAppleHardwareSerialCmd, kBatt, kBlock, 0, _HardwareSerialSym, kBoot}, 290 {kBPackReserveCmd, kBatt, kWord, 0, _PackReserveSym, kBoot}, 291 {kBDesignCycleCount9CCmd, kBatt, kWord, 0, _DesignCycleCount9CSym, kBoot}, 292 {kBManufactureDateCmd, kBatt, kWord, 0, _ManfDateSym, kBoot}, 293 {kBSerialNumberCmd, kBatt, kWord, 0, _SerialNumberSym, kBoot}, 294 {kBDesignCapacityCmd, kBatt, kWord, 0, _DesignCapacitySym, kBoot}, 295 {kBVoltageCmd, kBatt, kWord, 0, voltageKey, kBoot | kFull}, 296 {kBMaxErrorCmd, kBatt, kWord, 0, _MaxErrSym, kBoot | kFull}, 297 {kBCycleCountCmd, kBatt, kWord, 0, cycleCountKey, kBoot | kFull}, 298 {kBRunTimeToEmptyCmd, kBatt, kWord, 0, _InstantTimeToEmptySym, kBoot | kFull}, 299 {kBTemperatureCmd, kBatt, kWord, 0, _TemperatureSym, kBoot | kFull}, 300 {kBReadCellVoltage1Cmd, kBatt, kWord, 0, NULL, kBoot | kFull}, 301 {kBReadCellVoltage2Cmd, kBatt, kWord, 0, NULL, kBoot | kFull}, 302 {kBReadCellVoltage3Cmd, kBatt, kWord, 0, NULL, kBoot | kFull}, 303 {kBReadCellVoltage4Cmd, kBatt, kWord, 0, NULL, kBoot | kFull}, 304 {kBCurrentCmd, kBatt, kWord, 0, NULL, kBoot | kFull | kUserVis}, 305 {kBAverageCurrentCmd, kBatt, kWord, 0, NULL, kBoot | kFull | kUserVis}, 306 {kBAverageTimeToEmptyCmd, kBatt, kWord, 0, NULL, kBoot | kFull | kUserVis}, 307 {kBAverageTimeToFullCmd, kBatt, kWord, 0, NULL, kBoot | kFull | kUserVis}, 308 {kBRemainingCapacityCmd, kBatt, kWord, 0, NULL, kBoot | kFull | kUserVis}, 309 {kBFullChargeCapacityCmd, kBatt, kWord, 0, maxCapacityKey, kBoot | kFull | kUserVis}, 310 {kFinishPolling, 0, 0, 0, NULL, kBoot | kFull | kUserVis} 311 }; 312 313 cmdTable.table = NULL; 314 cmdTable.count = 0; 315 316 if ((cmdTable.table = (CommandStruct *)IOMalloc(sizeof(local_cmd)))) { 317 cmdTable.count = sizeof(local_cmd) / sizeof(CommandStruct); 318 bcopy(&local_cmd, cmdTable.table, sizeof(local_cmd)); 319 } 320} 321 322/****************************************************************************** 323 * AppleSmartBattery::commandForState 324 * 325 ******************************************************************************/ 326CommandStruct *AppleSmartBattery::commandForState(uint32_t state) 327{ 328 if (cmdTable.table) { 329 for (int i=0; i<cmdTable.count; i++) { 330 if (state == cmdTable.table[i].cmd) { 331 return &cmdTable.table[i]; 332 } 333 } 334 } 335 return NULL; 336} 337 338/****************************************************************************** 339 * AppleSmartBattery::initiateTransaction 340 * 341 ******************************************************************************/ 342bool AppleSmartBattery::initiateTransaction(const CommandStruct *cs, bool retry) 343{ 344 uint32_t cmd = cs->cmd; 345 346 if (cmd == kFinishPolling) 347 { 348 this->handlePollingFinished(true); 349 } 350 else if ((cmd == kBExtendedPFStatusCmd) 351 || (cmd == kBExtendedOperationStatusCmd)) 352 { 353 // Extended commands require a 2-stage write & read. 354 writeWordAsync(cmd, cs->addr, kBManufacturerAccessCmd, cmd); 355 goto command_started; 356 } 357 else if ((cmd == (kStage2 | kBExtendedPFStatusCmd)) 358 || (cmd == (kStage2 | kBExtendedOperationStatusCmd))) 359 { 360 readWordAsync(cmd, cs->addr, kBManufacturerAccessCmd); 361 goto command_started; 362 } 363 else if (cs->protocol == kWord) 364 { 365 readWordAsync(cmd, cs->addr, cmd); 366 goto command_started; 367 } else if ((cs->protocol == kBlock) 368 || (cs->protocol == kBlockData)) 369 { 370 readBlockAsync(cmd, cs->addr, cmd); 371 goto command_started; 372 } 373 374 return false; 375 376command_started: 377 return true; 378} 379 380/****************************************************************************** 381 * AppleSmartBattery::initiateNextTransaction 382 * 383 ******************************************************************************/ 384bool AppleSmartBattery::initiateNextTransaction(uint32_t state) 385{ 386 int found_current_index = 0; 387 const CommandStruct *cs = NULL; 388 389 if (!cmdTable.table) { 390 return false; 391 } 392 393 // Find index for "state" in cmd_machine 394 for (found_current_index = 0; found_current_index < cmdTable.count; found_current_index++) { 395 if (cmdTable.table[found_current_index].cmd == state) { 396 break; 397 } 398 } 399 // Find next state to read for fMachinePath 400 if (++found_current_index < cmdTable.count) { 401 for (; found_current_index<cmdTable.count; found_current_index++) 402 { 403 if (0 != (cmdTable.table[found_current_index].pathBits & fMachinePath)) 404 { 405 cs = &cmdTable.table[found_current_index]; 406 break; 407 } 408 } 409 } 410 411 if (cs) 412 return initiateTransaction(cs, false); 413 414 return false; 415} 416 417/****************************************************************************** 418 * AppleSmartBattery::retryCurrentTransaction 419 * 420 ******************************************************************************/ 421bool AppleSmartBattery::retryCurrentTransaction(uint32_t state) 422{ 423 int found_current_index = 0; 424 const CommandStruct *cs = NULL; 425 426 if (!cmdTable.table) { 427 return false; 428 } 429 430 // Find index for "state" in cmd_machine 431 for (found_current_index = 0; found_current_index < cmdTable.count; found_current_index++) { 432 if (cmdTable.table[found_current_index].cmd == state) { 433 cs = &cmdTable.table[found_current_index]; 434 break; 435 } 436 } 437 438 if (cs) 439 return initiateTransaction(cs, true); 440 441 return false; 442} 443 444/****************************************************************************** 445 * AppleSmartBattery::logReadError 446 * 447 ******************************************************************************/ 448void AppleSmartBattery::logReadError( 449 const char *error_type, 450 uint16_t additional_error, 451 IOSMBusTransaction *t) 452{ 453 454 if (!error_type) return; 455 456 BattLog("SmartBatteryManager Error: %s (%d)\n", error_type, additional_error); 457 if (t) { 458 BattLog("\tCorresponding transaction addr=0x%02x cmd=0x%02x status=0x%02x\n", 459 t->address, t->command, t->status); 460 } 461 462 return; 463} 464 465/****************************************************************************** 466 * AppleSmartBattery::handleSystemSleepWake 467 * 468 * Caller must hold the gate. 469 ******************************************************************************/ 470 471IOReturn AppleSmartBattery::handleSystemSleepWake( 472 IOService * powerService, bool isSystemSleep) 473{ 474 IOReturn ret = kIOPMAckImplied; 475 476 if (!powerService || (fSystemSleeping == isSystemSleep)) 477 return kIOPMAckImplied; 478 479 if (fPowerServiceToAck) 480 { 481 fPowerServiceToAck->release(); 482 fPowerServiceToAck = 0; 483 } 484 485 fSystemSleeping = isSystemSleep; 486 if (fSystemSleeping) 487 { 488 // Stall PM until battery poll in progress is cancelled. 489 if (fPollingNow) 490 { 491 fPowerServiceToAck = powerService; 492 fPowerServiceToAck->retain(); 493 if (fBatteryReadAllTimer) { 494 fBatteryReadAllTimer->cancelTimeout(); 495 } 496 ret = (kBatteryReadAllTimeout * 1000); 497 } 498 } 499 else // System Wake 500 { 501 fPowerServiceToAck = powerService; 502 fPowerServiceToAck->retain(); 503 pollBatteryState(kFull); 504 505 if (fPollingNow) 506 { 507 // Transaction started, wait for completion. 508 ret = (kBatteryReadAllTimeout * 1000); 509 } 510 else if (fPowerServiceToAck) 511 { 512 fPowerServiceToAck->release(); 513 fPowerServiceToAck = 0; 514 } 515 } 516 517 BattLog("SmartBattery: handleSystemSleepWake(%d) = %u\n", 518 isSystemSleep, (uint32_t) ret); 519 return ret; 520} 521 522/****************************************************************************** 523 * AppleSmartBattery::acknowledgeSystemSleepWake 524 * 525 * Caller must hold the gate. 526 ******************************************************************************/ 527 528void AppleSmartBattery::acknowledgeSystemSleepWake(void) 529{ 530 if (fPowerServiceToAck) 531 { 532 fPowerServiceToAck->acknowledgeSetPowerState(); 533 fPowerServiceToAck->release(); 534 fPowerServiceToAck = 0; 535 } 536} 537 538/****************************************************************************** 539 * AppleSmartBattery::pollBatteryState 540 * 541 * Asynchronously kicks off the register poll. 542 ******************************************************************************/ 543 544#define kMinimumPollingFrequencyMS 1000 545 546bool AppleSmartBattery::pollBatteryState(int type) 547{ 548 /* Don't perform any SMBus activity if a AppleSmartBatteryManagerUserClient 549 has grabbed exclusive access 550 */ 551 if (fStalledByUserClient) { 552 BattLog("AppleSmartBattery::pollBatteryState was stalled by an exclusive user client.\n"); 553 return false; 554 } 555 556 /* kUseLastPath = 0, 557 * kBoot = 1, 558 * kFull = 2, 559 * kUserVis = 4 560 */ 561 562 if (fPollingNow && (fMachinePath <= type)) { 563 /* We're already in the middle of a poll for a superset of 564 * the requested battery data. 565 */ 566 BattLog("AppleSmartBattery::pollBatteryState already polling (%d <= %d)\n", fMachinePath, type); 567 return true; 568 } 569 570 if (type != kUseLastPath) { 571 fMachinePath = type; 572 } 573 574 if (fInitialPollCountdown > 0) { 575 // We're going out of our way to make sure that we get a successfull 576 // initial poll at boot. Upgrade all early boot polls to kBoot. 577 fMachinePath = kBoot; 578 } 579 580 if (!fPollingNow) 581 { 582 /* Start the battery polling state machine (resetting it if it's already in progress) */ 583 return transactionCompletion((void *)kTransactionRestart, NULL); 584 } else { 585 /* Outstanding transaction in process; flag it to restart polling from 586 scratch when this flag is noticed. 587 */ 588 fRebootPolling = true; 589 return true; 590 } 591} 592 593void AppleSmartBattery::handleBatteryInserted(void) 594{ 595 clearBatteryState(false); 596 pollBatteryState(kBoot); 597 return; 598} 599 600void AppleSmartBattery::handleBatteryRemoved(void) 601{ 602 if (fPollingNow) { 603 fCancelPolling = true; 604 if (fBatteryReadAllTimer) { 605 fBatteryReadAllTimer->cancelTimeout(); 606 } 607 } 608 609 clearBatteryState(true); 610 acknowledgeSystemSleepWake(); 611 return; 612} 613 614void AppleSmartBattery::handleInflowDisabled(bool inflow_state) 615{ 616 fInflowDisabled = inflow_state; 617 // And kick off a re-poll using this new information 618 pollBatteryState(kFull); 619 620 return; 621} 622 623void AppleSmartBattery::handleChargeInhibited(bool charge_state) 624{ 625 fChargeInhibited = charge_state; 626 // And kick off a re-poll using this new information 627 pollBatteryState(kFull); 628} 629 630// One "wait interval" is 100ms 631#define kWaitExclusiveIntervals 30 632 633void AppleSmartBattery::handleExclusiveAccess(bool exclusive) 634{ 635 /* Write exclusive access bit to SMC via ACPI registers 636 * 637 * #define ACPIIO_SMB_MODE ACPIIO_SMB_BASE + 0x29 638 * Mode bit masks: 0x01 - OS requests exclusive access to battery 639 * 0x10 - SMC acknowledges OS exclusive access to battery 640 * (resets to non-exclusive (0) on warm restart 641 * or leaving S0 or timeout) 642 */ 643 644 IOACPIAddress ecBehaviorsAddress; 645 IOReturn ret = kIOReturnSuccess; 646 UInt64 value64 = 0; 647 int waitCount = 0; 648 649 // Shut off SMC hardware communications with the batteries 650 do { 651 652 if (!fACPIProvider) 653 break; 654 655 /* Read BYTE */ 656 // Register address is 0x29 + SMB base 0x20 657 ecBehaviorsAddress.addr64 = 0x20 + 0x29; 658 ret = fACPIProvider->readAddressSpace(&value64, 659 kIOACPIAddressSpaceIDEmbeddedController, 660 ecBehaviorsAddress, 8, 0, 0); 661 if (kIOReturnSuccess != ret) { 662 break; 663 } 664 665 /* Modify - set 0x01 to indicate the SMC should not communicate with battery*/ 666 if (exclusive) { 667 value64 |= 1; 668 } else { 669 // Zero'ing out bit 0x01 670 value64 &= ~1; 671 } 672 673 /* Write BYTE */ 674 ret = fACPIProvider->writeAddressSpace(value64, 675 kIOACPIAddressSpaceIDEmbeddedController, 676 ecBehaviorsAddress, 8, 0, 0); 677 if (kIOReturnSuccess != ret) { 678 break; 679 } 680 681 // Wait up to 3 seconds for the SMC to set/clear bit 0x10 682 // As-implemented, this waits at least 100 msec before proceeding. 683 // That is OK - this is a very infrequent code path. 684 685 waitCount = 0; 686 value64 = 0; 687 ret = kIOReturnSuccess; 688 while ((waitCount < kWaitExclusiveIntervals) 689 && (kIOReturnSuccess == ret)) 690 { 691 waitCount++; 692 IOSleep(100); 693 694 ret = fACPIProvider->readAddressSpace(&value64, 695 kIOACPIAddressSpaceIDEmbeddedController, 696 ecBehaviorsAddress, 8, 0, 0); 697 698 if (exclusive) { 699 // wait for 0x10 bit to set 700 if ((value64 & 0x10) == 0x10) 701 break; 702 } else { 703 // wait for 0x10 bit to clear 704 if ((value64 & 0x10) == 0) 705 break; 706 } 707 } 708 } while (0); 709 710 711 if (exclusive) 712 { 713 // Communications with battery have been shutdown for 714 // exclusive access by the user client. 715 setProperty("BatteryUpdatesBlockedExclusiveAccess", true); 716 fStalledByUserClient = true; 717 718 } else { 719 // Exclusive access disabled! restart polling 720 removeProperty("BatteryUpdatesBlockedExclusiveAccess"); 721 fStalledByUserClient = false; 722 723 // Restore battery state 724 // Do a complete battery poll 725 pollBatteryState(kFull); 726 } 727} 728 729/****************************************************************************** 730 * incompleteReadTimeOut 731 * 732 * The complete battery read has not completed in the allowed timeframe. 733 * We assume this is for several reasons: 734 * - The EC has dropped an SMBus packet (probably recoverable) 735 * - The EC has stalled an SMBus request; IOSMBusController is hung (probably not recoverable) 736 * 737 * Start the battery read over from scratch. 738 *****************************************************************************/ 739 740void AppleSmartBattery::incompleteReadTimeOut(void) 741{ 742 logReadError(kErrorOverallTimeoutExpired, 0, NULL); 743 744 /* Don't launch infinite re-tries if the system isn't completing my transactions 745 * (and thus probably leaking a lot of memory every time. 746 * Quit after kIncompleteReadRetryMax 747 */ 748 if (0 < fIncompleteReadRetries) 749 { 750 fIncompleteReadRetries--; 751 pollBatteryState(kUseLastPath); 752 } 753} 754 755bool AppleSmartBattery::transactionCompletion_shouldAbortTransactions(IOSMBusTransaction *transaction) 756{ 757 /* Stop battery work when system is going to sleep. 758 */ 759 if (fSystemSleeping) 760 { 761 return true; 762 } 763 764 /* If a user client has exclusive access to the SMBus, 765 * we'll exit immediately. 766 */ 767 if (fStalledByUserClient) 768 { 769 return true; 770 } 771 772 /* Do we need to abort an ongoing polling session? 773 Example: If a battery has just been removed in the midst of our polling, we 774 need to abort the remainder of our scheduled SMBus reads. 775 776 We do not abort newly started polling sessions where (NULL == transaction). 777 */ 778 if (fCancelPolling) 779 { 780 fCancelPolling = false; 781 if (transaction) 782 { 783 return true; 784 } 785 } 786 return false; 787} 788 789uint32_t AppleSmartBattery::transactionCompletion_requiresRetryGetMicroSec(IOSMBusTransaction *transaction) 790{ 791 IOSMBusStatus transaction_status = kIOSMBusStatusPECError; 792 bool transaction_needs_retry = false; 793 794 if (transaction) 795 transaction_status = transaction->status; 796 else 797 return 0; 798 799 /****************************************************************************************** 800 ******************************************************************************************/ 801 802 /* If the last transaction wasn't successful at the SMBus level, retry. 803 */ 804 if (STATUS_ERROR_NEEDS_RETRY(transaction_status)) 805 { 806 transaction_needs_retry = true; 807 } else if (STATUS_ERROR_NON_RECOVERABLE(transaction_status)) 808 { 809 transaction_needs_retry = false; 810 logReadError(kErrorNonRecoverableStatus, transaction_status, transaction); 811 goto exit; 812 } 813 814 /****************************************************************************************** 815 ******************************************************************************************/ 816 817 if (kIOSMBusStatusOK == transaction_status) 818 { 819 if (0 != fRetryAttempts) { 820 BattLog("SmartBattery: retry %d succeeded!\n", fRetryAttempts); 821 822 fRetryAttempts = 0; 823 transaction_needs_retry = false; /* potentially overridden below */ 824 } 825 826 /* Check for absurd return value for RemainingCapacity or FullChargeCapacity. 827 If the returned value is zero, re-read until it's non-zero (or until we 828 try too many times). 829 830 (FullChargeCapacity = 0) is NOT a valid state 831 (DesignCapacity = 0) is NOT a valid state 832 (RemainingCapacity = 0) is a valid state 833 (RemainingCapacity = 0) && !fFullyDischarged is NOT a valid state 834 */ 835 if (((kBFullChargeCapacityCmd == transaction->command) 836 || (kBDesignCapacityCmd == transaction->command) 837 || ((kBRemainingCapacityCmd == transaction->command) 838 && !fFullyDischarged)) 839 && ((transaction->receiveData[1] == 0) 840 && (transaction->receiveData[0] == 0))) 841 { 842 transaction_needs_retry = true; 843 } 844 } 845 846 /* Too many retries already? 847 */ 848 if (transaction_needs_retry && (kRetryAttempts == fRetryAttempts)) 849 { 850 // Too many consecutive failures to read this entry. Give up, and 851 // go on to attempt a read on the next element in the state machine. 852 853 BattLog("SmartBattery: Giving up on (0x%02x, 0x%02x) after %d retries.\n", 854 transaction->address, transaction->command, fRetryAttempts); 855 856 logReadError(kErrorRetryAttemptsExceeded, transaction_status, transaction); 857 858 fRetryAttempts = 0; 859 860 transaction_needs_retry = false; 861 862 // After too many retries, unblock PM state machine in case it is 863 // waiting for the first battery poll after wake to complete, 864 // avoiding a setPowerState timeout. 865 acknowledgeSystemSleepWake(); 866 867 goto exit; 868 } 869 870exit: 871 if (transaction_needs_retry) 872 { 873 fRetryAttempts++; 874 return microSecDelayTable[fRetryAttempts]; 875 } else { 876 return 0; 877 } 878} 879 880void AppleSmartBattery::handlePollingFinished(bool visitedEntirePath) 881{ 882 if (fBatteryReadAllTimer) { 883 fBatteryReadAllTimer->cancelTimeout(); 884 } 885 886 const char *reportPathFinishedKey; 887 if (kBoot == fMachinePath) { 888 reportPathFinishedKey = kBootPathKey; 889 } else if (kFull == fMachinePath) { 890 reportPathFinishedKey = kFullPathKey; 891 } else if (kUserVis == fMachinePath) { 892 reportPathFinishedKey = kUserVisPathKey; 893 } else { 894 reportPathFinishedKey = NULL; 895 } 896 897 if (reportPathFinishedKey) { 898 clock_sec_t secs; 899 clock_usec_t microsecs; 900 clock_get_calendar_microtime(&secs, µsecs); 901 setProperty(reportPathFinishedKey, secs, 32); 902 } 903 904 if (visitedEntirePath) { 905 if (fInitialPollCountdown > 0) { 906 fInitialPollCountdown--; 907 } 908 909 rebuildLegacyIOBatteryInfo(); 910 updateStatus(); 911 } 912 913 fPollingNow = false; 914 915 acknowledgeSystemSleepWake(); 916} 917 918 919bool AppleSmartBattery::handleSetItAndForgetIt(int state, int val16, const uint8_t *str32, uint32_t len) 920{ 921 CommandStruct *this_command = NULL; 922 const OSData *publishData; 923 const OSSymbol *publishSym; 924 OSNumber *val16num = NULL; 925 926 /* Set it and forget it 927 * 928 * These commands specify an OSSymbol in their CommandStruct. 929 * We directly publish the data into these registry keys. 930 */ 931 if ((this_command = commandForState(state)) && this_command->setItAndForgetItSym) 932 { 933 if (this_command->protocol == kWord) { 934 val16num = OSNumber::withNumber(val16, 16); 935 if (val16num) { 936 setPSProperty(this_command->setItAndForgetItSym, val16num); 937 val16num->release(); 938 } 939 return true; 940 } 941 942 else if (this_command->protocol == kBlock) { 943 publishSym = OSSymbol::withCString((const char *)str32); 944 if (publishSym) { 945 setPSProperty(this_command->setItAndForgetItSym, (OSObject *)publishSym); 946 publishSym->release(); 947 return true; 948 } 949 } 950 else if (this_command->protocol == kBlockData) { 951 publishData = OSData::withBytes((const void *)str32, len); 952 if (publishData) { 953 setPSProperty(this_command->setItAndForgetItSym, (OSObject *)publishData); 954 publishData->release(); 955 return true; 956 } 957 } 958 } 959 960 return false; 961} 962 963/****************************************************************************** 964 * AppleSmartBattery::transactionCompletion 965 * -> Runs in workloop context 966 * 967 ******************************************************************************/ 968 969bool AppleSmartBattery::transactionCompletion( 970 void *ref, 971 IOSMBusTransaction *transaction) 972{ 973 IOSMBusStatus transaction_status = kIOSMBusStatusPECError; 974 bool transaction_success = false; 975 int next_state = (uintptr_t)ref; 976 uint16_t val16 = 0; 977 uint32_t delay_for = 0; 978 OSNumber *num = NULL; 979 980 981 if (transaction) { 982 BattLog("transaction state = 0x%02x; status = 0x%02x; prot = 0x%02x; word = 0x%04x; %d us\n", 983 next_state, transaction->status, transaction->protocol, 984 (transaction->receiveData[1] << 8) | transaction->receiveData[0]); 985 } 986 987 // Abort? 988 if (transactionCompletion_shouldAbortTransactions(transaction)) { 989 goto abort; 990 } 991 992 // Restart? 993 if (!transaction || fRebootPolling) 994 { 995 // NULL argument for transaction means we should start the state machine from scratch. 996 transaction = NULL; 997 next_state = kTransactionRestart; 998 fRebootPolling = false; 999 } 1000 1001 if (transaction) 1002 { 1003 // Retry? 1004 delay_for = this->transactionCompletion_requiresRetryGetMicroSec(transaction); 1005 if (0 != delay_for) 1006 { 1007 // The transaction failed. We'll delay for a bit, then retry the transaction. 1008 if (delay_for < 1000) { 1009 IODelay(delay_for); // microseconds 1010 } else { 1011 IOSleep(delay_for / 1000); // milliseconds 1012 } 1013 1014 BattLog("SmartBattery: 0x%02x failed with 0x%02x; retry attempt %d of %d\n", 1015 transaction->command, transaction_status, fRetryAttempts, kRetryAttempts); 1016 1017 // Kick off the same transaction that just failed 1018 retryCurrentTransaction(next_state); 1019 return true; // not exit/abort 1020 } 1021 1022 transaction_success = (kIOSMBusStatusOK == transaction->status); 1023 if (transaction_success) { 1024 val16 = (transaction->receiveData[1] << 8) | transaction->receiveData[0]; 1025 } 1026 1027 // Is it a set it and forget it command? 1028 if (handleSetItAndForgetIt(next_state, val16, transaction->receiveData, 1029 transaction->receiveDataCount)) 1030 { 1031 goto exit; 1032 } 1033 } 1034 1035 switch(next_state) 1036 { 1037 case kTransactionRestart: 1038 1039 fCancelPolling = false; 1040 fPollingNow = true; 1041 1042 /* Initialize battery read timeout to catch any longstanding stalls. */ 1043 if (fBatteryReadAllTimer) { 1044 fBatteryReadAllTimer->cancelTimeout(); 1045 fBatteryReadAllTimer->setTimeoutMS(kBatteryReadAllTimeout); 1046 } 1047 break; 1048 1049 case kMStateContCmd: 1050 1051 // Determines if AC is plugged or unplugged 1052 // Determines if AC is "charge capable" 1053 if (transaction_success) 1054 { 1055 /* If fInflowDisabled is currently set, then we acknowledge 1056 * our lack of AC power. inflow disable means the system is not drawing power from AC. 1057 * (Having inflow disabled is uncommon.) 1058 * 1059 * Even with inflow disabled, the AC bit is still true if AC 1060 * is attached. We zero the bit instead, so that it looks 1061 * more accurate in BatteryMonitor. 1062 */ 1063 bool new_ac_connected = (!fInflowDisabled && (val16 & kMACPresentBit)) ? 1:0; 1064 1065 // Tell IOPMrootDomain on ac connect/disconnect 1066 IOPMrootDomain *rd = getPMRootDomain(); 1067 if (rd && (new_ac_connected != fACConnected)) 1068 { 1069 if (new_ac_connected) { 1070 rd->receivePowerNotification(kIOPMSetACAdaptorConnected | kIOPMSetValue); 1071 } else { 1072 rd->receivePowerNotification(kIOPMSetACAdaptorConnected); 1073 } 1074 } 1075 1076 fACConnected = new_ac_connected; 1077 setExternalConnected(fACConnected); 1078 setExternalChargeCapable((val16 & kMPowerNotGoodBit) ? false:true); 1079 1080 } else { 1081 fACConnected = false; 1082 setExternalConnected(true); 1083 setExternalChargeCapable(false); 1084 } 1085 break; 1086 1087 case kMStateCmd: 1088 1089 // Determines if battery is present 1090 // Determines if battery is charging 1091 if (transaction_success) 1092 { 1093 fBatteryPresent = (val16 & kMPresentBatt_A_Bit) ? true : false; 1094 1095 setBatteryInstalled(fBatteryPresent); 1096 1097 // If fChargeInhibit is currently set, then we acknowledge 1098 // our lack of charging and force the "isCharging" bit to false. 1099 // 1100 // charge inhibit means the battery will not charge, even if 1101 // AC is attached. 1102 // Without marking this lack of charging here, it can take 1103 // up to 30 seconds for the charge disable to be reflected in 1104 // the UI. 1105 1106 setIsCharging((!fChargeInhibited && (val16 & kMChargingBatt_A_Bit)) ? true:false); 1107 } else { 1108 fBatteryPresent = false; 1109 setBatteryInstalled(false); 1110 setIsCharging(false); 1111 } 1112 1113 break; 1114 1115 case kBBatteryStatusCmd: 1116 1117 if (!transaction_success) 1118 { 1119 fFullyCharged = false; 1120 fFullyDischarged = false; 1121 } else { 1122 1123 if (val16 & kBFullyChargedStatusBit) { 1124 fFullyCharged = true; 1125 } else { 1126 fFullyCharged = false; 1127 } 1128 1129 if (val16 & kBFullyDischargedStatusBit) 1130 { 1131 if (!fFullyDischarged) { 1132 fFullyDischarged = true; 1133 1134 // Immediately cancel AC Inflow disable 1135 fProvider->handleFullDischarge(); 1136 } 1137 } else { 1138 fFullyDischarged = false; 1139 } 1140 1141 /* Detect battery permanent failure 1142 * Permanent battery failure is marked by 1143 * (TerminateDischarge & TerminateCharge) bits being set simultaneously. 1144 */ 1145 if ((val16 1146 & (kBTerminateDischargeAlarmBit | kBTerminateChargeAlarmBit)) 1147 == (kBTerminateDischargeAlarmBit | kBTerminateChargeAlarmBit)) 1148 { 1149 logReadError(kErrorPermanentFailure, 0, transaction); 1150 setErrorCondition((OSSymbol *)_PermanentFailureSym); 1151 1152 fPermanentFailure = true; 1153 1154 /* We want to display the battery as present & completely discharged, not charging */ 1155 fBatteryPresent = true; 1156 setBatteryInstalled(true); 1157 setIsCharging(false); 1158 } else { 1159 fPermanentFailure = false; 1160 } 1161 } 1162 1163 setFullyCharged(fFullyCharged); 1164 1165 /* If the battery is present, we continue with our state machine 1166 and read battery state below. 1167 Otherwise, if the battery is not present, we zero out all 1168 the settings that would have been set in a connected battery. 1169 */ 1170 if (!fBatteryPresent) { 1171 // Clean-up battery state for absent battery; do no further 1172 // battery work until messaged that another battery has 1173 // arrived. 1174 1175 // zero out battery state with argument (do_update == true) 1176 clearBatteryState(true); 1177 goto abort; 1178 } 1179 1180 break; 1181 1182 case kBRemainingCapacityCmd: 1183 1184 fRemainingCapacity = val16; 1185 setCurrentCapacity(val16); 1186 1187 if (!fPermanentFailure && (0 == fRemainingCapacity)) 1188 { 1189 // fRemainingCapacity == 0 is an absurd value. 1190 // We have already retried several times, so we accept this value and move on. 1191 logReadError(kErrorZeroCapacity, kBRemainingCapacityCmd, transaction); 1192 } 1193 break; 1194 1195 /* *Instant* current */ 1196 case kBCurrentCmd: 1197 if ((num = OSNumber::withNumber(val16, 16))) { 1198 setPSProperty(_InstantAmperageSym, num); 1199 num->release(); 1200 } 1201 fInstantCurrent = (int)(int16_t)val16; 1202 break; 1203 1204 /* Average current */ 1205 case kBAverageCurrentCmd: 1206 setAmperage((int16_t)val16); 1207 fAvgCurrent = (int16_t)val16; 1208 if (0 == fAvgCurrent) { 1209 // Battery not present, or fully charged, or general error 1210 setTimeRemaining(0); 1211 } 1212 break; 1213 1214 case kBAverageTimeToEmptyCmd: 1215 1216 setAverageTimeToEmpty(val16); 1217 1218 if (fInstantCurrent < 0) { 1219 setTimeRemaining(val16); 1220 } 1221 break; 1222 1223 case kBAverageTimeToFullCmd: 1224 1225 setAverageTimeToFull(val16); 1226 1227 if (fInstantCurrent > 0) { 1228 setTimeRemaining(val16); 1229 } 1230 break; 1231 1232 case kBReadCellVoltage4Cmd: 1233 case kBReadCellVoltage3Cmd: 1234 case kBReadCellVoltage2Cmd: 1235 case kBReadCellVoltage1Cmd: 1236 1237 if (kBReadCellVoltage1Cmd == next_state) { 1238 if (fCellVoltages) 1239 { 1240 fCellVoltages->release(); 1241 fCellVoltages = NULL; 1242 } 1243 fCellVoltages = OSArray::withCapacity(4); 1244 } 1245 1246 // Executed for all 4 CellVoltage calls through here 1247 if (fCellVoltages) 1248 { 1249 num = OSNumber::withNumber(val16, 16); 1250 if (num) { 1251 fCellVoltages->setObject(num); 1252 num->release(); 1253 } 1254 } 1255 1256 // Executed for CellVoltage4 1257 if (kBReadCellVoltage4Cmd == next_state) 1258 { 1259 if (fCellVoltages) 1260 { 1261 setProperty(_CellVoltageSym, fCellVoltages); 1262 fCellVoltages->release(); 1263 fCellVoltages = NULL; 1264 } else { 1265 removeProperty(_CellVoltageSym); 1266 } 1267 } 1268 break; 1269 1270 case kBExtendedPFStatusCmd: 1271 case kBExtendedOperationStatusCmd: 1272 // 2 stage commands, first stage SMBus write completed. 1273 // Do nothing other than to prevent the error log in the default case. 1274 break; 1275 1276 default: 1277 BattLog("SmartBattery: Error state %x not expected\n", next_state); 1278 } 1279 1280exit: 1281 /* Kick off the next transaction */ 1282 if (kFinishPolling != next_state) { 1283 this->initiateNextTransaction(next_state); 1284 } 1285 return true; 1286 1287abort: 1288 handlePollingFinished(false); 1289 return true; 1290} 1291 1292 1293void AppleSmartBattery::clearBatteryState(bool do_update) 1294{ 1295 // Only clear out battery state; don't clear manager state like AC Power. 1296 // We just zero out the int and bool values, but remove the OSType values. 1297 1298 fRetryAttempts = 0; 1299 fFullyDischarged = false; 1300 fFullyCharged = false; 1301 fBatteryPresent = false; 1302 fACConnected = -1; 1303 fAvgCurrent = 0; 1304 1305 setBatteryInstalled(false); 1306 setIsCharging(false); 1307 setCurrentCapacity(0); 1308 setMaxCapacity(0); 1309 setTimeRemaining(0); 1310 setAmperage(0); 1311 setVoltage(0); 1312 setCycleCount(0); 1313 setAdapterInfo(0); 1314 setLocation(0); 1315 1316 properties->removeObject(manufacturerKey); 1317 removeProperty(manufacturerKey); 1318 properties->removeObject(serialKey); 1319 removeProperty(serialKey); 1320 1321 // Let rebuildLegacyIOBatteryInfo() update batteryInfoKey and detect 1322 // if any value in the dictionary has changed. Removing batteryInfoKey 1323 // from properties will always dirty the battery state and will cause 1324 // IOPMPowerSource::updateStatus() to message clients unnecessarily 1325 // when battery is not present. 1326 // properties->removeObject(batteryInfoKey); 1327 1328 removeProperty(batteryInfoKey); 1329 properties->removeObject(errorConditionKey); 1330 removeProperty(errorConditionKey); 1331 properties->removeObject(_PFStatusSym); 1332 removeProperty(_PFStatusSym); 1333 1334 rebuildLegacyIOBatteryInfo(); 1335 1336 logReadError(kErrorClearBattery, 0, NULL); 1337 1338 if (do_update) { 1339 updateStatus(); 1340 } 1341} 1342 1343 1344/****************************************************************************** 1345 * Package battery data in "legacy battery info" format, readable by 1346 * any applications using the not-so-friendly IOPMCopyBatteryInfo() 1347 ******************************************************************************/ 1348 1349 void AppleSmartBattery::rebuildLegacyIOBatteryInfo(void) 1350 { 1351 OSDictionary *legacyDict = OSDictionary::withCapacity(5); 1352 uint32_t flags = 0; 1353 OSNumber *flags_num = NULL; 1354 1355 if (externalConnected()) flags |= kIOPMACInstalled; 1356 if (batteryInstalled()) flags |= kIOPMBatteryInstalled; 1357 if (isCharging()) flags |= kIOPMBatteryCharging; 1358 1359 flags_num = OSNumber::withNumber((unsigned long long)flags, 32); 1360 legacyDict->setObject(kIOBatteryFlagsKey, flags_num); 1361 flags_num->release(); 1362 1363 legacyDict->setObject(kIOBatteryCurrentChargeKey, properties->getObject(kIOPMPSCurrentCapacityKey)); 1364 legacyDict->setObject(kIOBatteryCapacityKey, properties->getObject(kIOPMPSMaxCapacityKey)); 1365 legacyDict->setObject(kIOBatteryVoltageKey, properties->getObject(kIOPMPSVoltageKey)); 1366 legacyDict->setObject(kIOBatteryAmperageKey, properties->getObject(kIOPMPSAmperageKey)); 1367 legacyDict->setObject(kIOBatteryCycleCountKey, properties->getObject(kIOPMPSCycleCountKey)); 1368 1369 setLegacyIOBatteryInfo(legacyDict); 1370 1371 legacyDict->release(); 1372} 1373 1374 1375/****************************************************************************** 1376 * Power Source value accessors 1377 * These supplement the built-in accessors in IOPMPowerSource.h. 1378 ******************************************************************************/ 1379 1380#define CLASS AppleSmartBattery 1381 1382void AppleSmartBattery::setAverageTimeToEmpty(int seconds) { 1383 OSNumber *n = OSNumber::withNumber(seconds, 32); 1384 if (n) { 1385 setPSProperty(_AvgTimeToEmptySym, n); 1386 n->release(); 1387 } 1388} 1389void AppleSmartBattery::setAverageTimeToFull(int seconds) { 1390 OSNumber *n = OSNumber::withNumber(seconds, 32); 1391 if (n) { 1392 setPSProperty(_AvgTimeToFullSym, n); 1393 n->release(); 1394 } 1395} 1396 1397#define IMPLEMENT_APPLESMARTBATTERY_INT_GETTER(methodName, pspropSYM, return_type) \ 1398 return_type CLASS::methodName(void) { \ 1399 OSNumber *n = OSDynamicCast(OSNumber, properties->getObject(_SerialNumberSym)); \ 1400 if (n) { \ 1401 return n->unsigned16BitValue(); \ 1402 } else { \ 1403 return 0; \ 1404 } \ 1405 } 1406IMPLEMENT_APPLESMARTBATTERY_INT_GETTER(serialNumber, _SerialNumberSym, uint16_t); 1407IMPLEMENT_APPLESMARTBATTERY_INT_GETTER(maxErr, _MaxErrSym, int); 1408IMPLEMENT_APPLESMARTBATTERY_INT_GETTER(averageTimeToEmpty, _AvgTimeToEmptySym, int); 1409IMPLEMENT_APPLESMARTBATTERY_INT_GETTER(averageTimeToFull, _AvgTimeToFullSym, int); 1410IMPLEMENT_APPLESMARTBATTERY_INT_GETTER(manufactureDate, _ManfDateSym, int); 1411 1412OSSymbol * AppleSmartBattery::deviceName(void) 1413{ 1414 return OSDynamicCast(OSSymbol, properties->getObject(_DeviceNameSym)); 1415} 1416 1417void AppleSmartBattery::setFullyCharged(bool charged) 1418{ 1419 setPSProperty(_FullyChargedSym, (charged ? kOSBooleanTrue:kOSBooleanFalse)); 1420} 1421 1422bool AppleSmartBattery::fullyCharged(void) 1423{ 1424 return (kOSBooleanTrue == properties->getObject(_FullyChargedSym)); 1425} 1426 1427 1428/****************************************************************************** 1429 ****************************************************************************** 1430 ** 1431 ** Async SmartBattery read convenience functions 1432 ** 1433 ****************************************************************************** 1434 ******************************************************************************/ 1435IOReturn AppleSmartBattery::readWordAsync( 1436 uint32_t refnum, 1437 uint8_t address, 1438 uint8_t cmd 1439) { 1440 IOReturn ret = kIOReturnError; 1441 bzero(&fTransaction, sizeof(IOSMBusTransaction)); 1442 1443 // All transactions are performed async 1444 fTransaction.protocol = kIOSMBusProtocolReadWord; 1445 fTransaction.address = address; 1446 fTransaction.command = cmd; 1447 1448 ret = fProvider->performTransaction( 1449 &fTransaction, 1450 OSMemberFunctionCast(IOSMBusTransactionCompletion, 1451 this, &AppleSmartBattery::transactionCompletion), 1452 (OSObject *)this, 1453 (void *)(uintptr_t)refnum); 1454 1455 return ret; 1456} 1457 1458IOReturn AppleSmartBattery::writeWordAsync( 1459 uint32_t refnum, 1460 uint8_t address, 1461 uint8_t cmd, 1462 uint16_t writeWord) 1463{ 1464 IOReturn ret = kIOReturnError; 1465 bzero(&fTransaction, sizeof(IOSMBusTransaction)); 1466 1467 // All transactions are performed async 1468 fTransaction.protocol = kIOSMBusProtocolWriteWord; 1469 fTransaction.address = address; 1470 fTransaction.command = cmd; 1471 fTransaction.sendData[0] = writeWord & 0xFF; 1472 fTransaction.sendData[1] = (writeWord >> 8) & 0xFF; 1473 fTransaction.sendDataCount = 2; 1474 1475 ret = fProvider->performTransaction( 1476 &fTransaction, 1477 OSMemberFunctionCast(IOSMBusTransactionCompletion, 1478 this, &AppleSmartBattery::transactionCompletion), 1479 (OSObject *)this, 1480 (void *)((uintptr_t)refnum)); 1481 1482 return ret; 1483 1484} 1485 1486IOReturn AppleSmartBattery::readBlockAsync( 1487 uint32_t refnum, 1488 uint8_t address, 1489 uint8_t cmd 1490) { 1491 IOReturn ret = kIOReturnError; 1492 bzero(&fTransaction, sizeof(IOSMBusTransaction)); 1493 1494 // All transactions are performed async 1495 fTransaction.protocol = kIOSMBusProtocolReadBlock; 1496 fTransaction.address = address; 1497 fTransaction.command = cmd; 1498 1499 ret = fProvider->performTransaction( 1500 &fTransaction, 1501 OSMemberFunctionCast(IOSMBusTransactionCompletion, 1502 this, &AppleSmartBattery::transactionCompletion), 1503 (OSObject *)this, 1504 (void *)(uintptr_t)refnum); 1505 1506 return ret; 1507} 1508 1509