diff -r 000000000000 -r 96e5fb8b040d userlibandfileserver/fileserver/smassstorage/cbulkonlytransport.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/smassstorage/cbulkonlytransport.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,918 @@ +// Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "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: +// + +/** + @file + @internalTechnology +*/ +#include "cbulkonlytransport.h" +#include "cbulkonlytransportusbcldd.h" +#include "cbulkonlytransportusbcscldd.h" +#include "usbmsshared.h" +#include "massstoragedebug.h" +#include "cusbmassstorageserver.h" + + +//CBW offsets +LOCAL_D const TInt KCbwSignatureOffset = 0; +LOCAL_D const TInt KCbwTagOffset = 4; +LOCAL_D const TInt KCbwDataTransferLengthOffset = 8; +LOCAL_D const TInt KCbwFlagOffset = 12; +LOCAL_D const TInt KCbwLunOffset = 13; +LOCAL_D const TInt KCbwCbLengthOffset = 14; + +LOCAL_D const TInt KMaxCbwcbLength = 16; + +// CSW offsets +LOCAL_D const TInt KCswSingnatureOffset = 0; +LOCAL_D const TInt KCswTagOffset = 4; +LOCAL_D const TInt KCswDataResidueOffset = 8; +LOCAL_D const TInt KCswStatusOffset = 12; + + + +/** + This function unpacks into the TUsbRequestHdr class from a descriptor with + the alignment that would be introduced on the USB bus. + + @param aBuffer Input buffer + @param aTarget Unpacked header. + @return Error. + */ +TInt TUsbRequestHdr::Decode(const TDesC8& aBuffer) + + { + if (aBuffer.Length() < static_cast(KRequestHdrSize)) + { + __PRINT1(_L("TUsbRequestHdr::Decode buffer invalid length %d"), aBuffer.Length()); + return KErrGeneral; + } + + iRequestType = aBuffer[0]; + iRequest = static_cast(aBuffer[1]); + iValue = static_cast(aBuffer[2] + (aBuffer[3] << 8)); + iIndex = static_cast(aBuffer[4] + (aBuffer[5] << 8)); + iLength = static_cast(aBuffer[6] + (aBuffer[7] << 8)); + __PRINT5(_L("type=%d request=%d value=%d index=%d length=%d"), iRequestType,iRequest,iValue,iIndex,iLength); + + return KErrNone; + } + + +/** +This function determines whether data is required by the host in response +to a message header. + +@return TBool Flag indicating whether a data response required. +*/ +TBool TUsbRequestHdr::IsDataResponseRequired() const + + { + return (iRequestType & 0x80) ? (TBool)ETrue : (TBool)EFalse; + } + +//------------------------------------- +/** +Create an object of a class derived from CBulkOnlyTransport (default to CBulkOnlyTransportUsbcLdd object) +@param aNumDrives - The number of drives available for MS +@param aController - reference to the parent +@return pointer to newly created derived class object +*/ +CBulkOnlyTransport* CBulkOnlyTransport::NewL(TInt aNumDrives,CUsbMassStorageController& aController) + { + __FNLOG("CBulkOnlyTransport::NewL()"); + + return NewL(aNumDrives,aController, (CUsbMassStorageController::TTransportldd) 1); + } + +/** +Create an object of a class derived from CBulkOnlyTransport +@param aNumDrives - The number of drives available for MS +@param aController - reference to the parent +@param aTransportLddFlag - Type of usb client ldd +@return pointer to newly created derived class object +*/ +CBulkOnlyTransport* CBulkOnlyTransport::NewL(TInt aNumDrives,CUsbMassStorageController& aController, CUsbMassStorageController::TTransportldd aTransportLddFlag) + { + __FNLOG("CBulkOnlyTransport::NewL()"); + + if (aNumDrives <=0 || static_cast(aNumDrives) > KUsbMsMaxDrives) + { + User::Leave(KErrArgument); + } + + CBulkOnlyTransportUsbcScLdd* scTransport; + CBulkOnlyTransportUsbcLdd* nonscTransport; + switch (aTransportLddFlag) + { + case 1: + nonscTransport = new(ELeave) CBulkOnlyTransportUsbcLdd(aNumDrives, aController); + return nonscTransport; + + case 2: + scTransport = new(ELeave) CBulkOnlyTransportUsbcScLdd(aNumDrives, aController); + return scTransport; + default: + return NULL; + + } + } + + +TInt CBulkOnlyTransport::InitialiseTransportL(TInt aTransportLddFlag) + { + __FNLOG("CBulkOnlyTransportUsbcScLdd::InitialiseTransportL()"); + TInt ret = KErrNone; + MTransportBase* transport; + iController.GetTransport(transport); + switch (aTransportLddFlag) + { + case 2: + ret = ((CBulkOnlyTransportUsbcScLdd*) transport)->Ldd().Open(0); + if (ret != KErrNone) + { + return ret; + } + else + { + ((CBulkOnlyTransportUsbcScLdd*) transport)->Ldd().Close(); + CleanupStack::PushL(transport); + ((CBulkOnlyTransportUsbcScLdd*) transport)->ConstructL(); + CleanupStack::Pop(transport); + return ret; + } + case 1: + ret = ((CBulkOnlyTransportUsbcLdd*) transport)->Ldd().Open(0); + if (ret != KErrNone) + { + return ret; + } + else + { + ((CBulkOnlyTransportUsbcLdd*) transport)->Ldd().Close(); + CleanupStack::PushL(transport); + ((CBulkOnlyTransportUsbcLdd*) transport)->ConstructL(); + CleanupStack::Pop(transport); + return ret; + } + default: + return KErrNotFound; + } + } + +/** +c'tor +@param aNumDrives - The number of drives available for MS +@param aController - reference to the parent +*/ +CBulkOnlyTransport::CBulkOnlyTransport(TInt aNumDrives,CUsbMassStorageController& aController): + CActive(EPriorityStandard), + iMaxLun(aNumDrives-1), + iController(aController), + iStallAllowed(ETrue), + iInterfaceConfigured(EFalse), + iCommandBufPtr(NULL,0), + iDataBufPtr(NULL,0), + iCswBufPtr(NULL,0), + iPaddingBufPtr(NULL,0), + iWriteBufPtr(NULL,0), + iReadBufPtr(NULL, 0), + iCbwBufPtr(NULL,0) + { + __FNLOG("CBulkOnlyTransport::CBulkOnlyTransport"); + } + +/** +Destructor +*/ +CBulkOnlyTransport::~CBulkOnlyTransport() + { + __FNLOG("CBulkOnlyTransport::~CBulkOnlyTransport"); + if (iInterfaceConfigured) + { + Stop(); + } + } + + +/** +Called by the protocol after processing the packet to indicate that more data is required. + +@param aData reference to the data buffer. +*/ +void CBulkOnlyTransport::SetupReadData(TUint aLength) + { + __FNLOG("CBulkOnlyTransport::SetupReadData"); + __PRINT1(_L("Length = %d (bytes)\n"), aLength); + iBufSize = aLength; + iReadSetUp = ETrue; + } + + +/** +Called by the protocol after processing the packet to indicate that data should be written to the host. + +@param aData reference to the data buffer. +*/ +void CBulkOnlyTransport::SetupWriteData(TPtrC8& aData) + { + __FNLOG("CBulkOnlyTransport::SetupWriteData"); + __PRINT1(_L("Length = %d (bytes)\n"), aData.Length()); + iWriteBufPtr.Set(aData); + iWriteSetUp = ETrue; + } + + +TInt CBulkOnlyTransport::Start() + { + __FNLOG("CBulkOnlyTransport::Start"); + + TInt err = KErrNone; + + if (!iProtocol) + { + return KErrBadHandle; //protocol should be set up before start + } + + if (IsActive()) + { + __PRINT(_L("CBulkOnlyTransport::Start - active before start!\n")); + return KErrInUse; + } + + if ((err = SetupConfigurationDescriptor()) != KErrNone || + (err = SetupInterfaceDescriptors()) != KErrNone ) + { + __PRINT(_L("CBulkOnlyTransport::Start - Error during descriptors setup!\n")); + return err; + } + + AllocateEndpointResources(); + ActivateDeviceStateNotifier(); // activate notifier wich will wait until USB became configured + TUsbcDeviceState deviceStatus = EUsbcDeviceStateDefault; + err = GetDeviceStatus(deviceStatus); + __PRINT1(_L("CBulkOnlyTransport::Start - Device status = %d\n"), deviceStatus); + if (err == KErrNone && deviceStatus == EUsbcDeviceStateConfigured) + { + __PRINT(_L("CBulkOnlyTransport::Start - Starting bulk only transport\n")); + err = HwStart(); + } + +#ifdef MSDC_MULTITHREADED + TPtr8 aDes1(NULL,0); + TPtr8 aDes2(NULL,0); + GetBufferPointers(aDes1, aDes2); + iProtocol->InitializeBufferPointers(aDes1, aDes2); // have to pass pointer to memory not offsets to initialise TPtr, and lengths +#endif + + iInterfaceConfigured = ETrue; + return err; + } + +TInt CBulkOnlyTransport::HwStart(TBool aDiscard) + { + __FNLOG("CBulkOnlyTransport::HwStart"); + + TInt lun = MaxLun(); + do + { + Controller().DriveManager().Connect(lun); + } + while(--lun >= 0); + + TInt res = StartControlInterface(); + + iCurrentState = ENone; + iWriteSetUp=EFalse; + iReadSetUp=EFalse; + iStarted = ETrue; + + if (aDiscard) + { + FlushData(); + } + + ReadCBW(); + return res; + } + + +TInt CBulkOnlyTransport::HwStop() + { + __FNLOG("CBulkOnlyTransport::HwStop"); + if (iStarted) + { + StopBulkOnlyEndpoint(); + CancelControlInterface(); + iStarted = EFalse; + } + return KErrNone; + } + + +void CBulkOnlyTransport::StopBulkOnlyEndpoint() + { + __FNLOG("CBulkOnlyTransport::StopBulkOnlyEndpoint"); + + TInt lun = MaxLun(); + do + { + Controller().DriveManager().Disconnect(lun); + } + while(--lun >= 0); + Cancel(); + iProtocol->Cancel(); + } + + +TInt CBulkOnlyTransport::HwSuspend() + { + __FNLOG("CBulkOnlyTransport::HwSuspend"); + + TInt lun = MaxLun(); + do + { + Controller().DriveManager().Disconnect(lun); + } + while(--lun >= 0); + + return KErrNone; + } + + +TInt CBulkOnlyTransport::HwResume() + { + __FNLOG("CBulkOnlyTransport::HwResume"); + + TInt lun = MaxLun(); + do + { + Controller().DriveManager().Connect(lun); + } + while(--lun >= 0); + + return KErrNone; + } + +/** +Stops the Bulk Only Transport +*/ +TInt CBulkOnlyTransport::Stop() + { + __FNLOG("CBulkOnlyTransport::Stop"); + CancelControlInterface(); + CancelDeviceStateNotifier(); + Cancel(); + if (iInterfaceConfigured) + { + ReleaseInterface(); + SetupConfigurationDescriptor(ETrue); + } + iCurrentState = ENone; + iInterfaceConfigured = EFalse; + + return KErrNone; + } + + + +void CBulkOnlyTransport::DoCancel() + { + __FNLOG("CBulkOnlyTransport::DoCancel"); + CancelReadWriteRequests(); + } + + +void CBulkOnlyTransport::Activate(TInt aReason) + { + SetActive(); + TRequestStatus* r = &iStatus; + User::RequestComplete(r, aReason); + } + + +void CBulkOnlyTransport::RunL() + { + __FNLOG("CBulkOnlyTransport::RunL"); + if (iStatus != KErrNone) + { + __PRINT1(_L("Error %d in RunL, halt endpoints \n"), iStatus.Int()); + SetPermError(); //halt endpoints for reset recovery + return; + } + switch (iCurrentState) + { + case EWaitForCBW: + __PRINT(_L("EWaitForCBW")); + ProcessCbwEvent(); + break; + + case EWritingData: + __PRINT(_L("EWritingData")); + iWriteSetUp = EFalse; //the buffer was used + + if (iDataResidue && iStallAllowed) + { + StallEndpointAndWaitForClear(); + } + + SendCSW(iCbwTag, iDataResidue, iCmdStatus); + break; + + case EReadingData: + { + __PRINT(_L("EReadingData")); + + ProcessReadingDataEvent(); + } + break; + + case ESendingCSW: + __PRINT(_L("ESendingCSW")); + ReadCBW(); + break; + + case EPermErr: + __PRINT(_L("EPermErr")); + StallEndpointAndWaitForClear(); + break; + + default: + SetPermError(); // unexpected state + } + } + + +/** +Decode the CBW received from the host via OutEndpoint + +- If the header is valid, the data content is passed to the parser. +- Depending on the command, more data may be transmitted/received. +- ...or the CSW is sent (if not a data command). + +*/ +void CBulkOnlyTransport::DecodeCBW() + { + __FNLOG("CBulkOnlyTransport::DecodeCBW"); + + SetCbwPtr(); + + if (!CheckCBW()) //check if CBW valid and meaningful + { + // CBW not valid or meaningful + // Specification says: "If the CBW is not valid, the device shall STALL + // the Bulk-In pipe. Also, the device shall either STALL the Bulk-Out pipe, + // or the device shall accept and discard any Bulk-Out data. The device + // shall maintain this state until a Reset Recovery." + // Here we keep bulk-in ep stalled and ignore bulk-out ep. + SetPermError(); + ExpireData((TAny*) (iCbwBufPtr.Ptr())); + return; + } + + TPtrC8 aData; + aData.Set(&iCbwBufPtr[KCbwCbLengthOffset], KMaxCbwcbLength+1); //prepare data for protocol starting form Length + TUint8 lun = static_cast(iCbwBufPtr[13] & 0x0f); + + iCbwTag = static_cast(iCbwBufPtr[KCbwTagOffset]) | + static_cast(iCbwBufPtr[KCbwTagOffset+1]) <<8 | + static_cast(iCbwBufPtr[KCbwTagOffset+2]) <<16| + static_cast(iCbwBufPtr[KCbwTagOffset+3]) <<24; + + TInt i = KCbwDataTransferLengthOffset; + TUint hostDataLength = static_cast(iCbwBufPtr[i ]) | + static_cast(iCbwBufPtr[i+1]) <<8 | + static_cast(iCbwBufPtr[i+2]) <<16 | + static_cast(iCbwBufPtr[i+3]) <<24; + + TBool dataToHost = iCbwBufPtr[KCbwFlagOffset] & 0x80; + + __PRINT4(_L("lun =%d, hostDataLength=%d, CBWtag = 0x%x, dataToHost=%d\n"), lun, hostDataLength, iCbwTag, dataToHost); + ////////////////////////////////////////////// + TBool ret = iProtocol->DecodePacket(aData, lun); + ////////////////////////////////////////////// + ExpireData((TAny*) (iCbwBufPtr.Ptr())); + + + iStallAllowed = ETrue; + + if (!ret) + { + __PRINT(_L("Command Failed\n")); + iCmdStatus = ECommandFailed; + } + else + { + __PRINT(_L("Command Passed\n")); + iCmdStatus = ECommandPassed; + } + + if (hostDataLength) // Host expected data transfer + { + if (dataToHost) // send data to host + { + if (!iWriteSetUp) //write buffer was not set up + { + __PRINT(_L("Write buffer was not setup\n")); + iDataResidue =hostDataLength; + __PRINT1(_L("DataResidue (write to host)=%d\n"),iDataResidue); + +//------------------------------------ + if (hostDataLength <= KBOTMaxBufSize) + { + __PRINT(_L("Case 4 or 8\n")); + SetPaddingBufPtr(hostDataLength); + iPaddingBufPtr.FillZ(hostDataLength); + TPtrC8 ptr(NULL, 0); + ptr.Set((TUint8*)iPaddingBufPtr.Ptr(), hostDataLength); + WriteData(iStatus, ptr, hostDataLength, EFalse); + iStallAllowed = EFalse; + if (iReadSetUp) //read buffer WAS set up - case (8) + { + __PRINT(_L("It is Case 8\n")); + iCmdStatus = EPhaseError; + } + return; + } + else +//------------------------------------ +// Use next block instead of StallEndpointAndWaitForClear(InEndpoint); + { + SetPaddingBufPtr(hostDataLength); + iPaddingBufPtr.FillZ(KBOTMaxBufSize); + TUint c =0; + TRequestStatus status; + while (c KBOTMaxBufSize) + { + len = KBOTMaxBufSize; + } + else + { + len = hostDataLength - c; + } + + TPtrC8 ptr(NULL, 0); + ptr.Set((TUint8*)iPaddingBufPtr.Ptr(), len); + WriteUsb(status, ptr, len); + User::WaitForRequest(status); + c += KBOTMaxBufSize; + } + } + + if (iReadSetUp) //read buffer WAS set up - case (8) + { + __PRINT(_L("Case 8\n")); + SendCSW(iCbwTag, hostDataLength, EPhaseError); + //don't care to reset any flag - should get reset recovery + } + else // case (4) + { + __PRINT(_L("Case 4\n")); + SendCSW(iCbwTag, hostDataLength, iCmdStatus); + } + return; + } // if (!iWriteSetUp) + +//================== + TUint deviceDataLength = static_cast(iWriteBufPtr.Length()); + iDataResidue =hostDataLength - deviceDataLength ; + __PRINT2(_L("Device data length = %d, DataResidue (write to host)=%d\n"), deviceDataLength, iDataResidue); + + if (deviceDataLength < hostDataLength && + hostDataLength < KBOTMaxBufSize ) + { + __PRINT(_L("Case 5 (padding)\n")); + SetPaddingBufPtr(hostDataLength); + iPaddingBufPtr.Zero(); + iPaddingBufPtr.Append(iWriteBufPtr); + iStallAllowed = EFalse; + __PRINT1(_L("iPaddingBufPtr.Length = %d\n"),iPaddingBufPtr.Length()); + TPtrC8 ptr(NULL, 0); + ptr.Set((TUint8*)iPaddingBufPtr.Ptr(), hostDataLength); + WriteData(iStatus, ptr, hostDataLength, EFalse); + return; + } + +//=================== + + if (deviceDataLength == hostDataLength) //case (6)[==] + { + __PRINT(_L("Case 6\n")); + WriteData(iStatus, iWriteBufPtr, deviceDataLength); + return; + } + else if (deviceDataLength < hostDataLength) //case (5)[<] + { + __PRINT(_L("Case 5\n")); + WriteData(iStatus, iWriteBufPtr, deviceDataLength, ETrue); // Send ZLP + return; + } + else // deviceDataLength > hostDataLength - case (7) + { + __PRINT(_L("Case 7\n")); + iCmdStatus = EPhaseError; + iDataResidue = 0; + WriteData(iStatus, iWriteBufPtr, hostDataLength); + return; + } + } + else //read data from host + { + if (!iReadSetUp) + { + iDataResidue = hostDataLength; + __PRINT(_L("Read buffer was not setup\n")); +// Use next block instead of StallEndpointAndWaitForClear(OutEndpoint); + DiscardData(hostDataLength); + + if (iWriteSetUp) //case (10) + { + __PRINT(_L("case 10\n")); + SendCSW(iCbwTag, hostDataLength, EPhaseError); + } + else // case (9) + { + __PRINT(_L("Case 9\n")); + SendCSW(iCbwTag, hostDataLength, iCmdStatus); + } + + return; + } + + TUint deviceDataLength = iBufSize; + iDataResidue = hostDataLength; // calculate residue later + + __PRINT2(_L("deviceDataLength = iBufSize = %d, DataResidue = HDL for now (read from host) =%d\n"),deviceDataLength,iDataResidue); + + if (deviceDataLength <= hostDataLength) // case (11) and (12) + { + __PRINT(_L("Case 11 or 12\n")); + ReadData(deviceDataLength); + return; + } + if (deviceDataLength > hostDataLength) // case (13) + { + __PRINT(_L("Case 13\n")); + /** + * Comment following line in order to pass compliant test. + * As spec said in case 13:"The device may receive data up to a + * total of dCBWDataTransferLength." + * Here we choose to ignore incoming data. + */ + //StallEndpointAndWaitForClear(OutEndpoint); //Stall Out endpoint + if (iReadSetUp) + { + WriteToClient(hostDataLength); + iReadSetUp = EFalse; + } + SendCSW(iCbwTag, hostDataLength, EPhaseError); + return; + } + } + } + else // Host expected no data transfer + { + __PRINT(_L("No data transfer expected\n")); + iDataResidue = 0; + if (iWriteSetUp || iReadSetUp) // case (2) and (3) + { + __PRINT(_L("Case 2 or 3\n")); + SendCSW(iCbwTag, 0, EPhaseError); + } + else + { + __PRINT(_L("Case 1\n")); + SendCSW(iCbwTag, 0, iCmdStatus); //case (1) + } + } + } + + +/** +Check if CBW Valid and Meaningful. + +@return ETrue if CBW is Valid and Meaningful, EFalse otherwise +*/ +TBool CBulkOnlyTransport::CheckCBW() + { + __FNLOG("CBulkOnlyTransport::CheckCBW"); + + // + // Check valid + // + + // Check length + if ((TUint) (iCbwBufPtr.Length()) != KCbwLength) + { + __PRINT2(_L("Bad length: %d != KCbwLength"), iCbwBufPtr.Length(), KCbwLength); + return EFalse; + } + + // Check signature + TInt i = KCbwSignatureOffset; + if (iCbwBufPtr[i ] != 0x55 || // CBW Singature from USB Bulk-Only Transport spec + iCbwBufPtr[i+1] != 0x53 || + iCbwBufPtr[i+2] != 0x42 || + iCbwBufPtr[i+3] != 0x43) + { + __PRINT(_L("Bad signature")); + __PRINT4(_L(" 0x%x, 0x%x, 0x%x, 0x%x \n"), iCbwBufPtr[i], iCbwBufPtr[i+1], iCbwBufPtr[i+2],iCbwBufPtr[i+3]) + return EFalse; + } + + // + // Check meaningful + // + + // Check reserved bits ( must be zero ) + if ((iCbwBufPtr[KCbwLunOffset] & 0xF0) || (iCbwBufPtr[KCbwCbLengthOffset] & 0xE0)) + { + __PRINT(_L("Reserved bits not zero\n")); + return EFalse; + } + + // check command block length + TInt cbwcbLength = iCbwBufPtr[KCbwCbLengthOffset] & 0x1F; + if (cbwcbLength >KMaxCbwcbLength) + { + __PRINT(_L("Incorrect block length\n")); + return EFalse; + } + + //check LUN + TInt8 lun = static_cast(iCbwBufPtr[KCbwLunOffset] & 0x0f); + if (iMaxLun < lun) + { + __PRINT1(_L("bad lun: %d"), lun); + return EFalse; + } + + return ETrue; + } + + +/** +Initiate stalling of bulk IN endpoint. +Used when protocol wants to force host to initiate a reset recovery. +*/ +void CBulkOnlyTransport::SetPermError() + { + __FNLOG("CBulkOnlyTransport::SetPermError"); + iCurrentState = EPermErr; + Activate(KErrNone); + } + + +/** +Send data provided by protocol to the host + +@param aLength amount of data (in bytes) to be send to host +*/ +void CBulkOnlyTransport::WriteData(TRequestStatus& aStatus, TPtrC8& aDes, TUint aLength, TBool aZlpRequired) + { + __FNLOG("CBulkOnlyTransport::WriteData"); + + if (IsActive()) + { + __PRINT(_L("Still active\n")); + __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive)); + return; + } + WriteUsb(aStatus, aDes, aLength, aZlpRequired); + iCurrentState = EWritingData; + SetActive(); + } + + +/** +Send Command Status Wrapper to the host + +@param aTag Echo of Command Block Tag sent by the host. +@param aDataResidue the difference between the amount of data expected by the + host, and the actual amount of data processed by the device. +@param aStatus indicates the success or failure of the command. +*/ +void CBulkOnlyTransport::SendCSW(TUint aTag, TUint aDataResidue, TCswStatus aStatus) + { + __FNLOG("CBulkOnlyTransport::SendCSW"); + __PRINT2(_L("DataResidue = %d, Status = %d \n"), aDataResidue, aStatus); + + if (IsActive()) + { + __PRINT(_L("Still active\n")); + __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive)); + return; + } + + SetCswBufPtr(KCswLength); + TInt i = KCswSingnatureOffset; + iCswBufPtr[i ] = 0x55; // CSW Singature from USB Bulk-Only Transport spec + iCswBufPtr[i+1] = 0x53; + iCswBufPtr[i+2] = 0x42; + iCswBufPtr[i+3] = 0x53; + + i = KCswTagOffset; + + iCswBufPtr[i ] = static_cast((aTag & 0x000000FF)); + iCswBufPtr[i+1] = static_cast((aTag & 0x0000FF00) >> 8); + iCswBufPtr[i+2] = static_cast((aTag & 0x00FF0000) >> 16); + iCswBufPtr[i+3] = static_cast((aTag & 0xFF000000) >> 24); + + i = KCswDataResidueOffset; + iCswBufPtr[i ] = static_cast((aDataResidue & 0x000000FF)); + iCswBufPtr[i+1] = static_cast((aDataResidue & 0x0000FF00) >> 8); + iCswBufPtr[i+2] = static_cast((aDataResidue & 0x00FF0000) >> 16); + iCswBufPtr[i+3] = static_cast((aDataResidue & 0xFF000000) >> 24); + + iCswBufPtr[KCswStatusOffset] = static_cast(aStatus); + + TPtrC8 ptr(NULL, 0); + ptr.Set((const TUint8*)iCswBufPtr.Ptr(), KCswLength); + + WriteUsb(iStatus, ptr, KCswLength); + + iCurrentState = ESendingCSW; + + SetActive(); + } + + +/** +Associates the transport with the protocol. Called during initialization of the controller. + +@param aProtocol reference to the protocol +*/ +void CBulkOnlyTransport::RegisterProtocol(MProtocolBase& aProtocol) + { + __FNLOG("CBulkOnlyTransport::RegisterProtocol"); + iProtocol = &aProtocol; + } + + +/** +Used by CControlInterface + +@return reference to the controller which instantiate the CBulkOnlyTransport +*/ +CUsbMassStorageController& CBulkOnlyTransport::Controller() + { + return iController; + } + + +/** +@return the number of logical units supported by the device. +Logical Unit Numbers on the device shall be numbered contiguously starting from LUN +0 to a maximum LUN of 15 (Fh). +*/ +TInt CBulkOnlyTransport::MaxLun() + { + return iMaxLun; + } + + +void CBulkOnlyTransport::GetCommandBufPtr(TPtr8& aDes, TUint aLength) // Set pointer to buffer of specified aLength for command + { + aDes.Set(SetCommandBufPtr(aLength)); + } + +void CBulkOnlyTransport::GetReadDataBufPtr(TPtr8& aDes) // Set pointer to buffer into which data is to be read from drive (Read10) + { + aDes.Set(SetDataBufPtr()); + } + + +void CBulkOnlyTransport::GetWriteDataBufPtr(TPtrC8& aDes) // Set pointer to buffer from which data is to be written to drive (Write10) + { + aDes.Set(iReadBufPtr); + } + +#ifdef MSDC_MULTITHREADED +void CBulkOnlyTransport::ProcessReadData(TAny* aAddress) + { + ExpireData(aAddress); + } +#endif + + + + + + + +