AppleSmartBattery.cpp [plain text]
#include <IOKit/IOService.h>
#include <IOKit/IOWorkLoop.h>
#include <IOKit/IOTimerEventSource.h>
#include <IOKit/pwr_mgt/RootDomain.h>
#include <IOKit/pwr_mgt/IOPMPrivate.h>
#include <libkern/c++/OSObject.h>
#include "AppleSmartBatteryManager.h"
#include "AppleSmartBattery.h"
enum {
kExistingBatteryPath = 1,
kNewBatteryPath = 2
};
enum {
kRetryAttempts = 5,
kInitialPollCountdown = 5,
kIncompleteReadRetryMax = 10
};
enum {
kSecondsUntilValidOnWake = 30,
kPostChargeWaitSeconds = 120,
kPostDischargeWaitSeconds = 120
};
enum {
kDefaultPollInterval = 0,
kQuickPollInterval = 1
};
#define kErrorRetryAttemptsExceeded "Read Retry Attempts Exceeded"
#define kErrorOverallTimeoutExpired "Overall Read Timeout Expired"
#define kErrorZeroCapacity "Capacity Read Zero"
#define kErrorPermanentFailure "Permanent Battery Failure"
#define kErrorNonRecoverableStatus "Non-recoverable status failure"
static uint32_t milliSecPollingTable[2] =
{
30000, 1000 };
static const uint32_t kBatteryReadAllTimeout = 10000;
static const uint32_t microSecDelayTable[kRetryAttempts] =
{ 10, 100, 1000, 10000, 250000 };
#define STATUS_ERROR_NEEDS_RETRY(err) \
( (kIOSMBusStatusDeviceAddressNotAcknowledged == err) \
|| (kIOSMBusStatusDeviceCommandAccessDenied == err) \
|| (kIOSMBusStatusDeviceAccessDenied == err) \
|| (kIOSMBusStatusUnknownHostError == err) \
|| (kIOSMBusStatusUnknownFailure == err) \
|| (kIOSMBusStatusDeviceError == err) \
|| (kIOSMBusStatusTimeout == err) \
|| (kIOSMBusStatusBusy == err) )
#define STATUS_ERROR_NON_RECOVERABLE(err) \
( (kIOSMBusStatusHostUnsupportedProtocol == err) \
|| (kIOSMBusStatusPECError == err) )
static const OSSymbol *_MaxErrSym =
OSSymbol::withCString(kIOPMPSMaxErrKey);
static const OSSymbol *_DeviceNameSym =
OSSymbol::withCString(kIOPMDeviceNameKey);
static const OSSymbol *_FullyChargedSym =
OSSymbol::withCString(kIOPMFullyChargedKey);
static const OSSymbol *_AvgTimeToEmptySym =
OSSymbol::withCString("AvgTimeToEmpty");
static const OSSymbol *_AvgTimeToFullSym =
OSSymbol::withCString("AvgTimeToFull");
static const OSSymbol *_ManfDateSym =
OSSymbol::withCString(kIOPMPSManufactureDateKey);
static const OSSymbol *_DesignCapacitySym =
OSSymbol::withCString(kIOPMPSDesignCapacityKey);
#define super IOPMPowerSource
OSDefineMetaClassAndStructors(AppleSmartBattery,IOPMPowerSource)
AppleSmartBattery *
AppleSmartBattery::smartBattery(void)
{
AppleSmartBattery *me;
me = new AppleSmartBattery;
if(me && !me->init()) {
me->release();
return NULL;
}
return me;
}
bool AppleSmartBattery::init(void)
{
if(!super::init()) {
return false;
}
fProvider = NULL;
fWorkLoop = NULL;
fPollTimer = NULL;
return true;
}
bool AppleSmartBattery::start(IOService *provider)
{
IOReturn err;
OSNumber *debugPollingSetting;
BattLog("AppleSmartBattery loading...\n");
fProvider = OSDynamicCast(AppleSmartBatteryManager, provider);
if(!fProvider || !super::start(provider)) {
return false;
}
debugPollingSetting = (OSNumber *)fProvider->getProperty(kBatteryPollingDebugKey);
if( debugPollingSetting && OSDynamicCast(OSNumber, debugPollingSetting) )
{
fPollingInterval = debugPollingSetting->unsigned32BitValue();
fPollingOverridden = true;
} else {
fPollingInterval = kDefaultPollInterval;
fPollingOverridden = false;
}
fPollingNow = false;
fCancelPolling = false;
fRetryAttempts = 0;
fFullyDischarged = false;
fFullyCharged = false;
fBatteryPresent = false;
fACConnected = false;
fAvgCurrent = 0;
fInflowDisabled = false;
fRebootPolling = false;
fIncompleteReadRetries = kIncompleteReadRetryMax;
fInitialPollCountdown = kInitialPollCountdown;
fWorkLoop = getWorkLoop();
fPollTimer = IOTimerEventSource::timerEventSource( this,
OSMemberFunctionCast( IOTimerEventSource::Action,
this, &AppleSmartBattery::pollingTimeOut) );
fBatteryReadAllTimer = IOTimerEventSource::timerEventSource( this,
OSMemberFunctionCast( IOTimerEventSource::Action,
this, &AppleSmartBattery::incompleteReadTimeOut) );
if( !fWorkLoop || !fPollTimer
|| (kIOReturnSuccess != fWorkLoop->addEventSource(fPollTimer)) )
{
return false;
}
setProperty( kIOPMPSInvalidWakeSecondsKey,
kSecondsUntilValidOnWake, 32);
setProperty( kIOPMPSPostChargeWaitSecondsKey,
kPostChargeWaitSeconds, 32);
setProperty( kIOPMPSPostDishargeWaitSecondsKey,
kPostDischargeWaitSeconds, 32);
clearBatteryState(false);
BattLog("AppleSmartBattery polling battery data.\n");
pollBatteryState( kNewBatteryPath );
return true;
}
void AppleSmartBattery::logReadError(
const char *error_type,
uint16_t additional_error,
IOSMBusTransaction *t)
{
if(!error_type) return;
setProperty((const char *)"LatestErrorType", error_type);
IOLog("SmartBatteryManager Error: %s (%d)\n", error_type, additional_error);
if(t) {
IOLog("\tCorresponding transaction addr=0x%02x cmd=0x%02x status=0x%02x\n",
t->address, t->command, t->status);
}
return;
}
void AppleSmartBattery::setPollingInterval(
int milliSeconds)
{
if (!fPollingOverridden) {
milliSecPollingTable[kDefaultPollInterval] = milliSeconds;
fPollingInterval = kDefaultPollInterval;
}
}
bool AppleSmartBattery::pollBatteryState(int path)
{
fMachinePath = path;
if( !fPollingNow )
{
return transactionCompletion((void *)0, NULL);
} else {
fRebootPolling = true;
}
}
void AppleSmartBattery::handleBatteryInserted(void)
{
pollBatteryState( kNewBatteryPath );
return;
}
void AppleSmartBattery::handleBatteryRemoved(void)
{
if(fPollingNow) {
fCancelPolling = true;
fPollTimer->cancelTimeout();
fBatteryReadAllTimer->cancelTimeout();
}
clearBatteryState(true);
return;
}
void AppleSmartBattery::handleInflowDisabled(bool inflow_state)
{
fInflowDisabled = inflow_state;
pollBatteryState(kExistingBatteryPath);
return;
}
void AppleSmartBattery::handleChargeInhibited(bool charge_state)
{
fChargeInhibited = charge_state;
pollBatteryState(kExistingBatteryPath);
}
void AppleSmartBattery::pollingTimeOut(void)
{
if( !fPollingNow )
pollBatteryState( kExistingBatteryPath );
}
void AppleSmartBattery::incompleteReadTimeOut(void)
{
logReadError(kErrorOverallTimeoutExpired, 0, NULL);
if( 0 < fIncompleteReadRetries )
{
fIncompleteReadRetries--;
pollBatteryState( kNewBatteryPath );
}
}
bool AppleSmartBattery::transactionCompletion(
void *ref,
IOSMBusTransaction *transaction)
{
int next_state = (int)ref;
int16_t my_signed_16;
uint16_t my_unsigned_16;
uint8_t time_command = 0;
uint32_t delay_for = 0;
IOSMBusStatus transaction_status;
bool transaction_needs_retry = false;
char recv_str[kIOSMBusMaxDataCount+1];
if( transaction && fCancelPolling )
{
fCancelPolling = false;
fPollingNow = false;
return true;
}
if( NULL == transaction || fRebootPolling )
{
next_state = 0;
fRebootPolling = false;
} else {
transaction_status = transaction->status;
BattLog("transaction state = 0x%02x; status = 0x%02x\n; word = %02x.%02x",
next_state, transaction_status,
transaction->receiveData[1], transaction->receiveData[0]);
if( STATUS_ERROR_NEEDS_RETRY(transaction_status) )
{
transaction_needs_retry = true;
} else if( STATUS_ERROR_NON_RECOVERABLE(transaction_status) )
{
transaction_needs_retry = false;
logReadError(kErrorNonRecoverableStatus, transaction_status, transaction);
}
if( (kIOSMBusStatusOK == transaction_status)
&& (0 != fRetryAttempts) )
{
BattLog("SmartBattery: retry %d succeeded!\n", fRetryAttempts);
fRetryAttempts = 0;
transaction_needs_retry = false;
}
if( kIOSMBusStatusOK == transaction_status )
{
if( ((kBFullChargeCapacityCmd == transaction->command)
|| (kBDesignCapacityCmd == transaction->command)
|| ((kBRemainingCapacityCmd == transaction->command)
&& !fFullyDischarged) )
&& ((transaction->receiveData[1] == 0)
&& (transaction->receiveData[0] == 0)) )
{
IOLog("SmartBatteryManager: retrying command 0x%02x; retry due to absurd value _zero_\n",
transaction->command);
transaction_needs_retry = true;
}
if( ((kBRemainingCapacityCmd == transaction->command)
|| (kBDesignCapacityCmd == transaction->command)
|| (kBFullChargeCapacityCmd == transaction->command))
&& ((transaction->receiveData[1] != 0)
|| (transaction->receiveData[0] != 0))
&& (0 != fRetryAttempts) )
{
IOLog("SmartBatteryManager: Successfully read %d on retry %d\n",
transaction->command, fRetryAttempts);
fRetryAttempts = 0;
transaction_needs_retry = false;
}
}
if( transaction_needs_retry
&& (kRetryAttempts == fRetryAttempts) )
{
setProperty("LastBattReadError", transaction_status, 16);
setProperty("LastBattReadErrorCmd", transaction->command, 16);
IOLog("SmartBatteryManager: Giving up on retries\n");
BattLog("SmartBattery: Giving up on (0x%02x, 0x%02x) after %d retries.\n",
transaction->address, transaction->command, fRetryAttempts);
logReadError(kErrorRetryAttemptsExceeded, transaction_status, transaction);
fRetryAttempts = 0;
transaction_needs_retry = false;
}
if( transaction_needs_retry )
{
delay_for = microSecDelayTable[fRetryAttempts];
if( 0 != delay_for ) {
if( delay_for < 1000 ) {
IODelay(delay_for);
} else {
IOSleep(delay_for / 1000);
}
}
fRetryAttempts++;
BattLog("SmartBattery: 0x%02x failed with 0x%02x; retry attempt %d of %d\n",
transaction->command, transaction_status, fRetryAttempts, kRetryAttempts);
readWordAsync(transaction->address, transaction->command);
return true;
}
}
switch(next_state)
{
case 0:
fPollTimer->cancelTimeout();
fCancelPolling = false;
fPollingNow = true;
fBatteryReadAllTimer->cancelTimeout();
fBatteryReadAllTimer->setTimeoutMS( kBatteryReadAllTimeout );
readWordAsync(kSMBusManagerAddr, kMStateContCmd);
break;
case kMStateContCmd:
if( kIOSMBusStatusOK == transaction_status )
{
int new_ac_connected;
my_unsigned_16 = (transaction->receiveData[1] << 8)
| transaction->receiveData[0];
new_ac_connected = ( !fInflowDisabled
&& (my_unsigned_16 & kMACPresentBit) ) ? 1:0;
IOPMrootDomain *rd = getPMRootDomain();
if( rd && (new_ac_connected != fACConnected) ) {
if(new_ac_connected) {
rd->receivePowerNotification( kIOPMSetACAdaptorConnected
| kIOPMSetValue );
} else {
rd->receivePowerNotification(kIOPMSetACAdaptorConnected);
}
}
fACConnected = new_ac_connected;
setExternalConnected(fACConnected);
setExternalChargeCapable(
(my_unsigned_16 & kMPowerNotGoodBit) ? false:true);
} else {
fACConnected = false;
setExternalConnected(true);
setExternalChargeCapable(false);
}
readWordAsync(kSMBusManagerAddr, kMStateCmd);
break;
case kMStateCmd:
if( kIOSMBusStatusOK == transaction_status )
{
my_unsigned_16 = (transaction->receiveData[1] << 8)
| transaction->receiveData[0];
fBatteryPresent = (my_unsigned_16 & kMPresentBatt_A_Bit)
? true : false;
setBatteryInstalled(fBatteryPresent);
setIsCharging( !fChargeInhibited
&& (my_unsigned_16 & kMChargingBatt_A_Bit) ? true:false);
} else {
fBatteryPresent = false;
setBatteryInstalled(false);
setIsCharging(false);
}
if(!fBatteryPresent) {
fPollingNow = false;
clearBatteryState(true);
return true;
}
readWordAsync(kSMBusBatteryAddr, kBBatteryStatusCmd);
break;
case kBBatteryStatusCmd:
if( kIOSMBusStatusOK != transaction_status )
{
fFullyCharged = false;
fFullyDischarged = false;
} else {
my_unsigned_16 = (transaction->receiveData[1] << 8)
| transaction->receiveData[0];
if ( my_unsigned_16 & kBFullyChargedStatusBit) {
fFullyCharged = true;
} else {
fFullyCharged = false;
}
if ( my_unsigned_16 & kBFullyDischargedStatusBit)
{
if(!fFullyDischarged) {
fFullyDischarged = true;
fProvider->handleFullDischarge();
}
} else {
fFullyDischarged = false;
}
if( (my_unsigned_16
& (kBTerminateDischargeAlarmBit | kBTerminateChargeAlarmBit))
== (kBTerminateDischargeAlarmBit | kBTerminateChargeAlarmBit) )
{
logReadError( kErrorPermanentFailure, 0, transaction);
setProperty( kErrorPermanentFailure, true);
fBatteryReadAllTimer->cancelTimeout();
fPollingNow = false;
handleBatteryRemoved();
}
}
setFullyCharged(fFullyCharged);
if(kNewBatteryPath == fMachinePath) {
readBlockAsync(kSMBusBatteryAddr, kBManufactureNameCmd);
} else {
readWordAsync(kSMBusBatteryAddr, kBRemainingCapacityCmd);
}
break;
case kBManufactureNameCmd:
if( kIOSMBusStatusOK == transaction_status )
{
if(0 != transaction->receiveDataCount)
{
const OSSymbol *manf_sym;
bzero(recv_str, sizeof(recv_str));
bcopy(transaction->receiveData, recv_str,
transaction->receiveDataCount);
manf_sym = OSSymbol::withCString(recv_str);
if(manf_sym) {
setManufacturer((OSSymbol *)manf_sym);
manf_sym->release();
}
}
} else {
properties->removeObject(manufacturerKey);
}
readWordAsync(kSMBusBatteryAddr, kBManufactureDateCmd);
break;
case kBManufactureDateCmd:
if( kIOSMBusStatusOK == transaction_status )
{
setManufactureDate(
(uint32_t)(transaction->receiveData[0]
| (transaction->receiveData[1] << 8)));
} else {
setManufactureDate(0);
}
readBlockAsync(kSMBusBatteryAddr, kBDeviceNameCmd);
break;
case kBDeviceNameCmd:
if( kIOSMBusStatusOK == transaction_status )
{
if(0 != transaction->receiveDataCount)
{
const OSSymbol *device_sym;
bzero(recv_str, sizeof(recv_str));
bcopy(transaction->receiveData, recv_str,
transaction->receiveDataCount);
device_sym = OSSymbol::withCString(recv_str);
if(device_sym) {
setDeviceName((OSSymbol *)device_sym);
device_sym->release();
}
}
} else {
properties->removeObject(_DeviceNameSym);
}
readWordAsync(kSMBusBatteryAddr, kBSerialNumberCmd);
break;
case kBSerialNumberCmd:
if( kIOSMBusStatusOK == transaction_status )
{
const OSSymbol *serialSym;
bzero(recv_str, sizeof(recv_str));
snprintf(recv_str, sizeof(recv_str), "%d",
( transaction->receiveData[0]
| (transaction->receiveData[1] << 8) ));
serialSym = OSSymbol::withCString(recv_str);
if(serialSym) {
setSerial( (OSSymbol *) serialSym);
serialSym->release();
}
} else {
properties->removeObject(serialKey);
}
readWordAsync(kSMBusBatteryAddr, kBDesignCapacityCmd);
break;
case kBDesignCapacityCmd:
if( kIOSMBusStatusOK == transaction_status )
{
OSNumber *design_cap;
design_cap = OSNumber::withNumber(
(uint32_t)(transaction->receiveData[0]
| (transaction->receiveData[1] << 8)), 32);
if(design_cap) {
properties->setObject(_DesignCapacitySym, design_cap);
design_cap->release();
}
} else {
OSNumber *zero_num = OSNumber::withNumber((long long unsigned int)0, 32);
if(zero_num) {
properties->setObject(_DesignCapacitySym, zero_num);
zero_num->release();
}
}
readWordAsync(kSMBusBatteryAddr, kBRemainingCapacityCmd);
break;
case kBRemainingCapacityCmd:
if( kIOSMBusStatusOK == transaction_status )
{
my_unsigned_16 = (transaction->receiveData[1] << 8)
| transaction->receiveData[0];
fRemainingCapacity = my_unsigned_16;
setCurrentCapacity( (unsigned int)my_unsigned_16 );
} else {
fRemainingCapacity = 0;
setCurrentCapacity(0);
}
if ( 0 == fRemainingCapacity )
{
logReadError(kErrorZeroCapacity, kBRemainingCapacityCmd, transaction);
}
readWordAsync(kSMBusBatteryAddr, kBFullChargeCapacityCmd);
break;
case kBFullChargeCapacityCmd:
if( kIOSMBusStatusOK == transaction_status )
{
my_unsigned_16 = (transaction->receiveData[1] << 8)
| transaction->receiveData[0];
fFullChargeCapacity = my_unsigned_16;
setMaxCapacity( my_unsigned_16 );
if( !fPollingOverridden && fFullChargeCapacity )
{
if( (((100*fRemainingCapacity) / fFullChargeCapacity ) < 5)
&& fACConnected )
{
setProperty("Quick Poll", true);
fPollingInterval = kQuickPollInterval;
} else {
setProperty("Quick Poll", false);
fPollingInterval = kDefaultPollInterval;
}
}
} else {
fFullChargeCapacity == 0;
setMaxCapacity(0);
}
if ( (0 == fFullChargeCapacity) )
{
logReadError(kErrorZeroCapacity, kBFullChargeCapacityCmd, transaction);
}
readWordAsync(kSMBusBatteryAddr, kBAverageCurrentCmd);
break;
case kBAverageCurrentCmd:
time_command = 0;
if( kIOSMBusStatusOK == transaction_status )
{
my_signed_16 = (transaction->receiveData[1] << 8)
| transaction->receiveData[0];
setAmperage( my_signed_16 );
fAvgCurrent = my_signed_16;
} else {
fAvgCurrent = 0;
setAmperage(0);
setTimeRemaining(0);
}
readWordAsync(kSMBusBatteryAddr, kBVoltageCmd);
break;
case kBVoltageCmd:
if( kIOSMBusStatusOK == transaction_status )
{
my_unsigned_16 = (transaction->receiveData[1] << 8)
| transaction->receiveData[0];
setVoltage( my_unsigned_16 );
} else {
setVoltage(0);
}
readWordAsync(kSMBusBatteryAddr, kBMaxErrorCmd);
break;
case kBMaxErrorCmd:
if( kIOSMBusStatusOK == transaction_status )
{
my_unsigned_16 = (transaction->receiveData[1] << 8)
| transaction->receiveData[0];
setMaxErr( my_unsigned_16 );
} else {
setMaxErr(0);
}
readWordAsync(kSMBusBatteryAddr, kBCycleCountCmd);
break;
case kBCycleCountCmd:
if( kIOSMBusStatusOK == transaction_status )
{
my_unsigned_16 = (transaction->receiveData[1] << 8)
| transaction->receiveData[0];
setCycleCount( my_unsigned_16 );
} else {
setCycleCount(0);
}
readWordAsync(kSMBusBatteryAddr, kBAverageTimeToEmptyCmd);
break;
case kBAverageTimeToEmptyCmd:
if( kIOSMBusStatusOK == transaction_status )
{
my_unsigned_16 = (transaction->receiveData[1] << 8)
| transaction->receiveData[0];
setAverageTimeToEmpty( my_unsigned_16 );
if(fAvgCurrent < 0) {
setTimeRemaining( my_unsigned_16 );
}
} else {
setTimeRemaining(0);
setAverageTimeToEmpty(0);
}
readWordAsync(kSMBusBatteryAddr, kBAverageTimeToFullCmd);
break;
case kBAverageTimeToFullCmd:
if( kIOSMBusStatusOK == transaction_status )
{
my_unsigned_16 = (transaction->receiveData[1] << 8)
| transaction->receiveData[0];
setAverageTimeToFull( my_unsigned_16 );
if(fAvgCurrent > 0) {
setTimeRemaining( my_unsigned_16 );
}
} else {
setTimeRemaining(0);
setAverageTimeToFull(0);
}
readWordAsync(kSMBusBatteryAddr, kBCurrentCmd);
break;
case kBCurrentCmd:
int16_t signed_16;
if( kIOSMBusStatusOK == transaction_status )
{
signed_16 = (transaction->receiveData[1] << 8)
| transaction->receiveData[0];
setProperty((const char *)"RealCurrent",
(long long unsigned int)signed_16,
(unsigned int)16);
} else {
setProperty((const char *)"RealCurrent",
(long long unsigned int)0,
(unsigned int)16);
}
fBatteryReadAllTimer->cancelTimeout();
rebuildLegacyIOBatteryInfo();
updateStatus();
fPollingNow = false;
if( fPollingOverridden && (fPollingInterval==0))
{
pollBatteryState( kNewBatteryPath );
return true;
}
if( (fInitialPollCountdown > 0)
|| !fACConnected
|| (!fFullyCharged && fBatteryPresent)
|| fPollingOverridden )
{
if( fInitialPollCountdown > 0) {
fInitialPollCountdown--;
}
if( !fPollingOverridden )
{
fPollTimer->setTimeoutMS( milliSecPollingTable[fPollingInterval] );
} else {
fPollTimer->setTimeoutMS( 1000 * fPollingInterval );
}
} else {
BattLog("SmartBattery: letting timeout expire.\n");
}
break;
default:
BattLog("SmartBattery: Error state %d not expected\n", next_state);
}
return true;
}
void AppleSmartBattery::clearBatteryState(bool do_update)
{
fRetryAttempts = 0;
fFullyDischarged = false;
fFullyCharged = false;
fBatteryPresent = false;
fACConnected = false;
fAvgCurrent = 0;
setBatteryInstalled(false);
setIsCharging(false);
setCurrentCapacity(0);
setMaxCapacity(0);
setTimeRemaining(0);
setAmperage(0);
setVoltage(0);
setCycleCount(0);
setAdapterInfo(0);
setLocation(0);
properties->removeObject(manufacturerKey);
properties->removeObject(serialKey);
properties->removeObject(batteryInfoKey);
if(getProperty(kErrorPermanentFailure)) {
removeProperty(kErrorPermanentFailure);
}
rebuildLegacyIOBatteryInfo();
if(do_update) {
updateStatus();
}
}
void AppleSmartBattery::rebuildLegacyIOBatteryInfo(void)
{
OSDictionary *legacyDict = OSDictionary::withCapacity(5);
uint32_t flags = 0;
OSNumber *flags_num = NULL;
if(externalConnected()) flags |= kIOPMACInstalled;
if(batteryInstalled()) flags |= kIOPMBatteryInstalled;
if(isCharging()) flags |= kIOPMBatteryCharging;
flags_num = OSNumber::withNumber((unsigned long long)flags, 32);
legacyDict->setObject(kIOBatteryFlagsKey, flags_num);
flags_num->release();
legacyDict->setObject(kIOBatteryCurrentChargeKey, properties->getObject(kIOPMPSCurrentCapacityKey));
legacyDict->setObject(kIOBatteryCapacityKey, properties->getObject(kIOPMPSMaxCapacityKey));
legacyDict->setObject(kIOBatteryVoltageKey, properties->getObject(kIOPMPSVoltageKey));
legacyDict->setObject(kIOBatteryAmperageKey, properties->getObject(kIOPMPSAmperageKey));
legacyDict->setObject(kIOBatteryCycleCountKey, properties->getObject(kIOPMPSCycleCountKey));
setLegacyIOBatteryInfo(legacyDict);
legacyDict->release();
}
void AppleSmartBattery::setMaxErr(int error)
{
OSNumber *n = OSNumber::withNumber(error, 32);
if(n) {
properties->setObject(_MaxErrSym, n);
n->release();
}
}
int AppleSmartBattery::maxErr(void)
{
OSNumber *n = OSDynamicCast(OSNumber, properties->getObject(_MaxErrSym));
if(n) {
return n->unsigned32BitValue();
} else {
return 0;
}
}
void AppleSmartBattery::setDeviceName(OSSymbol *sym)
{
if(sym) {
properties->setObject(_DeviceNameSym, (OSObject *)sym);
}
}
OSSymbol * AppleSmartBattery::deviceName(void)
{
return OSDynamicCast(OSSymbol, properties->getObject(_DeviceNameSym));
}
void AppleSmartBattery::setFullyCharged(bool charged)
{
properties->setObject(
_FullyChargedSym,
(charged ? kOSBooleanTrue:kOSBooleanFalse) );
}
bool AppleSmartBattery::fullyCharged(void)
{
return (kOSBooleanTrue == properties->getObject(_FullyChargedSym));
}
void AppleSmartBattery::setAverageTimeToEmpty(int seconds)
{
OSNumber *n = OSNumber::withNumber(seconds, 32);
if(n) {
properties->setObject(_AvgTimeToEmptySym, n);
n->release();
}
}
int AppleSmartBattery::averageTimeToEmpty(void)
{
OSNumber *n = OSDynamicCast(OSNumber, properties->getObject(_AvgTimeToEmptySym));
if(n) {
return n->unsigned32BitValue();
} else {
return 0;
}
}
void AppleSmartBattery::setAverageTimeToFull(int seconds)
{
OSNumber *n = OSNumber::withNumber(seconds, 32);
if(n) {
properties->setObject(_AvgTimeToFullSym, n);
n->release();
}
}
int AppleSmartBattery::averageTimeToFull(void)
{
OSNumber *n = OSDynamicCast(OSNumber, properties->getObject(_AvgTimeToFullSym));
if(n) {
return n->unsigned32BitValue();
} else {
return 0;
}
}
void AppleSmartBattery::setManufactureDate(int date)
{
OSNumber *n = OSNumber::withNumber(date, 32);
if(n) {
properties->setObject(_ManfDateSym, n);
n->release();
}
}
int AppleSmartBattery::manufactureDate(void)
{
OSNumber *n = OSDynamicCast(OSNumber, properties->getObject(_ManfDateSym));
if(n) {
return n->unsigned32BitValue();
} else {
return 0;
}
}
IOReturn AppleSmartBattery::readWordAsync(
uint8_t address,
uint8_t cmd
) {
IOReturn ret = kIOReturnError;
bzero(&fTransaction, sizeof(IOSMBusTransaction));
fTransaction.protocol = kIOSMBusProtocolReadWord;
fTransaction.address = address;
fTransaction.command = cmd;
ret = fProvider->performTransaction(
&fTransaction,
OSMemberFunctionCast( IOSMBusTransactionCompletion,
this, &AppleSmartBattery::transactionCompletion),
(OSObject *)this,
(void *)cmd);
return ret;
}
IOReturn AppleSmartBattery::readBlockAsync(
uint8_t address,
uint8_t cmd
) {
IOReturn ret = kIOReturnError;
bzero(&fTransaction, sizeof(IOSMBusTransaction));
fTransaction.protocol = kIOSMBusProtocolReadBlock;
fTransaction.address = address;
fTransaction.command = cmd;
ret = fProvider->performTransaction(
&fTransaction,
OSMemberFunctionCast( IOSMBusTransactionCompletion,
this, &AppleSmartBattery::transactionCompletion),
(OSObject *)this,
(void *)cmd);
return ret;
}