--- 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
-