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