--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usbengines/usbdevcon/src/cstatemachine.cpp Thu Dec 17 09:14:30 2009 +0200
@@ -0,0 +1,384 @@
+/*
+* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: usbdevcon state machine
+*
+*/
+
+
+#include "cusbdevcon.h"
+#include "cstatemachine.h"
+#include "cep0reader.h"
+#include "cep0writer.h"
+#include "crequestshandler.h"
+#include "debug.h"
+
+const TUint KOneByte = 8; // for shifting data to one byte
+
+// binary constant for checking if bit 7 is set
+const TUint KUsbDevConBit7 = 0x80;
+
+const TUint KLengthLoByte = 6;
+const TUint KLengthHiByte = 7;
+
+// ---------------------------------------------------------------------------
+// Two-phase construction
+// ---------------------------------------------------------------------------
+//
+CStateMachine* CStateMachine::NewL(CRequestsHandler& aRequestsHandler, RDevUsbcClient& iLdd)
+ {
+ FLOG( _L( "[USBDEVCON]\tCStateMachine::NewL" ) );
+
+ CStateMachine* self = new (ELeave) CStateMachine(aRequestsHandler, iLdd);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+// ---------------------------------------------------------------------------
+// Two-phase constructon
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::ConstructL()
+ {
+
+ FLOG( _L( "[USBDEVCON]\tCStateMachine::ConstructL" ) );
+
+ iBuffer.CreateL(0); // later will be reallocated with required size
+
+ // reader
+ iEP0Reader = CEP0Reader::NewL(*this,iLdd);
+
+ // writer
+ iEP0Writer = CEP0Writer::NewL(*this, iLdd);
+
+ }
+
+// ---------------------------------------------------------------------------
+// Default construction
+// ---------------------------------------------------------------------------
+//
+CStateMachine::CStateMachine(CRequestsHandler& aRequestsHandler, RDevUsbcClient& aLdd) :
+ iRequestsHandler(aRequestsHandler),
+ iLdd (aLdd),
+ iState(ENoneState)
+ {
+ }
+
+// ---------------------------------------------------------------------------
+// Destruction
+// ---------------------------------------------------------------------------
+//
+CStateMachine::~CStateMachine()
+ {
+ delete iEP0Writer;
+ delete iEP0Reader;
+ iBuffer.Close();
+ }
+
+// ---------------------------------------------------------------------------
+// Starts state machine
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::Start()
+ {
+
+ FLOG( _L( "[USBDEVCON]\tCStateMachine::Start" ) );
+
+ // resetting, if it's been already started
+ if(IsStarted())
+ {
+ Stop();
+ }
+
+ iState = ESetupStage;
+ iEP0Reader->ReadSetupPacket();
+
+ }
+
+// ---------------------------------------------------------------------------
+// Stops machine
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::Stop()
+ {
+
+ FLOG( _L( "[USBDEVCON]\tCStateMachine::Stop" ) );
+
+ iEP0Reader->Cancel();
+ iEP0Writer->Cancel();
+
+ iState = ENoneState;
+
+ }
+
+// ---------------------------------------------------------------------------
+// ETrue if state machine is started
+// ---------------------------------------------------------------------------
+//
+TInt CStateMachine::IsStarted() const
+ {
+
+ if(ENoneState == iState)
+ {
+ FLOG( _L( "[USBDEVCON]\tCStateMachine::IsStarted == EFalse" ) );
+ return EFalse;
+ }
+ else
+ {
+ FLOG( _L( "[USBDEVCON]\tCStateMachine::IsStarted == ETrue" ) );
+ }
+ return ETrue;
+ }
+
+// ---------------------------------------------------------------------------
+// Something has been read from EP0
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::ReadEP0(RBuf8& aBuffer, const TRequestStatus& aStatus)
+ {
+
+ FTRACE(FPrint(
+ _L("[USBDEVCON]\tCStateMachine::ReadEP0: BufferLength = %d, aStatus = %d" ),aBuffer.Length(), aStatus.Int()));
+
+ // all errors while reading data lead to idle state (ESetupStage in our case)
+ if(KErrNone != aStatus.Int())
+ {
+ // restart
+ Start();
+ return;
+ }
+
+ TInt err(KErrNone);
+
+ switch(iState)
+ {
+ case ESetupStage: // setup transaction received
+ {
+
+ FLOG( _L( "[USBDEVCON]\tCStateMachine::ReadEP0 processing ESetupStage" ) );
+
+ if(aBuffer.Length() != KSetupPacketLength) // SetupPacket is always 8 bytes
+ {
+ Start();
+ return;
+ }
+
+ ProcessSetupPacket(aBuffer);
+
+ break;
+ }
+ case EDataStage: // some data received from host. This data is required for the request, received on setup stage
+ {
+
+ FLOG( _L( "[USBDEVCON]\tCStateMachine::ReadEP0 processing EDataStage" ) );
+
+ // handle request, providing data together with request descriptor
+ // iBuffer == request, aBuffer == data from host
+ err = iRequestsHandler.Handle(iBuffer, aBuffer);
+
+ if(KErrNone != err) // some error happened while handling request
+ {
+ iLdd.EndpointZeroRequestError(); // stall EP0
+ }
+ else
+ {
+ // send Status Packet, indicating that we received request, data, and handled request. OK
+ iLdd.SendEp0StatusPacket();
+ }
+
+ // all done, go to idle state
+ iState = ESetupStage;
+ iEP0Reader->ReadSetupPacket();
+
+ break;
+
+ }
+ default:
+ {
+ FLOG( _L( "[USBDEVCON]\tCStateMachine::ReadEP0 processing ***NOT_DEFINED state***" ) );
+ }
+
+ }
+
+ }
+
+// ---------------------------------------------------------------------------
+// Processing setup packet
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::ProcessSetupPacket(RBuf8& aSetupPacket)
+ {
+
+ FLOG( _L( "[USBDEVCON]\tCStateMachine::ProcessSetupPacket" ) );
+
+ TUint datalength(0); // data length, to be received from host
+
+ if(IsDataFromHostRequired(aSetupPacket, datalength)) // then goes to data stage
+ {
+
+ FTRACE(FPrint(
+ _L("[USBDEVCON]\tCStateMachine::ProcessSetupPacket. Data from host is required: %d bytes" ),datalength));
+
+ // save request, until receiving following data
+ iBuffer.Close();
+ iBuffer.Create(aSetupPacket);
+
+ // switch to Data state
+ iState = EDataStage;
+ iEP0Reader->Read(datalength);
+
+ return;
+
+ }
+
+ TInt err(KErrNone);
+
+ // Handle request. It does not require data from host
+ // aSetupPacket == request, iBuffer = result of the request
+ err = iRequestsHandler.Handle(aSetupPacket, iBuffer);
+
+ if(KErrNone != err) // some error happened while handling request
+ {
+
+ FTRACE(FPrint(
+ _L("[USBDEVCON]\tCStateMachine::ProcessSetupPacket. Error while handling request, errcode: %d" ), err));
+
+ iLdd.EndpointZeroRequestError(); // stall EP0
+
+ // listen to EP0
+ iState = ESetupStage;
+ iEP0Reader->ReadSetupPacket();
+
+ return;
+ }
+
+ // send response, size of datalength
+ if(IsDataFromDeviceRequired(aSetupPacket, datalength))
+ {
+
+ FTRACE(FPrint(
+ _L("[USBDEVCON]\tCStateMachine::ProcessSetupPacket. Data from device is required: %d bytes" ),datalength));
+
+ iState = EStatusStage;
+ iEP0Writer->Write(iBuffer, datalength);
+
+ return;
+
+ }
+
+ // status stage
+ iLdd.SendEp0StatusPacket();
+
+ // all is done, listen to EP0, in setup stage
+ iState = ESetupStage;
+ iEP0Reader->ReadSetupPacket();
+
+ }
+
+
+// ---------------------------------------------------------------------------
+// Something has been written to EP0
+// ---------------------------------------------------------------------------
+//
+void CStateMachine::WroteEP0(const TRequestStatus& aStatus)
+ {
+
+ FTRACE(FPrint(
+ _L("[USBDEVCON]\tCStateMachine::WroteEP0: iStatus = %d" ), aStatus.Int()));
+
+ // all errors while writing data lead to idle state (ESetupStage in our case)
+ if(KErrNone != aStatus.Int())
+ {
+ // restart
+ Start();
+ }
+
+ switch(iState)
+ {
+ case EStatusStage:
+ {
+
+ FLOG( _L( "[USBDEVCON]\tCStateMachine::WroteEP0 EStatusStage -> ESetupStage" ) );
+
+ // successfully wrote data to EP0
+ // go to idle
+ iState = ESetupStage;
+ iEP0Reader->ReadSetupPacket();
+
+ break;
+ }
+ default:
+ {
+ FLOG( _L( "[USBDEVCON]\tCStateMachine::WroteEP0 ***ENoneState***" ) );
+ }
+ }
+ }
+
+// ---------------------------------------------------------------------------
+// ETrue if data required to be send from host
+// ---------------------------------------------------------------------------
+//
+TBool CStateMachine::IsDataFromHostRequired(const RBuf8& aSetupPacket, TUint& aDataLength) const
+ {
+ // bits 6 and 7 of SetupPacket contain wLength - length of data in Data stage
+ aDataLength = static_cast<TUint16>(aSetupPacket[KLengthLoByte] |
+ (aSetupPacket[KLengthHiByte] << KOneByte));
+ if(0 == aDataLength)
+ {
+ // no data required in any direction
+ return EFalse;
+ }
+
+ // direction of data
+ // bit 7 of byte 0 of aSetupPacket (means bmRequestType one) contains:
+ // 0, if no data or data goes from host to device
+ // 1 means data goes from device to host
+ if(KUsbDevConBit7 & aSetupPacket[0])
+ { // bit 7 is set => data flow is from device to host
+ return EFalse;
+ }
+
+ return ETrue;
+
+ }
+
+// ---------------------------------------------------------------------------
+// ETrue if data required to be send to host
+// ---------------------------------------------------------------------------
+//
+TBool CStateMachine::IsDataFromDeviceRequired(const RBuf8& aSetupPacket, TUint& aDataLength) const
+ {
+ // bytes 6 and 7 of SetupPacket contain wLength - length of data in Data stage
+ aDataLength = static_cast<TUint16>(aSetupPacket[KLengthLoByte] |
+ (aSetupPacket[KLengthHiByte] << KOneByte));
+ if(0 == aDataLength)
+ {
+ // no data required in any direction
+ return EFalse;
+ }
+
+ // direction of data
+ // bit 7 of byte 0 of aSetupPacket (means bmRequestType one) contains:
+ // 0, if no data or data goes from host to device
+ // 1 means data goes from device to host
+ if(KUsbDevConBit7 & aSetupPacket[0])
+ { // bit 7 is set => data flow is from device to host
+ return ETrue;
+ }
+
+ return EFalse;
+ }
+
+