📄 smbbatt.c
字号:
if (NT_SUCCESS (status)) {
//
// Set batteries current power state & capacity
//
SmbBatt->Info.PowerState = BatteryStatus->PowerState;
SmbBatt->Info.Capacity = BatteryStatus->Capacity;
//
// Done, unlock the device and reset the selector state
//
status = SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
if (!NT_SUCCESS (status)) {
BattPrint(BAT_ERROR, ("SmbBattQueryStatus: can't reset selector communications path\n"));
}
} else {
//
// Ignore the return value from ResetSelectorComm because we already
// have an error here.
//
SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
}
SmbBattUnlockDevice (SmbBatt);
SmbBattUnlockSelector (SmbBatt->Selector);
BattPrint(BAT_TRACE, ("SmbBattQueryStatus: EXITING\n"));
return status;
}
NTSTATUS
SmbBattSetStatusNotify (
IN PVOID Context,
IN ULONG BatteryTag,
IN PBATTERY_NOTIFY Notify
)
/*++
Routine Description:
Called by the class driver to set the batteries current notification
setting. When the battery trips the notification, one call to
BatteryClassStatusNotify is issued. If an error is returned, the
class driver will poll the battery status - primarily for capacity
changes. Which is to say the miniport should still issue BatteryClass-
StatusNotify whenever the power state changes.
The class driver will always set the notification level it needs
after each call to BatteryClassStatusNotify.
Arguments:
Context - Miniport context value for battery
BatteryTag - Tag of current battery
BatteryNotify - The notification setting
Return Value:
Status
--*/
{
PSMB_BATT SmbBatt;
NTSTATUS status;
BOOLEAN UpdateAlarm;
ULONG Target, NewAlarm;
LONG DeltaAdjustment, Attempt, i;
ULONG oldSelectorState;
PAGED_CODE();
BattPrint(BAT_TRACE, ("SmbBattSetStatusNotify: ENTERING\n"));
if (BatteryTag == BATTERY_TAG_INVALID) {
return STATUS_NO_SUCH_DEVICE;
}
if ((Notify->HighCapacity == BATTERY_UNKNOWN_CAPACITY) ||
(Notify->LowCapacity == BATTERY_UNKNOWN_CAPACITY)) {
BattPrint(BAT_WARN, ("SmbBattSetStatusNotify: Failing because of BATTERY_UNKNOWN_CAPACITY.\n"));
return STATUS_NOT_SUPPORTED;
}
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;
BattPrint(BAT_DATA, ("SmbBattSetStatusNotify: (%01x): Called with LowCapacity = %08x\n",
SmbBatt->SelectorBitPosition, Notify->LowCapacity));
SmbBattLockSelector (SmbBatt->Selector);
SmbBattLockDevice (SmbBatt);
status = SmbBattSetSelectorComm (SmbBatt, &oldSelectorState);
if (!NT_SUCCESS (status)) {
BattPrint(BAT_ERROR, ("SmbBattSetStatusNotify: can't set selector communications path\n"));
} else {
// Target (10*PS*mWh) = Lowcapacity (mWh) / 10*PS (1/(10*PS))
Target = Notify->LowCapacity / SmbBatt->Info.PowerScale;
DeltaAdjustment = 0;
BattPrint(BAT_DATA, ("SmbBattSetStatusNotify: (%01x): Last set to: %08x\n",
SmbBatt->SelectorBitPosition, SmbBatt->AlarmLow.Setting));
//
// Some batteries are messed up and won't just take an alarm setting. Fortunately,
// the error is off in some linear fashion, so this code attempts to hone in on the
// adjustment needed to get the proper setting, along with an "allowable fudge value",
// since sometimes the desired setting can never be obtained.
//
for (; ;) {
if (BatteryTag != SmbBatt->Info.Tag) {
status = STATUS_NO_SUCH_DEVICE;
break;
}
//
// If the status is charging we can't detect. Let the OS poll
//
if (SmbBatt->Info.PowerState & (BATTERY_CHARGING | BATTERY_POWER_ON_LINE)) {
status = STATUS_NOT_SUPPORTED;
break;
}
//
// If the current capacity is below the target, fire an alarm and we're done
//
if (SmbBatt->Info.Capacity < Target) {
BatteryClassStatusNotify (SmbBatt->NP->Class);
break;
}
//
// If the target setting is the Skip value then there was an error attempting
// this value last time.
//
if (Target == SmbBatt->AlarmLow.Skip) {
status = STATUS_NOT_SUPPORTED;
break;
}
//
// If the current setting is above the current capacity then we need to
// program the alarm
//
UpdateAlarm = FALSE;
if (Target < SmbBatt->AlarmLow.Setting) {
UpdateAlarm = TRUE;
}
//
// If the target alarm is above the current setting, and the current setting
// is off by more then AllowedFudge then it needs updated
//
if (Target > SmbBatt->AlarmLow.Setting &&
Target - SmbBatt->AlarmLow.Setting > (ULONG) SmbBatt->AlarmLow.AllowedFudge) {
UpdateAlarm = TRUE;
}
//
// If alarm doesn't need updated, done
//
if (!UpdateAlarm) {
BattPrint(BAT_DATA, ("SmbBattSetStatusNotify: (%01x) NOT Updating Alarm.\n", SmbBatt->SelectorBitPosition));
break;
}
BattPrint(BAT_DATA, ("SmbBattSetStatusNotify: (%01x) Updating Alarm.\n", SmbBatt->SelectorBitPosition));
//
// If this is not the first time, then delta is not good enough. Let's start
// adjusting it
//
if (DeltaAdjustment) {
//
// If delta is positive subtract off 1/2 of fudge
//
if (DeltaAdjustment > 0) {
DeltaAdjustment -= SmbBatt->AlarmLow.AllowedFudge / 2 + (SmbBatt->AlarmLow.AllowedFudge & 1);
// too much - don't handle it
if (DeltaAdjustment > 50) {
status = STATUS_NOT_SUPPORTED;
break;
}
} else {
// too much - don't handle it
if (DeltaAdjustment < -50) {
status = STATUS_NOT_SUPPORTED;
break;
}
}
SmbBatt->AlarmLow.Delta += DeltaAdjustment;
}
//
// If attempt is less then 1, then we can't set it
//
Attempt = Target + SmbBatt->AlarmLow.Delta;
if (Attempt < 1) {
// battery class driver needs to poll for it
status = STATUS_NOT_SUPPORTED;
break;
}
//
// Perform IOs to update & read back the alarm. Use VerifyStaticInfo after
// IOs in case there's an IO error and the state is lost.
//
SmbBattWW(SmbBatt, BAT_REMAINING_CAPACITY_ALARM, Attempt);
// verify in case there was an IO error
//if (SmbBattVerifyStaticInfo (SmbBatt, BatteryTag)) {
// DeltaAdjustment = 0;
// continue;
//}
SmbBattRW(SmbBatt, BAT_REMAINING_CAPACITY_ALARM, &NewAlarm);
// verify in case there was an IO error
//if (SmbBattVerifyStaticInfo (SmbBatt, BatteryTag)) {
// DeltaAdjustment = 0;
// continue;
//}
BattPrint(BAT_DATA,
("SmbBattSetStatusNotify: (%01x) Want %X, Had %X, Got %X, CurrentCap %X, Delta %d, Fudge %d\n",
SmbBatt->SelectorBitPosition,
Target,
SmbBatt->AlarmLow.Setting,
NewAlarm,
SmbBatt->Info.Capacity / SmbBatt->Info.PowerScale,
SmbBatt->AlarmLow.Delta,
SmbBatt->AlarmLow.AllowedFudge
));
//
// If DeltaAdjustment was applied to Delta but the setting
// moved by more then DeltaAdjustment, then increase the
// allowed fudge.
//
if (DeltaAdjustment) {
i = NewAlarm - SmbBatt->AlarmLow.Setting - DeltaAdjustment;
if (DeltaAdjustment < 0) {
DeltaAdjustment = -DeltaAdjustment;
i = -i;
}
if (i > SmbBatt->AlarmLow.AllowedFudge) {
SmbBatt->AlarmLow.AllowedFudge = i;
BattPrint(BAT_DATA, ("SmbBattSetStatusNotify: Fudge increased to %x\n", SmbBatt->AlarmLow.AllowedFudge));
}
}
//
// Current setting
//
SmbBatt->AlarmLow.Setting = NewAlarm;
//
// Compute next delta adjustment
//
DeltaAdjustment = Target - SmbBatt->AlarmLow.Setting;
}
//
// If there was an attempt to set the alarm but it failed, set the
// skip value so we don't keep trying to set an alarm for this value
// which isn't working
//
if (!NT_SUCCESS(status) && DeltaAdjustment) {
SmbBatt->AlarmLow.Skip = Target;
}
}
//
// Done, unlock the device and reset the selector state
//
if (NT_SUCCESS (status)) {
status = SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
if (!NT_SUCCESS (status)) {
BattPrint(BAT_ERROR, ("SmbBattSetStatusNotify: can't reset selector communications path\n"));
}
} else {
//
// Ignore the return value from ResetSelectorComm because we already
// have an error here.
//
SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
}
SmbBattUnlockDevice (SmbBatt);
SmbBattUnlockSelector (SmbBatt->Selector);
BattPrint(BAT_TRACE, ("SmbBattSetStatusNotify: EXITING\n"));
return status;
}
NTSTATUS
SmbBattDisableStatusNotify (
IN PVOID Context
)
/*++
Routine Description:
Called by the class driver to disable the notification setting
for the battery supplied by Context. Note, to disable a setting
does not require the battery tag. Any notification is to be
masked off until a subsequent call to SmbBattSetStatusNotify.
Arguments:
Context - Miniport context value for battery
Return Value:
Status
--*/
{
NTSTATUS status;
PSMB_BATT SmbBatt;
ULONG oldSelectorState;
PAGED_CODE();
BattPrint(BAT_TRACE, ("SmbBattDisableStatusNotify: ENTERING\n"));
SmbBatt = (PSMB_BATT) Context;
SmbBattLockSelector (SmbBatt->Selector);
SmbBattLockDevice (SmbBatt);
status = SmbBattSetSelectorComm (SmbBatt, &oldSelectorState);
if (!NT_SUCCESS (status)) {
BattPrint(BAT_ERROR, ("SmbBattDisableStatusNotify: can't set selector communications path\n"));
} else {
SmbBatt->AlarmLow.Setting = 0;
SmbBattWW(SmbBatt, BAT_REMAINING_CAPACITY_ALARM, 0);
//
// Done, reset the selector state.
//
status = SmbBattResetSelectorComm (SmbBatt, oldSelectorState);
if (!NT_SUCCESS (status)) {
BattPrint(BAT_ERROR, ("SmbBattDisableStatusNotify: can't reset selector communications path\n"));
}
}
//
// Done, unlock the device
//
SmbBattUnlockDevice (SmbBatt);
SmbBattUnlockSelector (SmbBatt->Selector);
BattPrint(BAT_TRACE, ("SmbBattDisableStatusNotify: EXITING\n"));
return STATUS_SUCCESS;
}
BOOLEAN
SmbBattVerifyStaticInfo (
IN PSMB_BATT SmbBatt,
IN ULONG BatteryTag
)
/*++
Routine Description:
Reads any non-valid cached battery info and set Info.Valid accordingly.
Performs a serial number check after reading in battery info in order
to detect verify the data is from the same battery. If the value does
not match what is expect, the cached info is reset and the function
iterates until a consistent snapshot is obtained.
Arguments:
SmbBatt - Battery to read
BatteryTag - Tag of battery as expected by the caller
Return Value:
Returns a boolean to indicate to the caller that IO was performed.
This allows the caller to iterate on changes it may be ma
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -