Fix for bug 2283 (RVCT 4.0 support is missing from PDK 3.0.h)
Have multiple extension sections in the bld.inf, one for each version
of the compiler. The RVCT version building the tools will build the
runtime libraries for its version, but make sure we extract all the other
versions from zip archives. Also add the archive for RVCT4.
// 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<TInt>(KRequestHdrSize))
{
__PRINT1(_L("TUsbRequestHdr::Decode buffer invalid length %d"), aBuffer.Length());
return KErrGeneral;
}
iRequestType = aBuffer[0];
iRequest = static_cast<TEp0Request>(aBuffer[1]);
iValue = static_cast<TUint16>(aBuffer[2] + (aBuffer[3] << 8));
iIndex = static_cast<TUint16>(aBuffer[4] + (aBuffer[5] << 8));
iLength = static_cast<TUint16>(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<TUint>(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<TUint8>(iCbwBufPtr[13] & 0x0f);
iCbwTag = static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset]) |
static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset+1]) <<8 |
static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset+2]) <<16|
static_cast<TUint32>(iCbwBufPtr[KCbwTagOffset+3]) <<24;
TInt i = KCbwDataTransferLengthOffset;
TUint hostDataLength = static_cast<TUint32>(iCbwBufPtr[i ]) |
static_cast<TUint32>(iCbwBufPtr[i+1]) <<8 |
static_cast<TUint32>(iCbwBufPtr[i+2]) <<16 |
static_cast<TUint32>(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<hostDataLength)
{
TInt len;
if (hostDataLength - 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<TUint>(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<TUint8>(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<TUint8>((aTag & 0x000000FF));
iCswBufPtr[i+1] = static_cast<TUint8>((aTag & 0x0000FF00) >> 8);
iCswBufPtr[i+2] = static_cast<TUint8>((aTag & 0x00FF0000) >> 16);
iCswBufPtr[i+3] = static_cast<TUint8>((aTag & 0xFF000000) >> 24);
i = KCswDataResidueOffset;
iCswBufPtr[i ] = static_cast<TUint8>((aDataResidue & 0x000000FF));
iCswBufPtr[i+1] = static_cast<TUint8>((aDataResidue & 0x0000FF00) >> 8);
iCswBufPtr[i+2] = static_cast<TUint8>((aDataResidue & 0x00FF0000) >> 16);
iCswBufPtr[i+3] = static_cast<TUint8>((aDataResidue & 0xFF000000) >> 24);
iCswBufPtr[KCswStatusOffset] = static_cast<TUint8>(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