usbdrv/peripheral/pdd/pil/src/controltransfersm.cpp
branchRCL_3
changeset 43 012cc2ee6408
parent 42 f92a4f87e424
child 45 ee9b31ff95f7
child 52 3d9964be03bc
--- a/usbdrv/peripheral/pdd/pil/src/controltransfersm.cpp	Tue Aug 31 17:01:47 2010 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,604 +0,0 @@
-/*
-  Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies). 
-  All rights reserved.
-
-  This program and the accompanying materials are made available 
-  under the terms of the Eclipse Public License v1.0 which accompanies 
-  this distribution, and is available at 
-  http://www.eclipse.org/legal/epl-v10.html
-
-  Initial Contributors:
-  Nokia Corporation - initial contribution.
-
-  Contributors:
-*/
-
-#include "controltransfersm.h"
-
-// Bitmap of setup packet
-/*
-Offset 0, bmRequestType, 1 bytes
-    1 Bit-Map
-        D7 Data Phase Transfer Direction
-        0 = Host to Device
-        1 = Device to Host
-    
-        D6..5 Type
-        0 = Standard
-        1 = Class
-        2 = Vendor
-        3 = Reserved
-    
-        D4..0 Recipient
-        0 = Device
-        1 = Interface
-        2 = Endpoint
-        3 = Other
-        4..31 = Reserved
-
-Offset 1, bRequest
-
-Offset 6, Count, 2 bytes
-        Number of bytes to transfer if there is a data phase
-*/
-
-#if defined(_DEBUG)
-
-#define CTSM_ID "ControlTransferSM "
-
-char* DebugName[] = 
-    {
-    "Setup",
-    "Data Out",
-    "Status In",
-    "Data In",
-    "Status Out"
-    };
-    
-#endif
-
-// Static data instance
-TUsbcSetup TSetupPkgParser::iSetupPkt;
-
-TSetupPkgParser::TSetupPkgParser()
-    {
-    iSetupPkt.iRequestType = 0;
-    iSetupPkt.iRequest = 0;
-    
-    iSetupPkt.iValue  = 0;
-    iSetupPkt.iIndex  = 0;
-    iSetupPkt.iLength = 0;
-    }
-
-// Code for TSetupPkgParser
-// we do a bitwise copy here.
-void TSetupPkgParser::Set(const TUint8* aSetupBuf)
-    {
-    // TUint8 index
-    iSetupPkt.iRequestType = static_cast<const TUint8*>(aSetupBuf)[0];
-    iSetupPkt.iRequest = static_cast<const TUint8*>(aSetupBuf)[1];
-    // TUint16 index from here!
-    iSetupPkt.iValue = SWAP_BYTES_16((reinterpret_cast<const TUint16*>(aSetupBuf))[1]);
-    iSetupPkt.iIndex = SWAP_BYTES_16((reinterpret_cast<const TUint16*>(aSetupBuf))[2]);
-    iSetupPkt.iLength = SWAP_BYTES_16((reinterpret_cast<const TUint16*>(aSetupBuf))[3]);
-    
-    __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "TSetupPkgParser::Set"));
-    }
-
-// return the next stage by decoding the setup packet 
-// the possible stage followed by a setup packet are:
-//      StatusIn (no data stage)
-//      DataOut  (host sent to peripheral)
-//      DataIn   (peripheral to host)
-UsbShai::TControlStage TSetupPkgParser::NextStage()
-    {
-    UsbShai::TControlStage ret = UsbShai::EControlTransferStageMax;
-    
-    // Take the data length out, 0 length means no data stage
-    if (iSetupPkt.iLength == 0)
-        {
-        ret = UsbShai::EControlTransferStageStatusIn;
-        }
-    else if ((iSetupPkt.iRequestType & KUsbRequestType_DirMask) == KUsbRequestType_DirToDev)
-        {
-        // Dir to device means host will send data out
-        ret = UsbShai::EControlTransferStageDataOut;
-        }
-    else
-        {
-        // Otherwise, there must be a datain stage follows
-        ret = UsbShai::EControlTransferStageDataIn;
-        } 
-    
-    __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "TSetupPkgParser::NextStage %d", ret));
-    
-    return ret;
-    }
-
-// Base class of stage sm
-TControlStageSm::TControlStageSm(DControlTransferManager& aTransferMgr):
-    iTransferMgr(aTransferMgr)
-    {    
-    }
-
-void TControlStageSm::ChangeToStage(UsbShai::TControlStage aToStage)
-    {
-    __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "<> TControlStageSm::ChangeToStage: %s",DebugName[aToStage]));
-    iTransferMgr.iCurrentStage = aToStage;
-    }
-
-void TControlStageSm::ClearPendingRead()
-    {
-    iTransferMgr.iReadPending = EFalse;
-    }
-    
-// Code for DControlTransferManager
-// 
-
-DControlTransferManager::DControlTransferManager(MControlTransferIf& aCtrTransIf):
-    iCtrTransferIf(aCtrTransIf)
-    {    
-    for(int i=0; i<UsbShai::EControlTransferStageMax; i++)
-        {
-        iState[i] = NULL;
-        }
-    
-    Reset();
-    }
-
-TInt DControlTransferManager::SetupEndpointZeroRead()
-    {
-    if(iState[iCurrentStage]->IsRequstAllowed(TControlTransferRequestRead))
-        {
-        if(!iReadPending)
-            {
-            iReadPending = ETrue;
-            return CtrTransferIf().ProcessSetupEndpointZeroRead();
-            }
-        else
-            {
-            // A read operation already on going, ignore this request
-            return KErrNone;
-            }
-        }
-    else
-        {
-        __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID " !! SetupEndpointZeroRead discard"));
-        return KErrNotReady;
-        }
-    }
-    
-TInt DControlTransferManager::SetupEndpointZeroWrite(const TUint8* aBuffer, TInt aLength, TBool aZlpReqd)
-    {
-    if(iState[iCurrentStage]->IsRequstAllowed(TControlTransferRequestWrite))
-        {
-        return CtrTransferIf().ProcessSetupEndpointZeroWrite(aBuffer,aLength,aZlpReqd);
-        }
-    else
-        {
-        __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID " !! SetupEndpointZeroWrite discard"));
-        return KErrNotReady;
-        }    
-    }
-    
-TInt DControlTransferManager::SendEp0ZeroByteStatusPacket()
-    {
-     if(iState[iCurrentStage]->IsRequstAllowed(TControlTransferRequestSendStatus))
-        {
-        iCurrentStage = UsbShai::EControlTransferStageSetup;
-        return CtrTransferIf().ProcessSendEp0ZeroByteStatusPacket();
-        }
-    else
-        {
-        __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID " !! SendEp0ZeroByteStatusPacket discard"));
-        return KErrNotReady;
-        }
-    }
-    
-TInt DControlTransferManager::StallEndpoint(TInt aRealEndpoint)
-    {
-    // Endpoint is stalled, we need to reset our state machine.
-    Reset();
-    return CtrTransferIf().ProcessStallEndpoint(aRealEndpoint);
-    }
-
-void DControlTransferManager::Ep0SetupPacketProceed()
-    {
-    __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID " !! Missed setup packet processed"));
-    CtrTransferIf().ProcessEp0SetupPacketProceed();
-    }
-        
-void DControlTransferManager::Ep0DataPacketProceed()
-    {
-    __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID " !! Missed data packet processed")); 
-    CtrTransferIf().ProcessEp0DataPacketProceed();
-    }
-    
-void DControlTransferManager::Reset()
-    {
-    iCurrentStage = UsbShai::EControlTransferStageSetup;
-    iReadPending = EFalse;
-    }
-    
-void DControlTransferManager::Ep0RequestComplete(TUint8* aBuf, 
-                                             TInt aCount, 
-                                             TInt aError, 
-                                             UsbShai::TControlPacketType aPktType)
-    {   
-    __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "> DControlTransferManager::Ep0RequestComplete, packet type: %s", DebugName[aPktType])); 
-    // If a setup packet comes, update our local setup packet buffer first
-    if(aPktType == UsbShai::EControlPacketTypeSetup)
-        {
-        iPacketParser.Set(aBuf);
-        // This is the only place this variable to be reset.
-        iDataTransfered = 0;
-        }
-    
-    // RequestComplete will return ETrue if it can not handle a packet
-    // And it knows that some other sm can handle it.
-    // It will update the state to the one which can hanlde that packet first.        
-    TBool furtherProcessNeeded = ETrue;
-    while(furtherProcessNeeded)
-        {        
-        __KTRACE_OPT(KUSB, Kern::Printf("   We're at Stage:         %s", DebugName[iCurrentStage]));
-        furtherProcessNeeded = iState[iCurrentStage]->RequestComplete(aCount,aError,aPktType);
-        __KTRACE_OPT(KUSB, Kern::Printf("   We're moved to stage:   %s", DebugName[iCurrentStage]));
-        }    
-    
-    __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "< DControlTransferManager::Ep0RequestComplete")); 
-    }
-
-// setup the state machine for a state
-void DControlTransferManager::AddState(UsbShai::TControlStage aStage,TControlStageSm& aStageSm)
-    {
-    if( (aStage >= UsbShai::EControlTransferStageSetup) && (aStage < UsbShai::EControlTransferStageMax))
-        {
-        __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID " AddState(), Stage: %s", DebugName[aStage]));
-        iState[aStage] = &aStageSm;
-        }
-    }
-        
-// *************** Code for SETUP state machines **************************************
-//
-DSetupStageSm::DSetupStageSm(DControlTransferManager& aTransferMgr):
-    TControlStageSm(aTransferMgr)
-    {
-    }
-
-// WE are waiting a SETUP packet
-TBool DSetupStageSm::RequestComplete(TInt aPktSize, TInt aError, UsbShai::TControlPacketType aPktType)
-    {
-    TBool ret = EFalse;
-    
-    __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "DSetupStageSm::RequestComplete"));
-    
-    if(aPktType != UsbShai::EControlPacketTypeSetup)
-        {
-        // we just discard any non-setup packet
-        __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DSetupStageSm - Non-Setup recieved"));
-        return ret;
-        }
-    
-    // change state to whatever returned from this call.
-    ChangeToStage(iTransferMgr.PktParser().NextStage());
-    
-    // We're going to complete User's read request, consume the previous
-    // read operation
-    ClearPendingRead();
-    
-    // Setup packet are always need to be processed
-    iTransferMgr.CtrTransferIf().ProcessSetupPacket(aPktSize,aError);
-    
-    return EFalse;
-    }
-
-TBool DSetupStageSm::IsRequstAllowed(TControlTransferRequest aRequest)
-    {
-    // Allow user to read, No other operation is allowed
-    TBool ret = (aRequest == TControlTransferRequestRead)?ETrue:EFalse;
-    
-    if( ! ret)
-        {
-        __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "Warning: request %d was blocked at DSetupStageSm",aRequest));
-        }
-        
-    return ret;
-    }
-
-    
-// *************** Code for DATA IN state machines **************************************
-
-DDataInStageSm::DDataInStageSm(DControlTransferManager& aTransferMgr):
-    TControlStageSm(aTransferMgr)
-    {
-    }
-
-// We are waiting for a competion of DATA IN packet
-TBool DDataInStageSm::RequestComplete(TInt aPktSize, TInt aError, UsbShai::TControlPacketType aPktType)
-    {
-    TInt completionCode = aError;
-    TBool furtherRequest = EFalse;
-    
-    switch(aPktType)
-        {
-        case UsbShai::EControlPacketTypeSetup:
-            {
-            __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DDataInStageSm - Setup recieved"));
-            // Something goes wrong, host is abandoning the unfinished control transfer
-            completionCode = KErrGeneral;
-            
-            // Force SM restart at setup stage
-            ChangeToStage(UsbShai::EControlTransferStageSetup);
-            
-            // this packet is partially processed here
-            // need another SM to continue
-            furtherRequest = ETrue;
-            }
-            break;
-            
-        case UsbShai::EControlPacketTypeDataIn:
-            {
-            // PSL notifing us that the data had been sent to host
-            // next step is to wait for the status from Host
-            ChangeToStage(UsbShai::EControlTransferStageStatusOut);
-             
-            // In USB spec, a compete control transfer must inclue a status stage
-            // which is not case in reality,some PSL/Hardware will swallow the
-            // Status out report, so, we just complete client normally.
-            }
-            break;
-            
-        default:
-            {
-            __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DDataInStageSm -  %s recieved",DebugName[aPktType]));
-            
-            // Unexpected packet will be discard, and lead us reset state machine
-            // so that we can wait for next SETUP packet.
-            // Of course error will be report to any client if any there.
-            ChangeToStage(UsbShai::EControlTransferStageSetup);
-            completionCode = KErrGeneral;
-            }
-            break;
-        }
-    
-    iTransferMgr.CtrTransferIf().ProcessDataInPacket(aPktSize,completionCode);
-
-    return furtherRequest;
-    }
-
-TBool DDataInStageSm::IsRequstAllowed(TControlTransferRequest aRequest)
-    {
-    // Only write is possible because host is waiting for data from us
-    TBool ret = (aRequest == TControlTransferRequestWrite)?ETrue:EFalse;
-    
-    if( ! ret)
-        {
-        __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "Warning: request %d was blocked at DDataInStageSm",aRequest));
-        }
-        
-    return ret;
-    };
-    
-// *************** Code for STATUS OUT state machines **************************************
-DStatusOutStageSm::DStatusOutStageSm(DControlTransferManager& aTransferMgr):
-    TControlStageSm(aTransferMgr)
-    {
-    }
-
-// We are waiting for a competion of STATUS OUT or a SETUP packet if PSL or hardware don't
-// complete a status in packet
-TBool DStatusOutStageSm::RequestComplete(TInt aPktSize, TInt aError, UsbShai::TControlPacketType aPktType)
-    {
-    TBool furtherRequest = EFalse;
-    TInt completionCode = aError;
-    
-    switch(aPktType)
-        {
-        case UsbShai::EControlPacketTypeSetup:
-            {
-            __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DStatusOutStageSm - Setup recieved"));
-            // hw or PSL may not send back the status packet for a DATA OUT
-            // and we're ok for this, just back to EControlTransferStageSetup stage           
-            
-            // Force SM restart at setup stage
-            ChangeToStage(UsbShai::EControlTransferStageSetup);
-            
-            // this packet is partially processed here
-            // need another SM to continue
-            furtherRequest = ETrue;
-            }
-            break;
-
-        case UsbShai::EControlPacketTypeStatusOut:
-            {
-            // Force SM restart at setup stage
-            ChangeToStage(UsbShai::EControlTransferStageSetup);
-            }
-            break;
-        
-        default:
-            {
-            __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DStatusOutStageSm -  %s recieved",DebugName[aPktType]));
-
-            // Unexpected packet will be discard, and lead us reset state machine
-            // so that we can wait for next SETUP packet.
-            // Of course error will be report to any client if any there.            
-            ChangeToStage(UsbShai::EControlTransferStageSetup);
-            completionCode = KErrGeneral;
-            }
-            break;
-        }
-
-    iTransferMgr.CtrTransferIf().ProcessStatusOutPacket(completionCode);
-        
-    return furtherRequest;
-    
-    }
-
-TBool DStatusOutStageSm::IsRequstAllowed(TControlTransferRequest aRequest)
-    {
-    // Read is ok since client don't care the status out stage.
-    // and this lead no hurt to anybody.
-    TBool ret = (aRequest == TControlTransferRequestRead)?ETrue:EFalse;
-    
-    if( ! ret)
-        {
-        __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "Warning: request %d was blocked at DStatusOutStageSm",aRequest));
-        }
-        
-    return ret;
-    };
-
-// *************** Code for DATA OUT state machines **************************************
-//
-DDataOutStageSm::DDataOutStageSm(DControlTransferManager& aTransferMgr):
-    TControlStageSm(aTransferMgr)
-    {
-    }
-
-TBool DDataOutStageSm::RequestComplete(TInt aPktSize, TInt aError, UsbShai::TControlPacketType aPktType)
-    {
-    TBool furtherRequest = EFalse;
-    TInt completionCode = aError;
-    
-    switch(aPktType)
-        {
-        case UsbShai::EControlPacketTypeSetup:
-            {
-            __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DDataOutStageSm - Setup recieved"));
-            // Host is abandon the previous Transfer 
-            completionCode = KErrGeneral;
-            
-            // Force SM restart at setup stage
-            ChangeToStage(UsbShai::EControlTransferStageSetup);
-
-            // this packet is partially processed here
-            // need another SM to continue
-            furtherRequest = ETrue;
-            }
-            break;
-            
-        case UsbShai::EControlPacketTypeDataOut:
-            {
-            iTransferMgr.DataReceived(aPktSize);
-            
-            if(!iTransferMgr.IsMoreBytesNeeded())
-                {
-                // We had recieved enough bytes as indicated by the setup
-                // packet, Data stage is finished. enter STATUS IN state
-                ChangeToStage(UsbShai::EControlTransferStageStatusIn);       
-                }            
-            }
-            break;
-        
-        case UsbShai::EControlPacketTypeStatusIn:
-            {
-            // Status in had been sent to host
-            // return and waiting for new SETUP
-            ChangeToStage(UsbShai::EControlTransferStageSetup);
-            }
-            break;
-            
-        default:
-            {
-            __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DDataOutStageSm -  %s recieved",DebugName[aPktType]));
-            
-            // Unexpected packet will be discard, and lead us reset state machine
-            // so that we can wait for next SETUP packet.
-            // Of course error will be report to any client if any there.
-            ChangeToStage(UsbShai::EControlTransferStageSetup);
-            completionCode = KErrGeneral;
-            }
-            break;
-        }
-    
-    ClearPendingRead();
-    iTransferMgr.CtrTransferIf().ProcessDataOutPacket(aPktSize,completionCode);
-    
-    return furtherRequest;
-    }
-
-TBool DDataOutStageSm::IsRequstAllowed(TControlTransferRequest aRequest)
-    {
-    // only read operation is allowed in data out stage.
-    TBool ret = (aRequest == TControlTransferRequestRead)?ETrue:EFalse;
-    
-    if( ! ret)
-        {
-        __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "Warning: request %d was blocked at DDataOutStageSm",aRequest));
-        }
-        
-    return ret;
-    };
-
-// *************** Code for DATA OUT state machines **************************************
-//
-DStatusInStageSm::DStatusInStageSm(DControlTransferManager& aTransferMgr):
-    TControlStageSm(aTransferMgr)
-    {
-    }
-
-TBool DStatusInStageSm::RequestComplete(TInt aPktSize, TInt aError, UsbShai::TControlPacketType aPktType)
-    {
-    TBool furtherRequest = EFalse;
-    TInt completionCode = KErrNone;
-    
-    switch(aPktType)
-        {
-        case UsbShai::EControlPacketTypeSetup:
-            {
-            __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DStatusInStageSm - Setup recieved"));
-            // Status in is an optional for PSL
-            // If we received a setup packet here, we assume the previous
-            // status in packet had been successfully sent to host.
-            
-            // Force SM restart at setup stage
-            ChangeToStage(UsbShai::EControlTransferStageSetup);
-            
-            // this packet is partially processed here
-            // need another SM to continue
-            furtherRequest = ETrue;
-            }
-            break;
-            
-        case UsbShai::EControlPacketTypeStatusIn:
-            {
-            // Status in had been recieved, monitor setup packet then.
-            ChangeToStage(UsbShai::EControlTransferStageSetup);
-            }
-            break;
-            
-        default:
-            {
-            __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "ALERT: DStatusInStageSm -  %s recieved",DebugName[aPktType]));
-
-            // Unexpected packet will be discard, and lead us reset state machine
-            // so that we can wait for next SETUP packet.
-            // Of course error will be report to any client if any there.
-            ChangeToStage(UsbShai::EControlTransferStageSetup);
-            completionCode = KErrGeneral;
-            }
-            break;
-        }
-    
-    iTransferMgr.CtrTransferIf().ProcessStatusInPacket(completionCode);
-    
-    return furtherRequest;
-    }
-
-TBool DStatusInStageSm::IsRequstAllowed(TControlTransferRequest aRequest)
-    {
-    // Read is ok even we are wait for the client to send a zero status packet
-    TBool ret = ((aRequest == TControlTransferRequestSendStatus) || 
-                (aRequest == TControlTransferRequestRead))?ETrue:EFalse;
-    
-    if( ! ret)
-        {
-        __KTRACE_OPT(KUSB, Kern::Printf(CTSM_ID "Warning: request %d was blocked at DStatusInStageSm",aRequest));
-        }
-        
-    return ret;
-    }
-    
-// End of file
-