|
|
/*++
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); }
|