📄 smbbatt.c
字号:
// Check the status that was read versus what we wrote
// to see if the operation was successful
//
// To support simultaneous charging of more than one battery,
// we can't check the charge nibble to see if it is equal to
// what we wrote, but we can check to see if the battery
// we specified to charge is now set to charge.
tmp = (selectorState & SELECTOR_STATE_CHARGE_MASK) >> SELECTOR_SHIFT_CHARGE;
if (SmbBattReverseLogic(SmbBatt->Selector, tmp)) {
tmp ^= SELECTOR_STATE_PRESENT_MASK;
}
if (tmp & SmbBatt->SelectorBitPosition) {
BattPrint(BAT_IRPS, ("SmbBattSetInformation: successfully set charging battery\n"));
//
// Success! Save the new selector state in the cache
//
SmbBatt->Selector->SelectorState = selectorState;
status = STATUS_SUCCESS;
} else {
BattPrint(BAT_ERROR, ("SmbBattSetInformation: couldn't set charging battery\n"));
status = STATUS_UNSUCCESSFUL;
}
break;
case BatteryDischarge:
BattPrint(BAT_IRPS, ("SmbBattSetInformation: Got SetInformation for BatteryDischarge\n"));
//
// Set the appropriate bit in the selector state power by nibble
//
newSelectorState = SELECTOR_SET_POWER_BY_MASK;
newSelectorState |= (SmbBatt->SelectorBitPosition << SELECTOR_SHIFT_POWER);
//
// Write the new selector state, then read it back. The system
// may or may not let us do this.
//
smbStatus = SmbBattGenericWW (
SmbBatt->SmbHcFdo,
SmbBatt->Selector->SelectorAddress,
SmbBatt->Selector->SelectorStateCommand,
newSelectorState
);
if (smbStatus != SMB_STATUS_OK) {
BattPrint(BAT_ERROR,
("SmbBattSetInformation: couldn't write selector state - %x\n",
smbStatus)
);
status = STATUS_UNSUCCESSFUL;
break;
}
smbStatus = SmbBattGenericRW (
SmbBatt->SmbHcFdo,
SmbBatt->Selector->SelectorAddress,
SmbBatt->Selector->SelectorStateCommand,
&selectorState
);
if ((smbStatus != SMB_STATUS_OK)) {
BattPrint(BAT_ERROR,
("SmbBattSetInformation: couldn't read selector state - %x\n",
smbStatus)
);
status = STATUS_UNSUCCESSFUL;
break;
}
//
// Check the status that was read versus what we wrote
// to see if the operation was successful
//
// To support simultaneous powering of more than one battery,
// we can't check the power nibble to see if it is equal to
// what we wrote, but we can check to see if the battery
// we specified to power by is now set to power the system.
tmp = (selectorState & SELECTOR_STATE_POWER_BY_MASK) >> SELECTOR_SHIFT_POWER;
if (SmbBattReverseLogic(SmbBatt->Selector, tmp)) {
tmp ^= SELECTOR_STATE_PRESENT_MASK;
}
if (tmp & SmbBatt->SelectorBitPosition) {
BattPrint(BAT_IRPS, ("SmbBattSetInformation: successfully set powering battery\n"));
//
// Success! Save the new selector state in the cache
//
SmbBatt->Selector->SelectorState = selectorState;
status = STATUS_SUCCESS;
} else {
BattPrint(BAT_ERROR, ("SmbBattSetInformation: couldn't set powering battery\n"));
status = STATUS_UNSUCCESSFUL;
}
break;
} // switch (Level)
//
// Release the lock on the selector
//
SmbBattUnlockSelector (SmbBatt->Selector);
} // if (SmbBatt->Selector->SelectorPresent)
BattPrint(BAT_TRACE, ("SmbBattSetInformation: EXITING\n"));
return status;
}
NTSTATUS
SmbBattGetPowerState (
IN PSMB_BATT SmbBatt,
OUT PULONG PowerState,
OUT PLONG Current
)
/*++
Routine Description:
Returns the current state of AC power. There are several cases which
make this far more complex than it really ought to be.
NOTE: the selector must be locked before entering this routine.
Arguments:
SmbBatt - Miniport context value for battery
AcConnected - Pointer to a boolean where the AC status is returned
Return Value:
NTSTATUS
--*/
{
ULONG tmp;
ULONG chargeBattery;
ULONG powerBattery;
NTSTATUS status;
UCHAR smbStatus;
PAGED_CODE();
status = STATUS_SUCCESS;
*PowerState = 0;
//
// Is there a selector in the system? if not, go read directly from the charger
//
if ((SmbBatt->SelectorPresent) && (SmbBatt->Selector)) {
//
// There is a selector, we will examine the CHARGE nibble of the state register
//
SmbBattGenericRW(
SmbBatt->SmbHcFdo,
SMB_SELECTOR_ADDRESS,
SELECTOR_SELECTOR_STATE,
&SmbBatt->Selector->SelectorState);
chargeBattery = (SmbBatt->Selector->SelectorState & SELECTOR_STATE_CHARGE_MASK) >> SELECTOR_SHIFT_CHARGE;
powerBattery = (SmbBatt->Selector->SelectorState & SELECTOR_STATE_POWER_BY_MASK) >> SELECTOR_SHIFT_POWER;
//
// If the bits in the CHARGE_X nibble of the selector state register are in the
// reverse logic state, then AC is connected, otherwise AC is not connected.
//
// NOTE: This code depends on every selector implementing this. If it turns out
// that this is optional, we can no longer depend on this, and must enable the
// code below it.
//
if (SmbBattReverseLogic(SmbBatt->Selector, chargeBattery)) {
*PowerState |= BATTERY_POWER_ON_LINE;
}
//
// Look at Charge Indicator if it is supported
//
if (*PowerState & BATTERY_POWER_ON_LINE) {
if (SmbBatt->Selector->SelectorInfo & SELECTOR_INFO_CHARGING_INDICATOR_BIT) {
if (SmbBattReverseLogic(SmbBatt->Selector, powerBattery)) {
*PowerState |= BATTERY_CHARGING;
}
}
if (*Current > 0) {
*PowerState |= BATTERY_CHARGING;
}
} else {
if (*Current <= 0) {
//
// There is some small leakage on some systems, even when AC
// is present. So, if AC is present, and the draw
// is below this "noise" level we will not report as discharging
// and zero this out.
//
if (*Current < -25) {
*PowerState |= BATTERY_DISCHARGING;
} else {
*Current = 0;
}
}
//else {
// *PowerState |= BATTERY_CHARGING;
//
//}
// If we don't report as discharging, then the AC adapter removal
// might cause a PowerState of 0 to return, which PowerMeter assumes
// means, don't change anything
*PowerState |= BATTERY_DISCHARGING;
}
} else {
//
// There is no selector, so we'll try to read from the charger.
//
smbStatus = SmbBattGenericRW (
SmbBatt->SmbHcFdo,
SMB_CHARGER_ADDRESS,
CHARGER_STATUS,
&tmp
);
if (smbStatus != SMB_STATUS_OK) {
BattPrint (
BAT_ERROR,
("SmbBattGetPowerState: Trying to get charging info, couldn't read from charger at %x, status %x\n",
SMB_CHARGER_ADDRESS,
smbStatus)
);
*PowerState = 0;
status = STATUS_UNSUCCESSFUL;
}
// Read Charger Successful
else {
if (tmp & CHARGER_STATUS_AC_PRESENT_BIT) {
*PowerState = BATTERY_POWER_ON_LINE;
if (*Current > 0) {
*PowerState |= BATTERY_CHARGING;
}
} else {
if (*Current <= 0) {
//
// There is some small leakage on some systems, even when AC
// is present. So, if AC is present, and the draw
// is below this "noise" level we will not report as discharging
// and zero this out.
//
if (*Current < -25) {
*PowerState |= BATTERY_DISCHARGING;
} else {
*Current = 0;
}
}
// If we don't report as discharging, then the AC adapter removal
// might cause a PowerState of 0 to return, which PowerMeter assumes
// means, don't change anything
*PowerState |= BATTERY_DISCHARGING;
}
}
}
return status;
}
NTSTATUS
SmbBattQueryStatus (
IN PVOID Context,
IN ULONG BatteryTag,
OUT PBATTERY_STATUS BatteryStatus
)
/*++
Routine Description:
Called by the class driver to retrieve the batteries current status
N.B. the battery class driver will serialize all requests it issues to
the miniport for a given battery. However, this miniport implements
a lock on the battery device as it needs to serialize to the smb
battery selector device as well.
Arguments:
Context - Miniport context value for battery
BatteryTag - Tag of current battery
BatteryStatus - Pointer to structure to return the current battery status
Return Value:
Success if there is a battery currently installed, else no such device.
--*/
{
PSMB_BATT SmbBatt;
NTSTATUS status;
BOOLEAN IoCheck;
LONG Current;
ULONG oldSelectorState = 0;
PAGED_CODE();
BattPrint(BAT_TRACE, ("SmbBattQueryStatus: ENTERING\n"));
if (BatteryTag == BATTERY_TAG_INVALID) {
return STATUS_NO_SUCH_DEVICE;
}
status = STATUS_SUCCESS;
//
// Get device lock and make sure the selector is set up to talk to us.
// Since multiple people may be doing this, always lock the selector
// first followed by the battery.
//
SmbBatt = (PSMB_BATT) Context;
SmbBattLockSelector (SmbBatt->Selector);
SmbBattLockDevice (SmbBatt);
status = SmbBattSetSelectorComm (SmbBatt, &oldSelectorState);
if (!NT_SUCCESS (status)) {
BattPrint(BAT_ERROR, ("SmbBattQueryStatus: can't set selector communications path\n"));
} else {
do {
if (BatteryTag != SmbBatt->Info.Tag) {
status = STATUS_NO_SUCH_DEVICE;
break;
}
SmbBattRW(SmbBatt, BAT_VOLTAGE, &BatteryStatus->Voltage);
BatteryStatus->Voltage *= SmbBatt->Info.VoltageScale;
SmbBattRW(SmbBatt, BAT_REMAINING_CAPACITY, &BatteryStatus->Capacity);
BatteryStatus->Capacity *= SmbBatt->Info.PowerScale;
SmbBattRSW(SmbBatt, BAT_CURRENT, &Current);
Current *= SmbBatt->Info.CurrentScale;
BattPrint(BAT_DATA,
("SmbBattQueryStatus: (%01x)\n"
"------- Remaining Capacity - %x\n"
"------- Voltage - %x\n"
"------- Current - %x\n",
SmbBatt->SelectorBitPosition,
BatteryStatus->Capacity,
BatteryStatus->Voltage,
Current)
);
BatteryStatus->Rate = (Current * ((LONG)BatteryStatus->Voltage))/1000;
//
// Check to see if we are currently connected to AC.
//
status = SmbBattGetPowerState (SmbBatt, &BatteryStatus->PowerState, &Current);
if (!NT_SUCCESS (status)) {
BatteryStatus->PowerState = 0;
}
//
// Re-verify static info in case there's been an IO error
//
IoCheck = SmbBattVerifyStaticInfo (SmbBatt, BatteryTag);
} while (IoCheck);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -