windows-nt/Source/XPSP1/NT/base/busdrv/acpi/smbus/smbali/smbali.c
2020-09-26 16:20:57 +08:00

1070 lines
28 KiB
C

/*++
Copyright (c) 2000 Microsoft Corporation
Module Name:
smbali.c
Abstract:
SMB Host Controller Driver for ALI chipset
Author:
Michael Hills
Environment:
Notes:
Revision History:
--*/
#include "smbalip.h"
#if DBG
ULONG SmbAliDebug = SMB_ERROR|SMB_ALARM;
ULONG DbgSuccess = 0;
ULONG DbgFailure = 0;
ULONG DbgAddrNotAck = 0;
ULONG DbgTimeOut = 0;
ULONG DbgOtherErr = 0;
#endif
LARGE_INTEGER SmbIoPollRate = {-20*MILLISECONDS, -1}; // 20 millisecond poll rate. Relative time, so has to be negative
ULONG SmbIoInitTimeOut = 15; // 15 IoPollRate intervals before timeout
ULONG SmbIoCompleteTimeOut = 20; // 20 IoPollRate intervals before timeout
NTSTATUS
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
This routine initializes the SMBus Host Controller Driver
Arguments:
DriverObject - Pointer to driver object created by system.
RegistryPath - Pointer to the Unicode name of the registry path
for this driver.
Return Value:
The function value is the final status from the initialization operation.
--*/
{
NTSTATUS status;
// DbgBreakPoint();
status = SmbClassInitializeDevice (
SMB_ALI_MAJOR_VERSION,
SMB_ALI_MINOR_VERSION,
DriverObject
);
DriverObject->DriverExtension->AddDevice = SmbAliAddDevice;
return status;
}
NTSTATUS
SmbAliInitializeMiniport (
IN PSMB_CLASS SmbClass,
IN PVOID MiniportExtension,
IN PVOID MiniportContext
)
/*++
Routine Description:
This routine Initializes miniport data, and sets up communication with
lower device objects.
Arguments:
DriverObject - Pointer to driver object created by system.
Pdo - Pointer to physical device object
Return Value:
STATUS_SUCCESS
STATUS_INSUFFICIENT_RESOURCES
--*/
{
PSMB_ALI_DATA AliData = (PSMB_ALI_DATA) MiniportExtension;
NTSTATUS status = STATUS_SUCCESS;
PIRP irp;
PIO_STACK_LOCATION irpSp;
KEVENT syncEvent;
AliData->IoState = SmbIoIdle;
//
// Fill in SmbClass info
//
SmbClass->StartIo = SmbAliStartIo;
SmbClass->ResetDevice = SmbAliResetDevice;
SmbClass->StopDevice = SmbAliStopDevice;
//
// Get Acpi Interfaces
//
//
// Allocate an IRP for below
//
irp = IoAllocateIrp (SmbClass->LowerDeviceObject->StackSize, FALSE);
if (!irp) {
SmbPrint((SMB_ERROR),
("SmbAliInitializeMiniport: Failed to allocate Irp\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
irpSp = IoGetNextIrpStackLocation(irp);
//
// Use QUERY_INTERFACE to get the address of the direct-call ACPI interfaces.
//
irpSp->MajorFunction = IRP_MJ_PNP;
irpSp->MinorFunction = IRP_MN_QUERY_INTERFACE;
irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
irpSp->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_ACPI_INTERFACE_STANDARD;
irpSp->Parameters.QueryInterface.Version = 1;
irpSp->Parameters.QueryInterface.Size = sizeof (AliData->AcpiInterfaces);
irpSp->Parameters.QueryInterface.Interface = (PINTERFACE) &AliData->AcpiInterfaces;
irpSp->Parameters.QueryInterface.InterfaceSpecificData = NULL;
//
// Initialize an event so this will be a syncronous call.
//
KeInitializeEvent(&syncEvent, SynchronizationEvent, FALSE);
IoSetCompletionRoutine (irp, SmbAliSyncronousIrpCompletion, &syncEvent, TRUE, TRUE, TRUE);
//
// Call ACPI
//
status = IoCallDriver (SmbClass->LowerDeviceObject, irp);
//
// Wait if necessary, then clean up.
//
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&syncEvent, Executive, KernelMode, FALSE, NULL);
status = irp->IoStatus.Status;
}
IoFreeIrp (irp);
if (!NT_SUCCESS(status)) {
SmbPrint(SMB_ERROR,
("SmbAliInitializeMiniport: Could not get ACPI driver interfaces, status = %x\n", status));
}
//
// Initiaize worker thread
//
AliData->WorkItem = IoAllocateWorkItem (SmbClass->LowerDeviceObject);
return status;
}
NTSTATUS
SmbAliAddDevice (
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT Pdo
)
/*++
Routine Description:
This routine calls SMBClassCreateFdo to create the FDO
Arguments:
DriverObject - Pointer to driver object created by system.
Pdo - Pointer to physical device object
Return Value:
STATUS_SUCCESS
STATUS_INSUFFICIENT_RESOURCES
--*/
{
NTSTATUS status;
PDEVICE_OBJECT fdo = NULL;
PAGED_CODE();
SmbPrint(SMB_TRACE, ("SmbAliAddDevice Entered with pdo %x\n", Pdo));
if (Pdo == NULL) {
//
// Have we been asked to do detection on our own?
// if so just return no more devices
//
SmbPrint(SMB_ERROR, ("SmbHcAddDevice - asked to do detection\n"));
return STATUS_NO_MORE_ENTRIES;
}
//
// Create and initialize the new functional device object
//
status = SmbClassCreateFdo(
DriverObject,
Pdo,
sizeof (SMB_ALI_DATA),
SmbAliInitializeMiniport,
NULL,
&fdo
);
if (!NT_SUCCESS(status) || fdo == NULL) {
SmbPrint(SMB_ERROR, ("SmbAliAddDevice - error creating Fdo. Status = %08x\n", status));
}
return status;
}
NTSTATUS
SmbAliResetDevice (
IN struct _SMB_CLASS* SmbClass,
IN PVOID SmbMiniport
)
{
PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
PCM_PARTIAL_RESOURCE_LIST partialResourceList;
PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDesc;
ULONG i;
PIO_STACK_LOCATION irpStack;
NTSTATUS status = STATUS_UNSUCCESSFUL;
PSMB_ALI_DATA AliData = (PSMB_ALI_DATA) SmbMiniport;
PAGED_CODE();
if (SmbClass->CurrentIrp == NULL) {
SmbPrint(SMB_ERROR, ("SmbAliResetDevice: Null CurrentIrp. Can't get Alloocated Resources.\n"));
return STATUS_NO_MORE_ENTRIES;
}
irpStack = IoGetCurrentIrpStackLocation(SmbClass->CurrentIrp);
if (irpStack->Parameters.StartDevice.AllocatedResources == NULL) {
SmbPrint(SMB_ERROR, ("SmbAliResetDevice: Null resource pointer\n"));
return STATUS_NO_MORE_ENTRIES;
}
if (irpStack->Parameters.StartDevice.AllocatedResources->Count <= 0 ) {
SmbPrint(SMB_ERROR, ("SmbAliResetDevice: Count <= 0\n"));
return status;
}
//
// Traverse the resource list
//
AliData->SmbBaseIo = NULL;
fullResourceDesc=&irpStack->Parameters.StartDevice.AllocatedResources->List[0];
partialResourceList = &fullResourceDesc->PartialResourceList;
partialResourceDesc = partialResourceList->PartialDescriptors;
for (i=0; i<partialResourceList->Count; i++, partialResourceDesc++) {
if (partialResourceDesc->Type == CmResourceTypePort) {
if (AliData->SmbBaseIo == NULL) {
AliData->SmbBaseIo = (PUCHAR)((ULONG_PTR)partialResourceDesc->u.Port.Start.LowPart);
if (partialResourceDesc->u.Port.Length != SMB_ALI_IO_RESOURCE_LENGTH) {
SmbPrint(SMB_ERROR, ("SmbAliResetDevice: Wrong Resource length = 0x%08x\n", partialResourceDesc->u.Port.Length));
DbgBreakPoint();
}
status = STATUS_SUCCESS;
} else {
SmbPrint(SMB_ERROR, ("SmbAliResetDevice: More than 1 IO resource. Resources = 0x%08x\n", irpStack->Parameters.StartDevice.AllocatedResources));
DbgBreakPoint();
}
}
}
if (!NT_SUCCESS (status)) {
SmbPrint(SMB_ERROR, ("SmbAliResetDevice: IO resource error. Resources = 0x%08x\n", irpStack->Parameters.StartDevice.AllocatedResources));
DbgBreakPoint();
}
SmbPrint(SMB_TRACE, ("SmbAliResetDevice: IO Address = 0x%08x\n", AliData->SmbBaseIo));
//
// Register for device notification
//
// But this device can't seem to notify so never mind for now
//status = AliData->AcpiInterfaces.RegisterForDeviceNotifications (
// AliData->AcpiInterfaces.Context,
// SmbAliNotifyHandler,
// AliData);
//
//if (!NT_SUCCESS(status)) {
// SmbPrint(SMB_ERROR, ("SmbAliResetDevice: Failed RegisterForDeviceNotification. 0x%08x\n", status));
//}
KeInitializeTimer (&AliData->InitTimer);
KeInitializeDpc (&AliData->InitDpc,
SmbAliInitTransactionDpc,
SmbClass);
AliData->InitWorker = IoAllocateWorkItem (SmbClass->DeviceObject);
KeInitializeTimer (&AliData->CompleteTimer);
KeInitializeDpc (&AliData->CompleteDpc,
SmbAliCompleteTransactionDpc,
SmbClass);
AliData->CompleteWorker = IoAllocateWorkItem (SmbClass->DeviceObject);
SmbAliStartDevicePolling (SmbClass);
return status;
}
NTSTATUS
SmbAliStopDevice (
IN struct _SMB_CLASS* SmbClass,
IN PSMB_ALI_DATA AliData
)
{
SmbAliStopDevicePolling (SmbClass);
AliData->SmbBaseIo = NULL;
return STATUS_SUCCESS;
}
VOID
SmbAliStartIo (
IN struct _SMB_CLASS* SmbClass,
IN PSMB_ALI_DATA AliData
)
{
SmbPrint (SMB_TRACE, ("SmbAliStartIo: \n"));
SmbPrint (SMB_IO_REQUEST, (" Prtcl = %02x Addr = %02x Cmd = %02x BlkLen = %02x Data[0] = %02x\n",
SmbClass->CurrentSmb->Protocol,
SmbClass->CurrentSmb->Address,
SmbClass->CurrentSmb->Command,
SmbClass->CurrentSmb->BlockLength,
SmbClass->CurrentSmb->Data[0]));
// KeSetTimer (&AliData->InitTimer,
// Smb100ns,
// &AliData->InitDpc);
AliData->InternalRetries = 0;
AliData->InitTimeOut = SmbIoInitTimeOut;
IoQueueWorkItem (AliData->InitWorker,
SmbAliInitTransactionWorker,
DelayedWorkQueue,
SmbClass);
}
VOID
SmbAliInitTransactionDpc (
IN struct _KDPC *Dpc,
IN struct _SMB_CLASS* SmbClass,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
{
PSMB_ALI_DATA AliData = (PSMB_ALI_DATA)(SmbClass->Miniport);
IoQueueWorkItem (AliData->InitWorker,
SmbAliInitTransactionWorker,
DelayedWorkQueue,
SmbClass);
}
VOID
SmbAliInitTransactionWorker (
IN PDEVICE_OBJECT DeviceObject,
IN struct _SMB_CLASS* SmbClass
)
{
PSMB_ALI_DATA AliData = (PSMB_ALI_DATA)(SmbClass->Miniport);
UCHAR address;
UCHAR protocol;
SmbPrint (SMB_TRACE, ("SmbAliInitTransaction: Entered \n"));
if (SmbClass->CurrentSmb->Protocol >= SMB_MAXIMUM_PROTOCOL) {
SmbClass->CurrentSmb->Status = SMB_UNSUPPORTED_PROTOCOL;
// REVIEW: Shouldn't this complete the request? jimmat
return;
}
if (SmbAliHostBusy(AliData)) {
if (AliData->InitTimeOut == 4) {
// Time out. Issue kill command. If that fixes it, good, otherwise
// issue bus timeout command next time.
SmbAliResetHost (AliData);
}
if (AliData->InitTimeOut == 0) {
// Time out. Issue Bus timeout and kill command to reset host.
SmbAliResetBus (AliData);
AliData->InitTimeOut = SmbIoInitTimeOut;
} else {
SmbPrint (SMB_TRACE, ("SmbAliInitTransaction: Waiting (%d) \n", AliData->InitTimeOut));
AliData->InitTimeOut--;
}
KeSetTimer (&AliData->InitTimer,
SmbIoPollRate,
&AliData->InitDpc);
return;
}
//
// Ready to go
//
// Set Address and read/write bit
address = SmbClass->CurrentSmb->Address << 1 | (SmbClass->CurrentSmb->Protocol & 1);
SmbPrint (SMB_IO, ("SmbAliInitTransaction: IO write DEV_ADDR = 0x%02x \n", address));
WRITE_PORT_UCHAR (DEV_ADDR_REG, address);
SMBDELAY;
// Set transaction type: Inserts bits 3-1 of protocol into bits 6-4 of SMB_TYP
// protocol = READ_PORT_UCHAR (SMB_TYP_REG);
// SmbPrint (SMB_IO, ("SmbAliInitTransaction: IO read SMB_TYP = 0x%02x \n", protocol));
protocol = /*(protocol & ~SMB_TYP_MASK) |*/
((SmbClass->CurrentSmb->Protocol << 3) & SMB_TYP_MASK);
SmbPrint (SMB_IO, ("SmbAliInitTransaction: IO write SMB_TYP = 0x%02x, Protocol = 0x%02x \n", protocol,SmbClass->CurrentSmb->Protocol));
WRITE_PORT_UCHAR (SMB_TYP_REG, protocol);
SMBDELAY;
// Set SMBus Device Command value
if (SmbClass->CurrentSmb->Protocol >= SMB_WRITE_BYTE) {
SmbPrint (SMB_IO, ("SmbAliInitTransaction: IO write SMB_CMD = 0x%02x \n", SmbClass->CurrentSmb->Command));
WRITE_PORT_UCHAR (SMB_CMD_REG, SmbClass->CurrentSmb->Command);
SMBDELAY;
}
switch (SmbClass->CurrentSmb->Protocol) {
case SMB_WRITE_WORD:
case SMB_PROCESS_CALL:
// Set Data
SmbPrint (SMB_IO, ("SmbAliInitTransaction: IO write DEV_DATA1 = 0x%02x \n", SmbClass->CurrentSmb->Data[1]));
WRITE_PORT_UCHAR (DEV_DATA1_REG, SmbClass->CurrentSmb->Data[1]);
SMBDELAY;
// Fall through to set low byte of word
case SMB_SEND_BYTE:
case SMB_WRITE_BYTE:
// Set Data
SmbPrint (SMB_IO, ("SmbAliInitTransaction: IO write DEV_DATA0 = 0x%02x \n", SmbClass->CurrentSmb->Data[0]));
WRITE_PORT_UCHAR (DEV_DATA0_REG, SmbClass->CurrentSmb->Data[0]);
SMBDELAY;
break;
case SMB_WRITE_BLOCK:
// BUGBUG: not yet implemented.
SmbPrint (SMB_ERROR, ("SmbAliInitTransaction: Write Block not implemented. press 'g' to write random data.\n"));
DbgBreakPoint();
break;
}
// Initiate Transaction
SmbPrint (SMB_IO, ("SmbAliInitTransaction: IO write STR_PORT = 0x%02x \n", STR_PORT_START));
WRITE_PORT_UCHAR (STR_PORT_REG, STR_PORT_START);
AliData->CompleteTimeOut = SmbIoCompleteTimeOut;
KeSetTimer (&AliData->CompleteTimer,
SmbIoPollRate,
&AliData->CompleteDpc);
}
VOID
SmbAliCompleteTransactionDpc (
IN struct _KDPC *Dpc,
IN struct _SMB_CLASS* SmbClass,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
{
PSMB_ALI_DATA AliData = (PSMB_ALI_DATA)(SmbClass->Miniport);
IoQueueWorkItem (AliData->CompleteWorker,
SmbAliCompleteTransactionWorker,
DelayedWorkQueue,
SmbClass);
}
VOID
SmbAliCompleteTransactionWorker (
IN PDEVICE_OBJECT DeviceObject,
IN struct _SMB_CLASS* SmbClass
)
{
PSMB_ALI_DATA AliData = (PSMB_ALI_DATA)(SmbClass->Miniport);
UCHAR i, smb_sts;
UCHAR smbStatus;
SmbPrint (SMB_TRACE, ("SmbAliCompleteTransactionWorker: Entered \n"));
smbStatus = SMB_STATUS_OK;
if (!SmbAliTransactionComplete(AliData, &smbStatus)) {
//
// Timeout
//
if (AliData->CompleteTimeOut == 0) {
SmbPrint (SMB_TRACE, ("SmbAliCompleteTransactionWorker: Transation timed out. Resetting host. \n"));
SmbAliResetHost (AliData);
smbStatus = SMB_TIMEOUT;
} else {
SmbPrint (SMB_TRACE, ("SmbAliCompleteTransactionWorker: Not complete. Waiting (%d)... \n", AliData->CompleteTimeOut));
AliData->CompleteTimeOut--;
KeSetTimer (&AliData->CompleteTimer,
SmbIoPollRate,
&AliData->CompleteDpc);
return;
}
}
if (smbStatus == SMB_STATUS_OK) {
//
// If transaction was successful, read data.
//
switch (SmbClass->CurrentSmb->Protocol) {
case SMB_READ_WORD:
case SMB_PROCESS_CALL:
// Read High byte
SmbClass->CurrentSmb->Data[1] = READ_PORT_UCHAR (DEV_DATA1_REG);
SMBDELAY;
SmbPrint (SMB_IO, ("SmbAliCompleteTransactionWorker: IO read DEV_DATA1 = 0x%02x \n", SmbClass->CurrentSmb->Data[1]));
// Fall through to set low byte of word
case SMB_RECEIVE_BYTE:
case SMB_READ_BYTE:
// Read Low Byte
SmbClass->CurrentSmb->Data[0] = READ_PORT_UCHAR (DEV_DATA0_REG);
SMBDELAY;
SmbPrint (SMB_IO, ("SmbAliCompleteTransactionWorker: IO read DEV_DATA0 = 0x%02x \n", SmbClass->CurrentSmb->Data[0]));
break;
case SMB_READ_BLOCK:
// Read Block Count
SmbClass->CurrentSmb->BlockLength = READ_PORT_UCHAR (DEV_DATA0_REG);
SMBDELAY;
SmbPrint (SMB_IO, ("SmbAliCompleteTransactionWorker: IO read DEV_DATA0 (block length)= 0x%02x \n", SmbClass->CurrentSmb->BlockLength));
if (SmbClass->CurrentSmb->BlockLength >= 32) {
DbgBreakPoint();
SmbClass->CurrentSmb->BlockLength = 0;
}
// Reset Data pointer
// smb_sts = READ_PORT_UCHAR (SMB_STS_REG);
// SMBDELAY;
// SmbPrint (SMB_IO, ("SmbAliCompleteTransaction: IO read SMB_STS = 0x%02x \n", smb_sts));
smb_sts = SMB_STS_SMB_IDX_CLR;
SmbPrint (SMB_IO, ("SmbAliCompleteTransactionWorker: IO write SMB_STS = 0x%02x \n", smb_sts));
WRITE_PORT_UCHAR (SMB_STS_REG, smb_sts);
SMBDELAY;
// Read data
for (i = 0; i < SmbClass->CurrentSmb->BlockLength; i++) {
SmbClass->CurrentSmb->Data[i] = READ_PORT_UCHAR (BLK_DATA_REG);
SMBDELAY;
SmbPrint (SMB_IO, ("SmbAliCompleteTransactionWorker: IO read BLK_DATA_REG (i = %d) = 0x%02x \n", i, SmbClass->CurrentSmb->Data[i]));
}
break;
}
}
else // smbStatus != SMB_STATUS_OK
{
//
// Retry the transaction up to 5 times before returning to the caller.
// REVIEW: Only do this for certain devices, commands, or error status results?
//
if (AliData->InternalRetries < 5)
{
//SmbPrint (SMB_IO_RESULT, (" SMBus Transaction status: %02x, retrying...\n", smbStatus));
AliData->InternalRetries += 1;
// Send the work item back to the init worker
AliData->InitTimeOut = SmbIoInitTimeOut;
KeSetTimer (&AliData->InitTimer,
SmbIoPollRate,
&AliData->InitDpc);
return;
}
}
// Clear any previous status.
//SmbPrint (SMB_IO, ("SmbAliCompleteTransaction: IO write SMB_STS = 0x%02x \n", SMB_STS_CLEAR));
//WRITE_PORT_UCHAR (SMB_STS_REG, SMB_STS_CLEAR);
// SMBDELAY;
SmbClass->CurrentSmb->Status = smbStatus;
SmbPrint (SMB_IO, ("SmbAliCompleteTransactionWorker: SMB Status = 0x%x\n", smbStatus));
SmbClass->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
SmbClass->CurrentIrp->IoStatus.Information = sizeof(SMB_REQUEST);
SmbPrint (SMB_IO_RESULT, (" Prtcl = %02x Addr = %02x Cmd = %02x BL = %02x Data[0,1] = %02x %02x Sts = %02x Rty = %02x\n",
SmbClass->CurrentSmb->Protocol,
SmbClass->CurrentSmb->Address,
SmbClass->CurrentSmb->Command,
SmbClass->CurrentSmb->BlockLength,
SmbClass->CurrentSmb->Data[0],
(SMB_READ_WORD == SmbClass->CurrentSmb->Protocol ||
SMB_WRITE_WORD == SmbClass->CurrentSmb->Protocol ||
(SMB_READ_BLOCK == SmbClass->CurrentSmb->Protocol &&
SmbClass->CurrentSmb->BlockLength >= 2)) ?
SmbClass->CurrentSmb->Data[1] : 0xFF,
SmbClass->CurrentSmb->Status,
AliData->InternalRetries));
SmbClassLockDevice (SmbClass);
SmbClassCompleteRequest (SmbClass);
SmbClassUnlockDevice (SmbClass);
#if DBG
//
// Track the # of successful transactions, and if not successful,
// the types of errors encountered.
//
if (SMB_STATUS_OK == smbStatus)
DbgSuccess += 1;
else
{
DbgFailure += 1;
if (SMB_TIMEOUT == smbStatus)
DbgTimeOut += 1;
else if (SMB_ADDRESS_NOT_ACKNOWLEDGED == smbStatus)
DbgAddrNotAck += 1;
else
DbgOtherErr += 1;
}
if ((DbgSuccess + DbgFailure) % 100 == 0)
SmbPrint(SMB_STATS, ("SmbAliCompleteTransactionWorker: Stats:\n"
" Success: %d, Failure: %d, %%: %d\n"
" TimeOut: %d, AddrNotAck: %d, Other: %d\n",
DbgSuccess, DbgFailure, DbgSuccess * 100 / (DbgSuccess + DbgFailure),
DbgTimeOut, DbgAddrNotAck, DbgOtherErr));
#endif
}
VOID
SmbAliNotifyHandler (
IN PVOID Context,
IN ULONG NotifyValue
)
{
PSMB_ALI_DATA AliData = (PSMB_ALI_DATA) Context;
ULONG address;
ULONG data;
UCHAR smb_sts;
SmbPrint (SMB_TRACE, ("SmbAliNotifyHandler: Entered"));
smb_sts = READ_PORT_UCHAR (SMB_STS_REG);
SMBDELAY;
SmbPrint (SMB_TRACE, ("SmbAliNotifyHandler: SMB_STS = %02x", smb_sts));
if (smb_sts & (SMB_STS_ALERT_STS || SMB_STS_SCI_I_STS)) {
//
// Alert Reponse
//
} else if (smb_sts & SMB_STS_SCI_I_STS) {
//
// Last Transaction completed
//
} else {
//
// Check for errors, etc.
//
}
IoQueueWorkItem (AliData->WorkItem,
SmbAliWorkerThread,
DelayedWorkQueue,
AliData);
}
VOID
SmbAliWorkerThread (
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context
)
{
PSMB_ALI_DATA AliData = (PSMB_ALI_DATA) Context;
SmbPrint (SMB_TRACE, ("SmbAliIrpCompletionWorker: Entered"));
//
// Complete Irps here
//
}
NTSTATUS
SmbAliSyncronousIrpCompletion (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This routine is called when the lower driver completes an IRP.
Arguments:
DeviceObject - Pointer to the device object for the device.
Irp - Irp completed.
Context - Driver defined context.
Return Value:
The function value is the final status from the operation.
--*/
{
PKEVENT event = Context;
KeSetEvent(event,
1,
FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
BOOLEAN
SmbAliTransactionComplete (
PSMB_ALI_DATA AliData,
PUCHAR SmbStatus
)
/*++
Routine Description:
This routine checks to see if there is the last transation was completed.
Arguments:
AliData - minidriver device extension.
SmbStatus - Status being returned.
Return Value:
True if transaction completed or had an error.
False if it is still waiting.
--*/
{
UCHAR smb_sts;
smb_sts = READ_PORT_UCHAR (SMB_STS_REG);
SMBDELAY;
SmbPrint (SMB_IO, ("SmbAliTransactionComplete: IO read SMB_STS = 0x%02x \n", smb_sts));
if (smb_sts & SMB_STS_HOST_BSY) {
SmbPrint (SMB_IO, ("SmbAliTransactionComplete: Transaction Not Complete: HOST BUSY\n"));
return FALSE;
}
if (!(smb_sts & SMB_STS_IDLE_STS)) {
SmbPrint (SMB_IO, ("SmbAliTransactionComplete: Transaction Not Complete: Idle Not Indicated\n"));
return FALSE;
}
if (smb_sts & SMB_STS_SCI_I_STS) {
//
// Transaction is complete
//
*SmbStatus = SMB_STATUS_OK;
return TRUE;
}
if (smb_sts & SMB_STS_FAILED) {
*SmbStatus = SMB_UNKNOWN_FAILURE;
} else if (smb_sts & SMB_STS_BUS_ERR) {
*SmbStatus = SMB_ADDRESS_NOT_ACKNOWLEDGED;
} else if (smb_sts & SMB_STS_DRV_ERR) {
*SmbStatus = SMB_TIMEOUT;
} else {
//
// This state really shouldn't be reached.
// Reset the SMBus host
//
SmbPrint (SMB_BUS_ERROR, ("SmbAliTransactionComplete: Invalid SMBus host state.\n"));
*SmbStatus = SMB_UNKNOWN_ERROR;
}
//
// For the three know error tpes we want to reset the bus
//
SmbPrint (SMB_BUS_ERROR, ("SmbAliTransactionComplete: SMBus error: 0x%x \n", *SmbStatus));
// Don't reset the bus etc. if this is a Bus Collision error
if ( *SmbStatus == SMB_ADDRESS_NOT_ACKNOWLEDGED )
{
// Should we clear the bits, lets try it
SmbPrint (SMB_IO, ("SmbAliCompleteTransaction: Clearing Error Bits. IO write SMB_STS = 0x%02x \n", SMB_STS_CLEAR));
WRITE_PORT_UCHAR (SMB_STS_REG, SMB_STS_CLEAR);
SMBDELAY;
}
else
{
SmbAliResetHost (AliData);
SmbAliResetBus (AliData);
}
return TRUE;
}
BOOLEAN
SmbAliHostBusy (
PSMB_ALI_DATA AliData
)
/*++
Routine Description:
This routine checks to see if the Host controller is free to start a
new transaction.
Arguments:
AliData - minidriver device extension.
Return Value:
True if The host is busy.
False if it free for use.
--*/
{
UCHAR smb_sts;
SmbPrint (SMB_TRACE, ("SmbAliHostBusy: Entered \n"));
smb_sts = READ_PORT_UCHAR (SMB_STS_REG);
SMBDELAY;
SmbPrint (SMB_IO, ("SmbAliHostBusy: IO read SMB_STS = 0x%02x \n", smb_sts));
if (smb_sts & SMB_STS_ALERT_STS) {
SmbPrint (SMB_TRACE, ("SmbAliHostBusy: Alert Detected \n"));
DbgBreakPoint();
SmbAliHandleAlert (AliData);
//
// Say device is still busy for now. BUGBUG
return TRUE;
}
if ( smb_sts == SMB_STS_LAST_CMD_COMPLETED )
{
//
// Clear the done bit
SmbPrint (SMB_IO, ("SmbAliHostBusy: IO write SMB_TYP = 0x%02x \n", SMB_STS_CLEAR_DONE));
WRITE_PORT_UCHAR (SMB_STS_REG, SMB_STS_CLEAR_DONE);
SMBDELAY;
return FALSE;
}
if ( smb_sts == SMB_STS_IDLE_STS )
{
//
// No bits are set, Host is not busy
//
SmbPrint (SMB_TRACE, ("SmbAliHostBusy: Not busy \n"));
return FALSE;
}
if ( smb_sts & SMB_STS_ERRORS ) {
//
// Clear it.
// Wait a cycle before continuing.
//
SmbPrint (SMB_IO, ("SmbAliHostBusy: IO write SMB_TYP = 0x%02x \n", SMB_STS_CLEAR));
WRITE_PORT_UCHAR (SMB_STS_REG, SMB_STS_CLEAR);
SMBDELAY;
return TRUE;
}
if ((smb_sts & SMB_STS_HOST_BSY) || !(smb_sts & SMB_STS_IDLE_STS)) {
//
// Host is busy
//
SmbPrint (SMB_TRACE, ("SmbAliHostBusy: Host Busy \n"));
return TRUE;
}
SmbPrint (SMB_ERROR, ("SmbAliHostBusy: Exiting (Why?) \n"));
return TRUE;
}
VOID
SmbAliHandleAlert (
PSMB_ALI_DATA AliData
)
/*++
Routine Description:
This routine reads the alert data and sends notification to SMB class.
Arguments:
AliData - minidriver device extension.
Return Value:
None
--*/
{
//BUGBUG not yet implemented
return;
}
VOID
SmbAliResetBus (
PSMB_ALI_DATA AliData
)
/*++
Routine Description:
This resets the bus by sending the timeout command.
Arguments:
AliData - minidriver device extension.
Return Value:
--*/
{
UCHAR smb_sts;
smb_sts = SMB_TYP_T_OUT_CMD;
SmbPrint (SMB_IO, ("SmbAliResetBus: IO write SMB_TYP = 0x%02x \n", smb_sts));
WRITE_PORT_UCHAR (SMB_TYP_REG, smb_sts);
SMBDELAY;
SmbPrint (SMB_IO, ("SmbAliResetBus: IO write SMB_STS = 0x%02x \n", SMB_STS_CLEAR));
WRITE_PORT_UCHAR (SMB_STS_REG, SMB_STS_CLEAR);
SMBDELAY;
}
VOID
SmbAliResetHost (
PSMB_ALI_DATA AliData
)
/*++
Routine Description:
This resets the host by sending the kill command.
Arguments:
AliData - minidriver device extension.
Return Value:
--*/
{
UCHAR smb_sts;
UCHAR timeout = 5;
smb_sts = SMB_TYP_KILL;
SmbPrint (SMB_IO, ("SmbAliResetHost: IO write SMB_TYP = 0x%02x \n", smb_sts));
WRITE_PORT_UCHAR (SMB_TYP_REG, smb_sts);
SMBDELAY;
SmbPrint (SMB_IO, ("SmbAliResetHost: IO write SMB_STS = 0x%02x \n", SMB_STS_CLEAR));
WRITE_PORT_UCHAR (SMB_STS_REG, SMB_STS_CLEAR);
SMBDELAY;
do {
KeDelayExecutionThread (KernelMode, FALSE, &SmbIoPollRate);
smb_sts = READ_PORT_UCHAR (SMB_STS_REG);
SmbPrint (SMB_IO, ("SmbAliResetHost: IO read SMB_STS = 0x%02x \n", smb_sts));
if (! (timeout--)) {
break;
}
} while (smb_sts & SMB_STS_FAILED);
}
#ifdef USE_IO_DELAY
LARGE_INTEGER DbgDelay = {-1,-1};
VOID SmbDelay(VOID)
{
KeDelayExecutionThread (KernelMode, FALSE, &DbgDelay);
}
#endif