📄 smbmisc.c
字号:
IN UCHAR SmbCmd,
OUT PULONG Result
)
// function to read-word from the SMB device (charger or selector)
// N.B. word is returned as a ULONG
{
SMB_REQUEST SmbReq;
PAGED_CODE();
SmbReq.Protocol = SMB_READ_WORD;
SmbReq.Address = Address;
SmbReq.Command = SmbCmd;
SmbBattGenericRequest (SmbHcFdo, &SmbReq);
*Result = SmbReq.Data[0] | (SmbReq.Data[1] << WORD_MSB_SHIFT);
BattPrint(BAT_IO, ("SmbBattGenericRW: Address: %02x:%02x == %04x\n", Address, SmbCmd, *Result));
return SmbReq.Status;
}
UCHAR
SmbBattGenericWW(
IN PDEVICE_OBJECT SmbHcFdo,
IN UCHAR Address,
IN UCHAR SmbCmd,
IN ULONG Data
)
// function to write-word to SMB device (charger or selector)
{
SMB_REQUEST SmbReq;
PAGED_CODE();
SmbReq.Protocol = SMB_WRITE_WORD;
SmbReq.Address = Address;
SmbReq.Command = SmbCmd;
SmbReq.Data[0] = (UCHAR) (Data & WORD_LSB_MASK);
SmbReq.Data[1] = (UCHAR) (Data >> WORD_MSB_SHIFT) & WORD_LSB_MASK;
BattPrint(BAT_IO, ("SmbBattGenericWW: Address: %02x:%02x = %04x\n", Address, SmbCmd, Data));
SmbBattGenericRequest (SmbHcFdo, &SmbReq);
return SmbReq.Status;
}
VOID
SmbBattGenericRequest (
IN PDEVICE_OBJECT SmbHcFdo,
IN PSMB_REQUEST SmbReq
)
// function to issue SMBus request
{
KEVENT Event;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
NTSTATUS Status;
BOOLEAN useLock = SmbBattUseGlobalLock;
ACPI_MANIPULATE_GLOBAL_LOCK_BUFFER globalLock;
PAGED_CODE();
//
// Build Io Control for SMB bus driver for this request
//
KeInitializeEvent (&Event, NotificationEvent, FALSE);
if (!SmbHcFdo) {
//
// The SMB host controller either hasn't been opened yet (in start device) or
// there was an error opening it and we did not get deleted somehow.
//
BattPrint(BAT_ERROR, ("SmbBattGenericRequest: SmbHc hasn't been opened yet \n"));
SmbReq->Status = SMB_UNKNOWN_FAILURE;
return ;
}
Irp = IoAllocateIrp (SmbHcFdo->StackSize, FALSE);
if (!Irp) {
SmbReq->Status = SMB_UNKNOWN_FAILURE;
return ;
}
IrpSp = IoGetNextIrpStackLocation(Irp);
IrpSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
IrpSp->Parameters.DeviceIoControl.IoControlCode = SMB_BUS_REQUEST;
IrpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(SMB_REQUEST);
IrpSp->Parameters.DeviceIoControl.Type3InputBuffer = SmbReq;
IoSetCompletionRoutine (Irp, SmbBattSynchronousRequest, &Event, TRUE, TRUE, TRUE);
//
// Issue it
//
//
// Note: uselock is a cached value of the global variable, so in case the
// value changes, we won't acquire and not release etc.
//
if (useLock) {
if (!NT_SUCCESS (SmbBattAcquireGlobalLock (SmbHcFdo, &globalLock))) {
useLock = FALSE;
}
}
IoCallDriver (SmbHcFdo, Irp);
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
IoFreeIrp (Irp);
if (useLock) {
SmbBattReleaseGlobalLock (SmbHcFdo, &globalLock);
}
//
// Check result code
//
if (!NT_SUCCESS(Status)) {
BattPrint(BAT_ERROR, ("SmbBattGenericRequest: error in SmbHc request - %x\n", Status));
SmbReq->Status = SMB_UNKNOWN_FAILURE;
}
}
NTSTATUS
SmbBattSetSelectorComm (
IN PSMB_BATT SmbBatt,
OUT PULONG OldSelectorState
)
/*++
Routine Description:
This routine sets the communication path through the selector to the calling
battery. It returns the original selector state in the variable provided.
NOTE: It is assumed that the caller already has acquired the device lock on the
selector before calling us.
NOTE: This function should always be called in a pair with SmbBattResetSelectorComm
Arguments:
SmbBatt - Nonpaged extension for current battery
OldSelectorState - Original selector state at start of this function
Return Value:
NTSTATUS
--*/
{
PBATTERY_SELECTOR selector;
UCHAR smbStatus;
ULONG requestData;
PAGED_CODE();
BattPrint(BAT_TRACE, ("SmbBattSetSelectorComm: ENTERING\n"));
//
// We only need to do this if there is a selector in the system.
//
if (SmbBatt->SelectorPresent) {
selector = SmbBatt->Selector;
*OldSelectorState = selector->SelectorState;
//
// If the battery isn't present, fail the request.
//
if (!(selector->SelectorState & SmbBatt->SelectorBitPosition)) {
return STATUS_NO_SUCH_DEVICE;
}
//
// See if we are already set up to talk with the requesting battery.
// We will check against the cached information in the selector struct.
//
if (selector->SelectorState & (SmbBatt->SelectorBitPosition << SELECTOR_SHIFT_COM)) {
return STATUS_SUCCESS;
}
//
// Build the data word to change the selector communications. This will
// look like the following:
//
// PRESENT field 0xf we don't want to change anything here
// CHARGE field 0xf we don't want to change anything here
// POWER BY field 0xf we don't want to change anything here
// SMB field 0x_ the bit set according to the battery number
//
requestData = (SmbBatt->SelectorBitPosition << SELECTOR_SHIFT_COM) | SELECTOR_SET_COM_MASK;
smbStatus = SmbBattGenericWW (
SmbBatt->SmbHcFdo,
selector->SelectorAddress,
selector->SelectorStateCommand,
requestData
);
if (smbStatus != SMB_STATUS_OK) {
BattPrint (BAT_ERROR, ("SmbBattSetSelectorComm: couldn't write selector state - %x\n", smbStatus));
return STATUS_UNSUCCESSFUL;
} else {
selector->SelectorState |= SELECTOR_STATE_SMB_MASK;
selector->SelectorState &= requestData;
BattPrint (BAT_IO, ("SmbBattSetSelectorComm: state after write - %x\n", selector->SelectorState));
}
} // if (subsystemExt->SelectorPresent)
BattPrint(BAT_TRACE, ("SmbBattSetSelectorComm: EXITING\n"));
return STATUS_SUCCESS;
}
NTSTATUS
SmbBattResetSelectorComm (
IN PSMB_BATT SmbBatt,
IN ULONG OldSelectorState
)
/*++
Routine Description:
This routine resets the communication path through the selector to the its
original state. It returns the original selector state in the variable provided.
NOTE: It is assumed that the caller already has acquired the device lock on the
selector before calling us.
NOTE: This function should always be called in a pair with SmbBattSetSelectorComm
Arguments:
SmbBatt - Nonpaged extension for current battery
OldSelectorState - Original selector state to be restored
Return Value:
NTSTATUS
--*/
{
PBATTERY_SELECTOR selector;
UCHAR smbStatus;
ULONG tmpState;
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
BattPrint(BAT_TRACE, ("SmbBattResetSelectorComm: ENTERING\n"));
//
// We only need to do this if there is a selector in the system.
//
if (SmbBatt->SelectorPresent) {
selector = SmbBatt->Selector;
//
// See if we were already set up to talk with the requesting battery.
// We will check against the cached information in the selector struct.
//
if ((OldSelectorState & selector->SelectorState) & SELECTOR_STATE_SMB_MASK) {
return STATUS_SUCCESS;
}
//
// Change the selector communications back. The SMB field is the only
// that we will write.
//
tmpState = SELECTOR_SET_COM_MASK;
tmpState |= OldSelectorState & SELECTOR_STATE_SMB_MASK;
smbStatus = SmbBattGenericWW (
SmbBatt->SmbHcFdo,
selector->SelectorAddress,
selector->SelectorStateCommand,
tmpState
);
if (smbStatus != SMB_STATUS_OK) {
BattPrint (
BAT_ERROR,
("SmbBattResetSelectorComm: couldn't write selector state - %x\n",
smbStatus)
);
status = STATUS_UNSUCCESSFUL;
} else {
selector->SelectorState |= SELECTOR_STATE_SMB_MASK;
selector->SelectorState &= tmpState;
BattPrint (
BAT_IO,
("SmbBattResetSelectorComm: state after write - %x\n",
selector->SelectorState)
);
}
} // if (subsystemExt->SelectorPresent)
BattPrint(BAT_TRACE, ("SmbBattResetSelectorComm: EXITING\n"));
return status;
}
#if DEBUG
NTSTATUS
SmbBattDirectDataAccess (
IN PSMB_NP_BATT DeviceExtension,
IN PSMBBATT_DATA_STRUCT IoBuffer,
IN ULONG InputLen,
IN ULONG OutputLen
)
/*++
Routine Description:
This routine is used to handle IOCTLs acessing the SMBBatt commands directly.
Arguments:
DeviceExtension - Device extension for the smart battery subsystem
IoBuffer - Buffer that contains the input structure and will
contain the results of the read.
Return Value:
NTSTATUS
--*/
{
PSMB_BATT_SUBSYSTEM SubsystemExt;
PSMB_BATT SmbBatt;
UCHAR address;
UCHAR command;
UCHAR smbStatus;
ULONG oldSelectorState;
ULONG ReturnBufferLength;
UCHAR strLength;
UCHAR strBuffer[SMB_MAX_DATA_SIZE+1]; // +1 extra char to hold NULL
UCHAR strBuffer2[SMB_MAX_DATA_SIZE+1];
UNICODE_STRING unicodeString;
ANSI_STRING ansiString;
UCHAR tempFlags;
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
if (InputLen < sizeof(SMBBATT_DATA_STRUCT)) {
return STATUS_INVALID_BUFFER_SIZE;
}
if ((DeviceExtension->SmbBattFdoType == SmbTypeBattery)
&& (IoBuffer->Address == SMB_BATTERY_ADDRESS)) {
// This is a battery data request
SmbBatt = DeviceExtension->Batt;
SmbBattLockSelector (SmbBatt->Selector);
SmbBattLockDevice (SmbBatt);
status = SmbBattSetSelectorComm (SmbBatt, &oldSelectorState);
if (NT_SUCCESS (status)) {
if ((InputLen >= sizeof(SMBBATT_DATA_STRUCT)) && (OutputLen == 0)) {
// This is a write command
status = STATUS_NOT_IMPLEMENTED;
} else if ((InputLen == sizeof(SMBBATT_DATA_STRUCT)) && (OutputLen > 0)){
// This is a Read command
if ((IoBuffer->Command >= BAT_REMAINING_CAPACITY_ALARM) &&
(IoBuffer->Command <= BAT_SERIAL_NUMBER)) {
// ReadWord Commands
if (OutputLen == sizeof(SMBBATT_DATA_STRUCT)) {
tempFlags = SmbBatt->Info.Valid;
SmbBatt->Info.Valid |= VALID_TAG_DATA;
SmbBattRW(SmbBatt, IoBuffer->Command, &IoBuffer->Data.Ulong);
if (SmbBatt->Info.Valid & VALID_TAG_DATA) {
ReturnBufferLength = sizeof(ULONG);
} else {
status = STATUS_DATA_ERROR;
}
SmbBatt->Info.Valid = tempFlags;
} else {
status = STATUS_INVALID_BUFFER_SIZE;
}
} else if ((IoBuffer->Command >= BAT_MANUFACTURER_NAME) &&
(IoBuffer->Command <= BAT_MANUFACTURER_DATA)) {
// ReadBlock Commands
if (OutputLen == (SMBBATT_DATA_STRUCT_SIZE)+(SMB_MAX_DATA_SIZE*2)) {
memset (&IoBuffer->Data.Block[0], 0, (SMB_MAX_DATA_SIZE*2));
unicodeString.Buffer = &IoBuffer->Data.Block[0];
unicodeString.MaximumLength = SMB_MAX_DATA_SIZE*2;
unicodeString.Length = 0;
memset (strBuffer, 0, sizeof(strBuffer));
memset (strBuffer2, 0, sizeof(strBuffer2));
do {
SmbBattRB (
SmbBatt,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -