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

428 lines
13 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
smbcsrv.c
Abstract:
SMBus class driver service functions
Author:
Ken Reneris
Environment:
Notes:
Revision History:
--*/
#include "smbc.h"
VOID
SmbCRetry (
IN struct _KDPC *Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
Handles retry timer
--*/
{
PSMBDATA Smb;
Smb = (PSMBDATA) DeferredContext;
SmbClassLockDevice (&Smb->Class);
//
// State is waiting for retry, move it to send request
//
ASSERT (Smb->IoState == SMBC_WAITING_FOR_RETRY);
Smb->IoState = SMBC_START_REQUEST;
SmbClassStartIo (Smb);
SmbClassUnlockDevice (&Smb->Class);
}
VOID
SmbClassStartIo (
IN PSMBDATA Smb
)
/*++
Routine Description:
Main class driver state loop
N.B. device lock is held by caller.
N.B. device lock may be released and re-acquired during call
--*/
{
PLIST_ENTRY Entry;
PIRP Irp;
PIO_STACK_LOCATION IrpSp;
PSMB_REQUEST SmbReq;
LARGE_INTEGER duetime;
//
// If already servicing the device, done
//
if (Smb->InService) {
return ;
}
//
// Service the device
//
Smb->InService = TRUE;
while (Smb->InService) {
ASSERT_DEVICE_LOCKED (Smb);
switch (Smb->IoState) {
case SMBC_IDLE:
//
// Check if there is a request to give to the miniport
//
ASSERT (!Smb->Class.CurrentIrp);
if (IsListEmpty(&Smb->WorkQueue)) {
// nothing to do, stop servicing the device
Smb->InService = FALSE;
break;
}
//
// Get the next IRP
//
Entry = RemoveHeadList(&Smb->WorkQueue);
Irp = CONTAINING_RECORD (
Entry,
IRP,
Tail.Overlay.ListEntry
);
//
// Make it the current request
//
Smb->RetryCount = 0;
Smb->Class.DeviceObject->CurrentIrp = Irp;
Smb->IoState = SMBC_START_REQUEST;
break;
case SMBC_START_REQUEST:
//
// Tell miniport to start on this request
//
Irp = Smb->Class.DeviceObject->CurrentIrp;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
Smb->Class.CurrentIrp = Irp;
Smb->Class.CurrentSmb = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
Smb->IoState = SMBC_WAITING_FOR_REQUEST;
#if DEBUG
if (SMBCDebug & SMB_TRANSACTION) {
PUCHAR protocols [SMB_MAXIMUM_PROTOCOL+1] = {
"SMB_WRITE_QUICK",
"SMB_READ_QUICK",
"SMB_SEND_BYTE",
"SMB_RECEIVE_BYTE",
"SMB_WRITE_BYTE",
"SMB_READ_BYTE",
"SMB_WRITE_WORD",
"SMB_READ_WORD",
"SMB_WRITE_BLOCK",
"SMB_READ_BLOCK",
"SMB_PROCESS_CALL",
"SMB_BLOCK_PROCESS_CALL"};
UCHAR i;
SmbPrint (SMB_TRANSACTION, ("SmbClassStartIo: started %s (%02x) Add: %02x",
(Smb->Class.CurrentSmb->Protocol <= SMB_MAXIMUM_PROTOCOL) ?
protocols[Smb->Class.CurrentSmb->Protocol] : "BAD PROTOCOL",
Smb->Class.CurrentSmb->Protocol, Smb->Class.CurrentSmb->Address));
switch (Smb->Class.CurrentSmb->Protocol) {
case SMB_WRITE_QUICK:
case SMB_READ_QUICK:
case SMB_RECEIVE_BYTE:
SmbPrint (SMB_TRANSACTION, ("\n"));
break;
case SMB_SEND_BYTE:
SmbPrint (SMB_TRANSACTION, (", Data: %02x\n", Smb->Class.CurrentSmb->Data[0]));
break;
case SMB_WRITE_BYTE:
SmbPrint (SMB_TRANSACTION, (", Com: %02x, Data: %02x\n",
Smb->Class.CurrentSmb->Command, Smb->Class.CurrentSmb->Data[0]));
break;
case SMB_READ_BYTE:
case SMB_READ_WORD:
case SMB_READ_BLOCK:
SmbPrint (SMB_TRANSACTION, (", Com: %02x\n",
Smb->Class.CurrentSmb->Command));
break;
case SMB_WRITE_WORD:
case SMB_PROCESS_CALL:
SmbPrint (SMB_TRANSACTION, (", Com: %02x, Data: %04x\n",
Smb->Class.CurrentSmb->Command, *((PUSHORT)Smb->Class.CurrentSmb->Data)));
break;
case SMB_WRITE_BLOCK:
case SMB_BLOCK_PROCESS_CALL:
SmbPrint (SMB_TRANSACTION, (", Com: %02x, Len: %02x, Data:",
Smb->Class.CurrentSmb->Command, Smb->Class.CurrentSmb->BlockLength));
for (i=0; i < Smb->Class.CurrentSmb->BlockLength; i++) {
SmbPrint (SMB_TRANSACTION, (" %02x", Smb->Class.CurrentSmb->Data[i]));
}
SmbPrint (SMB_TRANSACTION, ("\n"));
break;
default:
SmbPrint (SMB_TRANSACTION, ("\n"));
}
}
#endif
Smb->Class.StartIo (&Smb->Class, Smb->Class.Miniport);
break;
case SMBC_WAITING_FOR_REQUEST:
//
// Waiting for miniport, just keep waiting
//
Smb->InService = FALSE;
break;
case SMBC_COMPLETE_REQUEST:
//
// Miniport has returned the request
//
Irp = Smb->Class.DeviceObject->CurrentIrp;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
SmbReq = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
#if DEBUG
if (SMBCDebug & SMB_TRANSACTION) {
PUCHAR protocols [SMB_MAXIMUM_PROTOCOL+1] = {
"SMB_WRITE_QUICK",
"SMB_READ_QUICK",
"SMB_SEND_BYTE",
"SMB_RECEIVE_BYTE",
"SMB_WRITE_BYTE",
"SMB_READ_BYTE",
"SMB_WRITE_WORD",
"SMB_READ_WORD",
"SMB_WRITE_BLOCK",
"SMB_READ_BLOCK",
"SMB_PROCESS_CALL",
"SMB_BLOCK_PROCESS_CALL"};
UCHAR i;
SmbPrint (SMB_TRANSACTION, ("SmbClassStartIo: finished %s (%02x) Status: %02x, Add: %02x",
(SmbReq->Protocol <= SMB_MAXIMUM_PROTOCOL) ?
protocols[SmbReq->Protocol] : "BAD PROTOCOL",
SmbReq->Protocol, SmbReq->Status, SmbReq->Address));
if (SmbReq->Status != SMB_STATUS_OK) {
SmbPrint (SMB_TRANSACTION, ("\n"));
} else {
switch (SmbReq->Protocol) {
case SMB_WRITE_QUICK:
case SMB_READ_QUICK:
case SMB_SEND_BYTE:
SmbPrint (SMB_TRANSACTION, ("\n"));
break;
case SMB_RECEIVE_BYTE:
SmbPrint (SMB_TRANSACTION, (", Data: %02x\n", SmbReq->Data[0]));
break;
case SMB_READ_BYTE:
SmbPrint (SMB_TRANSACTION, (", Com: %02x, Data: %02x\n",
SmbReq->Command, SmbReq->Data[0]));
break;
case SMB_WRITE_BYTE:
case SMB_WRITE_WORD:
case SMB_WRITE_BLOCK:
SmbPrint (SMB_TRANSACTION, (", Com: %02x\n",
SmbReq->Command));
break;
case SMB_READ_WORD:
case SMB_PROCESS_CALL:
SmbPrint (SMB_TRANSACTION, (", Com: %02x, Data: %04x\n",
SmbReq->Command, *((PUSHORT)SmbReq->Data)));
break;
case SMB_READ_BLOCK:
case SMB_BLOCK_PROCESS_CALL:
SmbPrint (SMB_TRANSACTION, (", Com: %02x, Len: %02x, Data:",
SmbReq->Command, SmbReq->BlockLength));
for (i=0; i < SmbReq->BlockLength; i++) {
SmbPrint (SMB_TRANSACTION, (" %02x", SmbReq->Data[i]));
}
SmbPrint (SMB_TRANSACTION, ("\n"));
break;
default:
SmbPrint (SMB_TRANSACTION, ("\n"));
}
}
}
#endif
if (SmbReq->Status != SMB_STATUS_OK) {
//
// SMB request had an error, check for a retry
//
SmbPrint (SMB_WARN, ("SmbCStartIo: smb request error %x\n", SmbReq->Status));
if (Smb->RetryCount < MAX_RETRIES) {
Smb->RetryCount += 1;
Smb->IoState = SMBC_WAITING_FOR_RETRY;
duetime.QuadPart = RETRY_TIME;
KeSetTimer (&Smb->RetryTimer, duetime, &Smb->RetryDpc);
break;
}
}
//
// Complete the request
//
Smb->Class.DeviceObject->CurrentIrp = NULL;
Smb->IoState = SMBC_COMPLETING_REQUEST;
SmbClassUnlockDevice (&Smb->Class);
IoCompleteRequest (Irp, IO_NO_INCREMENT);
SmbClassLockDevice (&Smb->Class);
//
// Now idle
//
Smb->IoState = SMBC_IDLE;
break;
case SMBC_WAITING_FOR_RETRY:
//
// Waiting to retry, just keep waiting
//
Smb->InService = FALSE;
break;
default:
SmbPrint(SMB_ERROR, ("SmbCStartIo: unknown state\n"));
Smb->IoState = SMBC_IDLE;
Smb->InService = FALSE;
break;
}
}
return ;
}
VOID
SmbClassCompleteRequest (
IN PSMB_CLASS SmbClass
)
/*++
Routine Description:
Called by the miniport to complete the request it was given
N.B. device lock is held by caller.
N.B. device lock may be released and re-acquired during call
--*/
{
PSMBDATA Smb;
//
// Device must be locked, and waiting for a request to compelte
//
Smb = CONTAINING_RECORD (SmbClass, SMBDATA, Class);
ASSERT_DEVICE_LOCKED (Smb);
ASSERT (Smb->IoState == SMBC_WAITING_FOR_REQUEST);
//
// No irp at miniport
//
SmbClass->CurrentIrp = NULL;
SmbClass->CurrentSmb = NULL;
//
// Update state to complete it and handle it
//
Smb->IoState = SMBC_COMPLETE_REQUEST;
SmbClassStartIo (Smb);
}
VOID
SmbClassLockDevice (
IN PSMB_CLASS SmbClass
)
/*++
Routine Description:
Called to acquire the device lock
--*/
{
PSMBDATA Smb;
Smb = CONTAINING_RECORD (SmbClass, SMBDATA, Class);
KeAcquireSpinLock (&Smb->SpinLock, &Smb->SpinLockIrql);
#if DEBUG
ASSERT (!Smb->SpinLockAcquired);
Smb->SpinLockAcquired = TRUE;
#endif
}
VOID
SmbClassUnlockDevice (
IN PSMB_CLASS SmbClass
)
/*++
Routine Description:
Called to release the device lock
--*/
{
PSMBDATA Smb;
Smb = CONTAINING_RECORD (SmbClass, SMBDATA, Class);
#if DEBUG
ASSERT_DEVICE_LOCKED (Smb);
Smb->SpinLockAcquired = FALSE;
#endif
KeReleaseSpinLock (&Smb->SpinLock, Smb->SpinLockIrql);
}