📄 smbmisc.c
字号:
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
smbmisc.c
Abstract:
SMBus handler functions
Author:
Ken Reneris
Environment:
Notes:
Revision History:
Chris Windle 1/27/98 Bug Fixes
--*/
#include "smbbattp.h"
//
// Make the SelectorBit table pageable
//
//#ifdef ALLOC_DATA_PRAGMA
//#pragma data_seg("PAGE")
//#endif
//
// Lookup table for the battery that corresponds to bit positions and
// whether or not reverse logic is being used (to indicate charging or
// discharging).
//
// NOTE: To support Simultaneous Charging and Powering, this table
// has been modified to account for multiple bits. Also, it can't be
// used for battery index lookup since it assumes one bit set maximum.
// Instead, use special indexes for multiple batteries as follows:
//
// 1st Battery = Index & 0x03
// 2nd Battery = (Index >> 2) & 0x03 (Battery A not allowed)
// 3rd Battery = (Index >> 4) & 0x03 (Battery A not allowed)
//
// In < 4 battery systems the Battery D bit can be used to determine
// the nibbles that are inverted, and it allows the following combinations:
//
// Battery A & B
// Battery A & C
// Battery B & C
// Battery A, B, & C
//
const SELECTOR_STATE_LOOKUP SelectorBits [16] = {
{BATTERY_NONE, FALSE}, // Bit Pattern: 0000
{BATTERY_A, FALSE}, // 0001
{BATTERY_B, FALSE}, // 0010
{MULTIBATT_AB, FALSE}, // 0011
{BATTERY_C, FALSE}, // 0100
{MULTIBATT_AC, FALSE}, // 0101
{MULTIBATT_BC, FALSE}, // 0110
{MULTIBATT_ABC, FALSE}, // 0111
{MULTIBATT_ABC, TRUE}, // 1000
{MULTIBATT_BC, TRUE}, // 1001
{MULTIBATT_AC, TRUE}, // 1010
{BATTERY_C, TRUE}, // 1011
{MULTIBATT_AB, TRUE}, // 1100
{BATTERY_B, TRUE}, // 1101
{BATTERY_A, TRUE}, // 1110
{BATTERY_NONE, TRUE} // 1111
};
//
// Note: For 4-Battery Systems to support Simultaneous Capability
// properly, the following two assumptions must be made:
// - Battery D can never be used simultaneously.
// - Three batteries can not be used simultaneously.
//
// This allows for only the following possible battery combinations:
//
// Battery A & B
// Battery A & C
// Battery B & C
//
// The following table is used for 4-battery lookup
//
const SELECTOR_STATE_LOOKUP SelectorBits4 [16] = {
{BATTERY_NONE, FALSE}, // Bit Pattern: 0000
{BATTERY_A, FALSE}, // 0001
{BATTERY_B, FALSE}, // 0010
{MULTIBATT_AB, FALSE}, // 0011
{BATTERY_C, FALSE}, // 0100
{MULTIBATT_AC, FALSE}, // 0101
{MULTIBATT_BC, FALSE}, // 0110
{BATTERY_D, TRUE}, // 0111
{BATTERY_D, FALSE}, // 1000
{MULTIBATT_BC, TRUE}, // 1001
{MULTIBATT_AC, TRUE}, // 1010
{BATTERY_C, TRUE}, // 1011
{MULTIBATT_AB, TRUE}, // 1100
{BATTERY_B, TRUE}, // 1101
{BATTERY_A, TRUE}, // 1110
{BATTERY_NONE, TRUE} // 1111
};
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,SmbBattLockDevice)
#pragma alloc_text(PAGE,SmbBattUnlockDevice)
#pragma alloc_text(PAGE,SmbBattLockSelector)
#pragma alloc_text(PAGE,SmbBattUnlockSelector)
#pragma alloc_text(PAGE,SmbBattRequest)
#pragma alloc_text(PAGE,SmbBattRB)
#pragma alloc_text(PAGE,SmbBattRW)
#pragma alloc_text(PAGE,SmbBattRSW)
#pragma alloc_text(PAGE,SmbBattWW)
#pragma alloc_text(PAGE,SmbBattGenericRW)
#pragma alloc_text(PAGE,SmbBattGenericWW)
#pragma alloc_text(PAGE,SmbBattGenericRequest)
#pragma alloc_text(PAGE,SmbBattSetSelectorComm)
#pragma alloc_text(PAGE,SmbBattResetSelectorComm)
#if DEBUG
#pragma alloc_text(PAGE,SmbBattDirectDataAccess)
#endif
#pragma alloc_text(PAGE,SmbBattIndex)
#pragma alloc_text(PAGE,SmbBattReverseLogic)
#pragma alloc_text(PAGE,SmbBattAcquireGlobalLock)
#pragma alloc_text(PAGE,SmbBattReleaseGlobalLock)
#endif
VOID
SmbBattLockDevice (
IN PSMB_BATT SmbBatt
)
{
PAGED_CODE();
//
// Get device lock on the battery
//
ExAcquireFastMutex (&SmbBatt->NP->Mutex);
}
VOID
SmbBattUnlockDevice (
IN PSMB_BATT SmbBatt
)
{
PAGED_CODE();
//
// Release device lock on the battery
//
ExReleaseFastMutex (&SmbBatt->NP->Mutex);
}
VOID
SmbBattLockSelector (
IN PBATTERY_SELECTOR Selector
)
{
PAGED_CODE();
//
// Get device lock on the selector
//
if (Selector) {
ExAcquireFastMutex (&Selector->Mutex);
}
}
VOID
SmbBattUnlockSelector (
IN PBATTERY_SELECTOR Selector
)
{
PAGED_CODE();
//
// Release device lock on the selector
//
if (Selector) {
ExReleaseFastMutex (&Selector->Mutex);
}
}
NTSTATUS
SmbBattSynchronousRequest (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
Completion function for synchronous IRPs sent to this driver.
Context is the event to set
--*/
{
PKEVENT Event;
Event = (PKEVENT) Context;
KeSetEvent (Event, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
SmbBattRequest (
IN PSMB_BATT SmbBatt,
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 (!SmbBatt->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, ("SmbBattRequest: SmbHc hasn't been opened yet \n"));
SmbReq->Status = SMB_UNKNOWN_FAILURE;
return ;
}
Irp = IoAllocateIrp (SmbBatt->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 aquire and not release etc.
//
if (useLock) {
if (!NT_SUCCESS (SmbBattAcquireGlobalLock (SmbBatt->SmbHcFdo, &globalLock))) {
useLock = FALSE;
}
}
IoCallDriver (SmbBatt->SmbHcFdo, Irp);
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
IoFreeIrp (Irp);
if (useLock) {
SmbBattReleaseGlobalLock (SmbBatt->SmbHcFdo, &globalLock);
}
//
// Check result code
//
if (!NT_SUCCESS(Status)) {
BattPrint(BAT_ERROR, ("SmbBattRequest: error in SmbHc request - %x\n", Status));
SmbReq->Status = SMB_UNKNOWN_FAILURE;
}
}
VOID
SmbBattRB(
IN PSMB_BATT SmbBatt,
IN UCHAR SmbCmd,
OUT PUCHAR Buffer,
OUT PUCHAR BufferLength
)
// function to read-block from the battery
{
SMB_REQUEST SmbReq;
PAGED_CODE();
SmbReq.Protocol = SMB_READ_BLOCK;
SmbReq.Address = SMB_BATTERY_ADDRESS;
SmbReq.Command = SmbCmd;
SmbBattRequest (SmbBatt, &SmbReq);
if (SmbReq.Status == SMB_STATUS_OK) {
ASSERT (SmbReq.BlockLength < SMB_MAX_DATA_SIZE);
memcpy (Buffer, SmbReq.Data, SmbReq.BlockLength);
*BufferLength = SmbReq.BlockLength;
} else {
// some sort of failure, check tag data for cache validity
SmbBatt->Info.Valid &= ~VALID_TAG_DATA;
}
}
VOID
SmbBattRW(
IN PSMB_BATT SmbBatt,
IN UCHAR SmbCmd,
OUT PULONG Result
)
// function to read-word from the battery
// N.B. word is returned as a ULONG
{
SMB_REQUEST SmbReq;
PAGED_CODE();
SmbReq.Protocol = SMB_READ_WORD;
SmbReq.Address = SMB_BATTERY_ADDRESS;
SmbReq.Command = SmbCmd;
SmbBattRequest (SmbBatt, &SmbReq);
if (SmbReq.Status != SMB_STATUS_OK) {
// some sort of failure, check tag data for cache validity
SmbBatt->Info.Valid &= ~VALID_TAG_DATA;
}
*Result = SmbReq.Data[0] | SmbReq.Data[1] << WORD_MSB_SHIFT;
BattPrint(BAT_IO, ("SmbBattRW: Command: %02x == %04x\n", SmbCmd, *Result));
}
VOID
SmbBattRSW(
IN PSMB_BATT SmbBatt,
IN UCHAR SmbCmd,
OUT PLONG Result
)
// function to read-signed-word from the battery
// N.B. word is returned as a LONG
{
ULONG i;
PAGED_CODE();
SmbBattRW(SmbBatt, SmbCmd, &i);
*Result = ((SHORT) i);
}
VOID
SmbBattWW(
IN PSMB_BATT SmbBatt,
IN UCHAR SmbCmd,
IN ULONG Data
)
// function to write-word to the battery
{
SMB_REQUEST SmbReq;
PAGED_CODE();
SmbReq.Protocol = SMB_WRITE_WORD;
SmbReq.Address = SMB_BATTERY_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, ("SmbBattWW: Command: %02x = %04x\n", SmbCmd, Data));
SmbBattRequest (SmbBatt, &SmbReq);
if (SmbReq.Status != SMB_STATUS_OK) {
// some sort of failure, check tag data for cache validity
SmbBatt->Info.Valid &= ~VALID_TAG_DATA;
}
}
UCHAR
SmbBattGenericRW(
IN PDEVICE_OBJECT SmbHcFdo,
IN UCHAR Address,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -