428 lines
13 KiB
C
428 lines
13 KiB
C
/*++
|
||
|
||
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);
|
||
}
|