/*
* 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 "cbulkonlytransportusbcscldd.h"
#include "usbmsshared.h"
#include "massstoragedebug.h"
#include "cusbmassstorageserver.h"
//This value defined in USB Mass Storage Bulk Only Transrt spec and not supposed to be changed
LOCAL_D const TInt KRequiredNumberOfEndpoints = 2; // in addition to endpoint 0.
LOCAL_D const TInt KUsbNumInterfacesOffset = 4;
#ifdef MSDC_MULTITHREADED
//Only used in DB. The first 2K of KMaxScBufferSize for sending CSW
static const TUint32 KCswBufferSize = 2 * 1024;
#endif
////////////////////////////////////
/**
Called by CBulkOnlyTransportUsbcScLdd to create an instance of CControlInterfaceUsbcScLdd
@param aParent reference to the CBulkOnlyTransportUsbcScLdd
*/
CControlInterfaceUsbcScLdd* CControlInterfaceUsbcScLdd::NewL(CBulkOnlyTransportUsbcScLdd& aParent)
{
CControlInterfaceUsbcScLdd* self = new(ELeave) CControlInterfaceUsbcScLdd(aParent);
CleanupStack::PushL(self);
self->ConstructL();
CActiveScheduler::Add(self);
CleanupStack::Pop();
return self;
}
void CControlInterfaceUsbcScLdd::ConstructL()
{
}
/**
c'tor
@param aParent reference to the CBulkOnlyTransportUsbcScLdd
*/
CControlInterfaceUsbcScLdd::CControlInterfaceUsbcScLdd(CBulkOnlyTransportUsbcScLdd& aParent)
:CActive(EPriorityStandard),
iParent(aParent),
iCurrentState(ENone)
{
}
/**
d'tor
*/
CControlInterfaceUsbcScLdd::~CControlInterfaceUsbcScLdd()
{
__FNLOG("CControlInterfaceUsbcScLdd::~CControlInterfaceUsbcScLdd ");
Cancel();
iEp0Buf.Close();
}
TInt CControlInterfaceUsbcScLdd::OpenEp0()
{
TInt res = iParent.Ldd().OpenEndpoint(iEp0Buf,0);
return res;
}
/**
Called by CBulkOnlyTransport HwStart to start control interface
*/
TInt CControlInterfaceUsbcScLdd::Start()
{
__FNLOG("CControlInterfaceUsbcScLdd::Start ");
TInt res = ReadEp0Data();
return (res);
}
/**
Called by desctructor of CBulkOnlyTransportUsbcScLdd to stop control interface
*/
void CControlInterfaceUsbcScLdd::Stop()
{
__FNLOG("CControlInterfaceUsbcScLdd::Stop ");
if (!IsActive())
{
__PRINT(_L("Not active\n"));
return;
}
__PRINT(_L("\nStopping...\n"));
iCurrentState = ENone;
Cancel();
}
/**
Cancel outstanding request (if any)
*/
void CControlInterfaceUsbcScLdd::DoCancel()
{
__FNLOG("CControlInterfaceUsbcScLdd::DoCancel ");
switch(iCurrentState)
{
case EReadEp0Data:
iParent.Ldd().ReadCancel(KUsbcScEndpointZero);
break;
case ESendMaxLun:
iParent.Ldd().WriteCancel(KUsbcScEndpointZero);
break;
default:
__PRINT(_L("\nWrong state !\n"));
__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceBadState));
}
}
/**
Implement CControlInterfaceUsbcScLdd state machine
*/
void CControlInterfaceUsbcScLdd::RunL()
{
__FNLOG("CControlInterfaceUsbcScLdd::RunL ");
if (iStatus != KErrNone)
{
__PRINT1(_L("Error %d in RunL\n"), iStatus.Int());
//read EP0 again
ReadEp0Data();
return;
}
ReadEp0Data();
}
/**
Actual Read to RDevUsbcScClient BIL
*/
TInt CControlInterfaceUsbcScLdd::ReadUsbEp0()
{
iCurrentState = EReadEp0Data;
iStatus = KRequestPending;
return iEp0Buf.GetBuffer (iEp0Packet,iEp0Size,iEp0Zlp,iStatus);
}
/**
Post a read request to EEndpoint0 to read request header
*/
TInt CControlInterfaceUsbcScLdd::ReadEp0Data()
{
__FNLOG("CControlInterfaceUsbcScLdd::ReadEp0Data ");
if (IsActive())
{
__PRINT(_L("Still active\n"));
return KErrServerBusy;
}
TInt r = KErrNone;
do
{
r = ReadUsbEp0();
if (r == KErrCompletion)
{
iStatus = KErrNone;
DecodeEp0Data();
}
else if (r == KErrNone)
{
SetActive();
}
} while (((r == KErrCompletion) || (r == TEndpointBuffer::KStateChange)) && (!IsActive()));
return KErrNone;
}
/**
Decode request header and do appropriate action - get max LUN info or post a reset request
*/
void CControlInterfaceUsbcScLdd::DecodeEp0Data()
{
__FNLOG("CControlInterfaceUsbcScLdd::DecodeEp0Data ");
if (IsActive())
{
__PRINT(_L("Still active\n"));
__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceStillActive));
return;
}
TPtrC8 ep0ReadDataPtr((TUint8*)iEp0Packet, iEp0Size);
TInt err = iRequestHeader.Decode(ep0ReadDataPtr);
if(err != KErrNone)
return;
switch(iRequestHeader.iRequest)
{
//
// GET MAX LUN (0xFE)
//
case TUsbRequestHdr::EReqGetMaxLun:
{
__PRINT1(_L("DecodeEp0Data : 'Get Max LUN' Request MaxLun = %d"),iParent.MaxLun() );
if ( iRequestHeader.iRequestType != 0xA1 //value from USB MS BOT spec
|| iRequestHeader.iIndex > 15
|| iRequestHeader.iValue != 0
|| iRequestHeader.iLength != 1)
{
__PRINT(_L("GetMaxLun command packet check error"));
iParent.Ldd().EndpointZeroRequestError();
break;
}
TPtr8* ep0WriteDataPtr = NULL;
TUint ep0Length;
iEp0Buf.GetInBufferRange(((TAny*&)ep0WriteDataPtr),ep0Length);
ep0WriteDataPtr->SetLength(1); //Return only 1 byte to host
ep0WriteDataPtr->Fill(0);
ep0WriteDataPtr->Fill(iParent.MaxLun()); // Supported Units
TInt length = ep0WriteDataPtr->Length();
err = iEp0Buf.WriteBuffer((TPtr8*)(ep0WriteDataPtr->Ptr()),length,ETrue,iStatus);
iCurrentState = ESendMaxLun;
SetActive();
return;
}
//
// RESET (0xFF)
//
case TUsbRequestHdr::EReqReset:
{
__PRINT(_L("DecodeEp0Data : 'Mass Storage Reset' Request"));
if ( iRequestHeader.iRequestType != 0x21 //value from USB MS BOT spec
|| iRequestHeader.iIndex > 15
|| iRequestHeader.iValue != 0
|| iRequestHeader.iLength != 0)
{
__PRINT(_L("MSC Reset command packet check error"));
iParent.Ldd().EndpointZeroRequestError();
break;
}
iParent.HwStop();
iParent.Controller().Reset();
iParent.HwStart(ETrue);
err = iParent.Ldd().SendEp0StatusPacket();
return;
}
//
// Unknown?
//
default:
{
__PRINT(_L("DecodeEp0Data : Unknown Request"));
}
}
ReadEp0Data(); //try to get another request
}
//
// --- class CBulkOnlyTransportUsbcScLdd ---------------------------------------------------------
//
CBulkOnlyTransportUsbcScLdd::CBulkOnlyTransportUsbcScLdd(TInt aNumDrives,CUsbMassStorageController& aController)
:CBulkOnlyTransport(aNumDrives, aController)
{
__FNLOG("CBulkOnlyTransportUsbcScLdd::CBulkOnlyTransportUsbcScLdd");
}
/**
Constructs the CBulkOnlyTransportUsbcScLdd object
*/
void CBulkOnlyTransportUsbcScLdd::ConstructL()
{
__FNLOG("CBulkOnlyTransportUsbcScLdd::ConstructL()");
iControlInterface = CControlInterfaceUsbcScLdd::NewL(*this);
iDeviceStateNotifier = CActiveDeviceStateNotifierBase::NewL(*this, *this);
iChunk = new RChunk();
CActiveScheduler::Add(this);
}
CBulkOnlyTransportUsbcScLdd::~CBulkOnlyTransportUsbcScLdd()
{
__FNLOG("CBulkOnlyTransportUsbcScLdd::~CBulkOnlyTransportUsbcScLdd");
if (iInterfaceConfigured)
{
TInt err = iSCReadEndpointBuf.Close();
err = iSCWriteEndpointBuf.Close();
delete iControlInterface ;
delete iDeviceStateNotifier;
delete iChunk;
}
}
RDevUsbcScClient& CBulkOnlyTransportUsbcScLdd::Ldd()
{
return iLdd;
}
/**
Set or unset configuration descriptor for USB MassStorage Bulk Only transport
@param aUnset indicate whether set or unset descriptor
@return KErrNone if operation was completed successfully, errorcode otherwise
*/
TInt CBulkOnlyTransportUsbcScLdd::SetupConfigurationDescriptor(TBool aUnset)
{
__FNLOG("CBulkOnlyTransportUsbcScLdd::SetupConfigurationDescriptor");
TInt ret(KErrNone);
if ((ret = iLdd.Open(0)) != KErrNone)
return ret;
TInt configDescriptorSize(0);
iLdd.GetConfigurationDescriptorSize(configDescriptorSize);
if (static_cast<TUint>(configDescriptorSize) != KUsbDescSize_Config)
{
return KErrCorrupt;
}
TBuf8<KUsbDescSize_Config> configDescriptor;
ret = iLdd.GetConfigurationDescriptor(configDescriptor);
if (ret != KErrNone)
{
return ret;
}
// I beleive that other fields setted up during LDD initialisation
if (aUnset)
{
--configDescriptor[KUsbNumInterfacesOffset];
}
else
{
++configDescriptor[KUsbNumInterfacesOffset];
}
ret = iLdd.SetConfigurationDescriptor(configDescriptor);
if (aUnset)
{
iLdd.Close();
}
return ret;
}
/**
Set up interface descriptor
@return KErrNone if operation was completed successfully, errorcode otherwise
*/
TInt CBulkOnlyTransportUsbcScLdd::SetupInterfaceDescriptors()
{
__FNLOG("CBulkOnlyTransportUsbcScLdd::SetupInterfaceDescriptors");
// Device caps
TUsbDeviceCaps d_caps;
TInt ret = iLdd.DeviceCaps(d_caps);
if (ret != KErrNone)
{
return ret;
}
TInt totalEndpoints = d_caps().iTotalEndpoints;
if (totalEndpoints < KRequiredNumberOfEndpoints)
{
return KErrHardwareNotAvailable;
}
// Endpoint caps
TUsbcEndpointData data[KUsbcMaxEndpoints];
TPtr8 dataptr(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data));
ret = iLdd.EndpointCaps(dataptr);
if (ret != KErrNone)
{
return ret;
}
// Set the active interface
TUsbcScInterfaceInfoBuf ifc;
TInt ep_found = 0;
TBool foundBulkIN = EFalse;
TBool foundBulkOUT = EFalse;
for (TInt i = 0; i < totalEndpoints ; i++)
{
const TUsbcEndpointCaps* caps = &data[i].iCaps;
const TInt maxPacketSize = caps->MaxPacketSize();
if (!foundBulkIN &&
(caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirIn)) == (KUsbEpTypeBulk | KUsbEpDirIn))
{
// InEndpoint is going to be our TX (IN, write) endpoint
ifc().iEndpointData[0].iType = KUsbEpTypeBulk;
if((d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_EndpointResourceAllocV2) == KUsbDevCapsFeatureWord1_EndpointResourceAllocV2)
ifc().iEndpointData[0].iFeatureWord1 = KUsbcEndpointInfoFeatureWord1_DMA|KUsbcEndpointInfoFeatureWord1_DoubleBuffering;
ifc().iEndpointData[0].iDir = KUsbEpDirIn;
ifc().iEndpointData[0].iSize = maxPacketSize;
ifc().iEndpointData[0].iInterval_Hs = 0;
ifc().iEndpointData[0].iBufferSize = KMaxScBufferSize;
foundBulkIN = ETrue;
if (++ep_found == KRequiredNumberOfEndpoints)
{
break;
}
continue;
}
if (!foundBulkOUT &&
(caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirOut)) == (KUsbEpTypeBulk | KUsbEpDirOut))
{
// OutEndpoint is going to be our RX (OUT, read) endpoint
ifc().iEndpointData[1].iType = KUsbEpTypeBulk;
if((d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_EndpointResourceAllocV2) == KUsbDevCapsFeatureWord1_EndpointResourceAllocV2)
ifc().iEndpointData[1].iFeatureWord1 = KUsbcEndpointInfoFeatureWord1_DMA|KUsbcEndpointInfoFeatureWord1_DoubleBuffering;
ifc().iEndpointData[1].iDir = KUsbEpDirOut;
ifc().iEndpointData[1].iSize = maxPacketSize;
ifc().iEndpointData[1].iInterval_Hs = 0;
ifc().iEndpointData[1].iBufferSize = KMaxScBufferSize;
ifc().iEndpointData[1].iReadSize = KMaxScReadSize;
foundBulkOUT = ETrue;
if (++ep_found == KRequiredNumberOfEndpoints)
{
break;
}
continue;
}
}
if (ep_found != KRequiredNumberOfEndpoints)
{
return KErrHardwareNotAvailable;
}
_LIT16(string, "USB Mass Storage Interface");
ifc().iString = const_cast<TDesC16*>(&string);
ifc().iTotalEndpointsUsed = KRequiredNumberOfEndpoints;
ifc().iClass.iClassNum = 0x08; // Mass Storage
ifc().iClass.iSubClassNum = 0x06; // SCSI Transparent Command Set
ifc().iClass.iProtocolNum = 0x50; // Bulk Only Transport
if (d_caps().iHighSpeed)
{
// Tell the Protocol about it, because it might want to do some
// optimizing too.
iProtocol->ReportHighSpeedDevice();
}
if ((ret = iLdd.SetInterface(0, ifc)) == KErrNone)
{
return (iLdd.FinalizeInterface(iChunk));
}
return ret;
}
void CBulkOnlyTransportUsbcScLdd::ReleaseInterface()
{
iLdd.ReleaseInterface(0);
}
TInt CBulkOnlyTransportUsbcScLdd::StartControlInterface()
{
return iControlInterface->Start();
}
void CBulkOnlyTransportUsbcScLdd::CancelControlInterface()
{
iControlInterface->Cancel();
}
void CBulkOnlyTransportUsbcScLdd::ActivateDeviceStateNotifier()
{
iDeviceStateNotifier->Activate();
}
void CBulkOnlyTransportUsbcScLdd::CancelDeviceStateNotifier()
{
iDeviceStateNotifier->Cancel();
}
void CBulkOnlyTransportUsbcScLdd::CancelReadWriteRequests()
{
__FNLOG("CBulkOnlyTransportUsbcScLdd::CancelReadWriteRequests");
TUsbcScChunkHeader chunkHeader(*iChunk);
for (TInt i = 0; i < chunkHeader.iAltSettings->iNumOfAltSettings; i++)
{
TInt8* endpoint = (TInt8*) (chunkHeader.iAltSettings->iAltTableOffset[i] + (TInt) iChunk->Base());
TInt numOfEps = chunkHeader.GetNumberOfEndpoints(i);
__ASSERT_DEBUG(numOfEps >= 0, User::Invariant());
for (TInt j = 1; j <= numOfEps; j++)
{
TUsbcScHdrEndpointRecord* endpointInf = (TUsbcScHdrEndpointRecord*) &(endpoint[j * chunkHeader.iAltSettings->iEpRecordSize]);
if (endpointInf->Direction() == KUsbScHdrEpDirectionOut)
{
iLdd.ReadCancel(endpointInf->iBufferNo);
}
if (endpointInf->Direction() == KUsbScHdrEpDirectionIn)
{
iLdd.WriteCancel(endpointInf->iBufferNo);
}
}
}
}
void CBulkOnlyTransportUsbcScLdd::AllocateEndpointResources()
{
TUsbcScChunkHeader chunkHeader(*iChunk);
for (TInt i = 0; i < chunkHeader.iAltSettings->iNumOfAltSettings; i++)
{
TInt8* endpoint = (TInt8*) (chunkHeader.iAltSettings->iAltTableOffset[i] + (TInt) iChunk->Base());
for (TInt j = 1; j <= chunkHeader.GetNumberOfEndpoints(i); j++)
{
TUsbcScHdrEndpointRecord* endpointInf = (TUsbcScHdrEndpointRecord*) &(endpoint[j * chunkHeader.iAltSettings->iEpRecordSize]);
if (endpointInf->Direction() == KUsbScHdrEpDirectionOut)
{
iOutEndpoint = j;
}
if (endpointInf->Direction() == KUsbScHdrEpDirectionIn)
{
iInEndpoint = j;
}
}
}
TUsbDeviceCaps d_caps;
TInt err;
TInt ret = iLdd.DeviceCaps(d_caps);
if (ret == KErrNone)
{
if((d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_EndpointResourceAllocV2) != KUsbDevCapsFeatureWord1_EndpointResourceAllocV2)
{
__PRINT(_L("CBulkOnlyTransportUsbcScLdd::Start - Setting up DMA and double buffering\n"));
// Set up DMA if possible (errors are non-critical)
err = iLdd.AllocateEndpointResource(iOutEndpoint, EUsbcEndpointResourceDMA);
if (err != KErrNone)
{
__PRINT1(_L("Set DMA on OUT endpoint failed with error code: %d"), err);
}
err = iLdd.AllocateEndpointResource(iInEndpoint, EUsbcEndpointResourceDMA);
if (err != KErrNone)
{
__PRINT1(_L("Set DMA on IN endpoint failed with error code: %d"), err);
}
// Set up Double Buffering if possible (errors are non-critical)
err = iLdd.AllocateEndpointResource(iOutEndpoint, EUsbcEndpointResourceDoubleBuffering);
if (err != KErrNone)
{
__PRINT1(_L("Set Double Buffering on OUT endpoint failed with error code: %d"), err);
}
err = iLdd.AllocateEndpointResource(iInEndpoint, EUsbcEndpointResourceDoubleBuffering);
if (err != KErrNone)
{
__PRINT1(_L("Set Double Buffering on IN endpoint failed with error code: %d"), err);
}
}
}
err = OpenEndpoints();
}
TInt CBulkOnlyTransportUsbcScLdd::OpenEndpoints()
{
TInt res = iLdd.OpenEndpoint(iSCReadEndpointBuf, iOutEndpoint);
if (res == KErrNone)
{
res = iLdd.OpenEndpoint(iSCWriteEndpointBuf, iInEndpoint);
if (res == KErrNone)
{
iSCWriteEndpointBuf.GetInBufferRange((TAny*&)iDataPtr, iInBufferLength);
res = iControlInterface->OpenEp0();
}
return res;
}
return res;
}
TInt CBulkOnlyTransportUsbcScLdd::GetDeviceStatus(TUsbcDeviceState& deviceStatus)
{
return iLdd.DeviceStatus(deviceStatus);
}
void CBulkOnlyTransportUsbcScLdd::FlushData()
{
// Intentionally Left Blank Do Nothing
}
/**
* Read out rest data from OutEndpoint and discard them
*/
void CBulkOnlyTransportUsbcScLdd::ReadAndDiscardData(TInt /*aBytes*/)
{
__FNLOG("CBulkOnlyTransport::ReadAndDiscardData");
TRequestStatus status;
TInt r = KErrNone; // Lets assume there is no data
do
{
iSCReadSize = 0;
status = KErrNone;
r = iSCReadEndpointBuf.TakeBuffer(iSCReadData,iSCReadSize,iReadZlp,status);
iSCReadEndpointBuf.Expire();
}
while (r == KErrCompletion);
if (r == KErrNone)
{
TRequestStatus* stat = &status;
User::RequestComplete(stat, KErrNone);
}
}
/**
Called by the protocol to determine how many bytes of data are available in the read buffer.
@return The number of bytes available in the read buffer
*/
TInt CBulkOnlyTransportUsbcScLdd::BytesAvailable()
{
// Intentionally Left Blank Do Nothing
return 0;
}
void CBulkOnlyTransportUsbcScLdd::StallEndpointAndWaitForClear()
{
__FNLOG("CBulkOnlyTransportUsbcScLdd::StallEndpointAndWaitForClear");
// Now stall this endpoint
__PRINT1(_L("Stalling endpoint %d"), iInEndpoint);
TInt r = iLdd.HaltEndpoint(iInEndpoint);
if (r != KErrNone)
{
__PRINT2(_L("Error: stalling ep %d failed: %d"), iInEndpoint, r);
}
TEndpointState ep_state;
TInt i = 0;
do
{
// Wait for 10ms before checking the ep status
User::After(10000);
iLdd.EndpointStatus(iInEndpoint, ep_state);
if (++i >= 550)
{
// 5.5 secs should be enough (see 9.2.6.1 Request Processing Timing)
__PRINT1(_L("Error: Checked for ep %d de-stall for 5.5s - giving up now"), iInEndpoint);
// We can now only hope for a Reset Recovery
return;
}
} while ((ep_state == EEndpointStateStalled) && iStarted);
__PRINT2(_L("Checked for ep %d de-stall: %d time(s)"), iInEndpoint, i);
}
/**
Read CBW data from the host and decode it.
*/
void CBulkOnlyTransportUsbcScLdd::ReadCBW()
{
__FNLOG("CBulkOnlyTransportUsbcScLdd::ReadCBW");
if (IsActive())
{
__PRINT(_L("Still active\n"));
__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
return;
}
TInt r = KErrNone;
do
{
r = ReadUsb();
if ((r == KErrCompletion) && (iSCReadSize == KCbwLength))
{
iCurrentState = EWaitForCBW;
iStatus = KErrNone;
DecodeCBW();
iSCReadSize = 0;
}
else if (r == KErrNone)
{
iCurrentState = EWaitForCBW;
SetActive();
}
else if ((r == KErrCompletion) && (iSCReadSize != KCbwLength))
{
ExpireData(iSCReadData);
}
}while ((r == KErrCompletion) && (!IsActive()));
}
void CBulkOnlyTransportUsbcScLdd::ExpireData(TAny* aAddress)
{
if (aAddress)
{
iSCReadEndpointBuf.Expire(aAddress);
}
else
{
iSCReadEndpointBuf.Expire();
}
}
void CBulkOnlyTransportUsbcScLdd::ProcessCbwEvent()
{
ReadCBW();
}
/**
Request data form the host for the protocol
@param aLength amount of data (in bytes) to be received from the host
*/
void CBulkOnlyTransportUsbcScLdd::ReadData(TUint /*aLength*/)
{
__FNLOG("CBulkOnlyTransportUsbcScLdd::ReadData");
if (IsActive())
{
__PRINT(_L("Still active\n"));
__ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive));
return;
}
TInt r = KErrNone;
do
{
r = ReadUsb();
iCurrentState = EReadingData;
if (r == KErrCompletion)
{
iReadBufPtr.Set((TUint8*) iSCReadData, iSCReadSize, iSCReadSize);
iStatus = KErrNone;
ProcessDataFromHost();
iSCReadSize = 0;
}
else if (r == KErrNone)
{
iSCReadSize = 0;
SetActive();
}
}while ((r == KErrCompletion) && (!IsActive()));
}
void CBulkOnlyTransportUsbcScLdd::ProcessDataFromHost()
{
TInt ret = KErrNone;
{
if (iReadSetUp)
{
ret = iProtocol->ReadComplete(KErrNone);
}
#ifndef MSDC_MULTITHREADED
ExpireData(iSCReadData);
#endif
TUint deviceDataLength = iSCReadSize; // What was written to the disk // static_cast<TUint>(iReadBuf.Length());
if(ret == KErrCompletion)
{
// The protocol has indicated with KErrCompletion that sufficient
// data is available in the buffer to process the transfer immediately.
//iDataResidue is initially set to host data length as we do not know how much data is there in the 'LDD transfer'.
//After a TakeBuffer call, iSCReadSize in updated and set to deviceDataLength
iDataResidue -= deviceDataLength;
}
else
{
iDataResidue -= deviceDataLength;
// The protocol has indicated that transfer is
// complete, so send the CSW response to the host.
iReadSetUp = EFalse;
if (ret != KErrNone)
{
iCmdStatus = ECommandFailed;
}
if (iDataResidue)
{
__PRINT(_L("Discarding residue"));
// we have to read as much data as available that host PC sends;
// otherwise, bulk-out endpoint will need to keep sending NAK back.
ReadAndDiscardData(iDataResidue);
}
SendCSW(iCbwTag, iDataResidue, iCmdStatus);
}
}
}
void CBulkOnlyTransportUsbcScLdd::WriteUsb(TRequestStatus& aStatus, TPtrC8& aDes, TUint aLength, TBool aZlpRequired)
{
TUint aOffset = (TUint) aDes.Ptr() - (TUint) iChunk->Base();
iSCWriteEndpointBuf.WriteBuffer(aOffset, aLength, aZlpRequired, aStatus);
}
void CBulkOnlyTransportUsbcScLdd::SetCbwPtr()
{
iCbwBufPtr.Set((TUint8*)iSCReadData, iSCReadSize);
}
TPtr8& CBulkOnlyTransportUsbcScLdd::SetCommandBufPtr(TUint aLength)
{
TPtr8 writeBuf((TUint8*) iDataPtr, aLength);
iCommandBufPtr.Set(writeBuf);
return iCommandBufPtr;
}
void CBulkOnlyTransportUsbcScLdd::SetReadDataBufPtr(TUint /*aLength*/)
{
// Do nothing for now
}
TPtr8& CBulkOnlyTransportUsbcScLdd::SetDataBufPtr()
{
TPtr8 writeBuf((TUint8*) iDataPtr, iInBufferLength);
iDataBufPtr.Set(writeBuf);
return iDataBufPtr;
}
void CBulkOnlyTransportUsbcScLdd::SetPaddingBufPtr(TUint aLength)
{
TPtr8 writeBuf((TUint8*) iDataPtr, aLength, aLength);
iPaddingBufPtr.Set(writeBuf);
}
void CBulkOnlyTransportUsbcScLdd::SetCswBufPtr(TUint aLength)
{
TPtr8 writeBuf((TUint8*) iDataPtr, aLength, aLength);
iCswBufPtr.Set(writeBuf);
}
void CBulkOnlyTransportUsbcScLdd::ProcessReadingDataEvent()
{
ReadData();
}
TInt CBulkOnlyTransportUsbcScLdd::ReadUsb(TUint /*aLength*/)
{
__FNLOG("CBulkOnlyTransportUsbcScLdd::ReadUSB");
return iSCReadEndpointBuf.TakeBuffer(iSCReadData,iSCReadSize,iReadZlp,iStatus);
}
void CBulkOnlyTransportUsbcScLdd::DiscardData(TUint aLength)
{
TUint c = 0;
TRequestStatus status;
TInt r = KErrNone;
while (c < aLength)
{
iSCReadSize = 0;
status = KErrNone;
r = iSCReadEndpointBuf.TakeBuffer(iSCReadData,iSCReadSize,iReadZlp,status);
c += iSCReadSize;
if (r == KErrNone)
User::WaitForRequest(status);
if (r == KErrCompletion)
{
iSCReadEndpointBuf.Expire();
}
iSCReadSize = 0;
}
}
void CBulkOnlyTransportUsbcScLdd::WriteToClient(TUint aLength)
{
TUint c = 0;
TRequestStatus status;
TInt r = KErrNone;
while (c < aLength)
{
iSCReadSize = 0;
status = KErrNone;
r = iSCReadEndpointBuf.TakeBuffer(iSCReadData,iSCReadSize,iReadZlp,status);
c += iSCReadSize;
iProtocol->ReadComplete(KErrGeneral);
if (r == KErrNone)
User::WaitForRequest(status);
if (r == KErrCompletion)
{
iSCReadEndpointBuf.Expire();
}
iSCReadSize = 0;
}
}
#ifdef MSDC_MULTITHREADED
void CBulkOnlyTransportUsbcScLdd::GetBufferPointers(TPtr8& aDes1, TPtr8& aDes2)
{
//for DB
TUint length = (TUint) (iInBufferLength - KCswBufferSize) / 2;
TUint8* start = (TUint8*) (iDataPtr) + KCswBufferSize ; // 'first' buffer
aDes1.Set(start, length, length);
start = (TUint8*) (iDataPtr) + KCswBufferSize + length; // 'second' buffer
aDes2.Set(start, length, length);
}
#endif
void CBulkOnlyTransportUsbcScLdd::Activate(TRequestStatus& aStatus, TUint& aDeviceState)
{
iLdd.AlternateDeviceStatusNotify(aStatus, aDeviceState);
}
void CBulkOnlyTransportUsbcScLdd::Cancel()
{
iLdd.AlternateDeviceStatusNotifyCancel();
}