diff -r 000000000000 -r a41df078684a userlibandfileserver/fileserver/smassstorage/cbulkonlytransportusbcldd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/smassstorage/cbulkonlytransportusbcldd.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,830 @@ +/* +* 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 "usbmsshared.h" +#include "massstoragedebug.h" +#include "cusbmassstorageserver.h" + +#define InEndpoint EEndpoint1 +#define OutEndpoint EEndpoint2 + +//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; + +//////////////////////////////////// +/** +Called by CBulkOnlyTransportUsbcLdd to create an instance of CControlInterfaceUsbcLdd + +@param aParent reference to the CBulkOnlyTransportUsbcLdd +*/ + + +CControlInterfaceUsbcLdd* CControlInterfaceUsbcLdd::NewL(CBulkOnlyTransportUsbcLdd& aParent) + { + CControlInterfaceUsbcLdd* self = new(ELeave) CControlInterfaceUsbcLdd(aParent); + CleanupStack::PushL(self); + self->ConstructL(); + CActiveScheduler::Add(self); + CleanupStack::Pop(); + return self; + } + + +void CControlInterfaceUsbcLdd::ConstructL() + { + } + + +/** +c'tor + +@param aParent reference to the CBulkOnlyTransportUsbcLdd +*/ +CControlInterfaceUsbcLdd::CControlInterfaceUsbcLdd(CBulkOnlyTransportUsbcLdd& aParent) + :CActive(EPriorityStandard), + iParent(aParent), + iCurrentState(ENone) + { + } + + +/** +d'tor +*/ +CControlInterfaceUsbcLdd::~CControlInterfaceUsbcLdd() + { + __FNLOG("CControlInterfaceUsbcLdd::~CControlInterfaceUsbcLdd "); + Cancel(); + } + + +/** +Called by CBulkOnlyTransport HwStart to start control interface +*/ +TInt CControlInterfaceUsbcLdd::Start() + { + __FNLOG("CControlInterfaceUsbcLdd::Start "); + TInt res = ReadEp0Data(); + return (res); + } + + +/** +Called by desctructor of CBulkOnlyTransportUsbcLdd to stop control interface +*/ +void CControlInterfaceUsbcLdd::Stop() + { + __FNLOG("CControlInterfaceUsbcLdd::Stop "); + if (!IsActive()) + { + __PRINT(_L("Not active\n")); + return; + } + + __PRINT(_L("\nStopping...\n")); + + + iCurrentState = ENone; + + Cancel(); + } + + +/** +Cancel outstanding request (if any) +*/ +void CControlInterfaceUsbcLdd::DoCancel() + { + __FNLOG("CControlInterfaceUsbcLdd::DoCancel "); + switch(iCurrentState) + { + case EReadEp0Data: + iParent.Ldd().ReadCancel(EEndpoint0); + break; + case ESendMaxLun: + iParent.Ldd().WriteCancel(EEndpoint0); + break; + default: + __PRINT(_L("\nWrong state !\n")); + __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceBadState)); + } + } + + +/** +Implement CControlInterfaceUsbcLdd state machine +*/ +void CControlInterfaceUsbcLdd::RunL() + { + __FNLOG("CControlInterfaceUsbcLdd::RunL "); + if (iStatus != KErrNone) + { + __PRINT1(_L("Error %d in RunL\n"), iStatus.Int()); + + //read EP0 again + ReadEp0Data(); + return; + } + + switch (iCurrentState) + { + case ESendMaxLun: + ReadEp0Data(); + break; + + case EReadEp0Data: + DecodeEp0Data(); + break; + + default: + __PRINT(_L(" error: (Shouldn't end up here...)\n")); + __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceBadState)); + break; + } + return; + } + + +/** +Post a read request to EEndpoint0 to read request header +*/ +TInt CControlInterfaceUsbcLdd::ReadEp0Data() + { + __FNLOG("CControlInterfaceUsbcLdd::ReadEp0Data "); + if (IsActive()) + { + __PRINT(_L("Still active\n")); + return KErrServerBusy; + } + iParent.Ldd().Read(iStatus, EEndpoint0, iData, KRequestHdrSize); + + iCurrentState = EReadEp0Data; + + SetActive(); + return KErrNone; + } + + +/** +Decode request header and do appropriate action - get max LUN info or post a reset request +*/ +void CControlInterfaceUsbcLdd::DecodeEp0Data() + { + __FNLOG("CControlInterfaceUsbcLdd::DecodeEp0Data "); + if (IsActive()) + { + __PRINT(_L("Still active\n")); + __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsControlInterfaceStillActive)); + return; + } + + TInt err = iRequestHeader.Decode(iData); + + 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; + } + iData.FillZ(1); //Return only 1 byte to host + iData[0] = static_cast(iParent.MaxLun()); // Supported Units + iParent.Ldd().Write(iStatus, EEndpoint0, iData, 1); + + 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 CBulkOnlyTransportUsbcLdd --------------------------------------------------------- +// + +CBulkOnlyTransportUsbcLdd::CBulkOnlyTransportUsbcLdd(TInt aNumDrives,CUsbMassStorageController& aController) + :CBulkOnlyTransport(aNumDrives, aController), + iSwap(ETrue) + { + __FNLOG("CBulkOnlyTransportUsbcLdd::CBulkOnlyTransportUsbcLdd"); + } + +/** +Constructs the CBulkOnlyTransportUsbcLdd object +*/ +void CBulkOnlyTransportUsbcLdd::ConstructL() + { + __FNLOG("CBulkOnlyTransportUsbcLdd::ConstructL()"); + iControlInterface = CControlInterfaceUsbcLdd::NewL(*this); + iDeviceStateNotifier = CActiveDeviceStateNotifierBase::NewL(*this, *this); + CActiveScheduler::Add(this); + } + +CBulkOnlyTransportUsbcLdd::~CBulkOnlyTransportUsbcLdd() + { + __FNLOG("CBulkOnlyTransportUsbcLdd::~CBulkOnlyTransportUsbcLdd"); + if (iInterfaceConfigured) + { + delete iControlInterface ; + delete iDeviceStateNotifier; + } + } + +RDevUsbcClient& CBulkOnlyTransportUsbcLdd::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 CBulkOnlyTransportUsbcLdd::SetupConfigurationDescriptor(TBool aUnset) + { + __FNLOG("CBulkOnlyTransportUsbcLdd::SetupConfigurationDescriptor"); + TInt ret(KErrNone); + + if ((ret = iLdd.Open(0)) != KErrNone) + return ret; + + TInt configDescriptorSize(0); + iLdd.GetConfigurationDescriptorSize(configDescriptorSize); + if (static_cast(configDescriptorSize) != KUsbDescSize_Config) + { + return KErrCorrupt; + } + + TBuf8 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 CBulkOnlyTransportUsbcLdd::SetupInterfaceDescriptors() + { + __FNLOG("CBulkOnlyTransportUsbcLdd::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(data), sizeof(data), sizeof(data)); + ret = iLdd.EndpointCaps(dataptr); + if (ret != KErrNone) + { + return ret; + } + + // Set the active interface + TUsbcInterfaceInfoBuf 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; + ifc().iEndpointData[0].iDir = KUsbEpDirIn; + ifc().iEndpointData[0].iSize = maxPacketSize; + ifc().iEndpointData[0].iInterval_Hs = 0; + 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; + ifc().iEndpointData[1].iDir = KUsbEpDirOut; + ifc().iEndpointData[1].iSize = maxPacketSize; + ifc().iEndpointData[1].iInterval_Hs = 0; + foundBulkOUT = ETrue; + if (++ep_found == KRequiredNumberOfEndpoints) + { + break; + } + continue; + } + } + if (ep_found != KRequiredNumberOfEndpoints) + { + return KErrHardwareNotAvailable; + } + + _LIT16(string, "USB Mass Storage Interface"); + ifc().iString = const_cast(&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 + + TUint bandwidth_priority = (EUsbcBandwidthOUTDefault | EUsbcBandwidthINDefault); + if (d_caps().iHighSpeed) + { + // If this device supports USB High-speed, then we request 64KB buffers + // (otherwise the default 4KB ones will do). + bandwidth_priority = (EUsbcBandwidthOUTPlus2 | EUsbcBandwidthINPlus2); + // Also, tell the Protocol about it, because it might want to do some + // optimizing too. + iProtocol->ReportHighSpeedDevice(); + } + ret = iLdd.SetInterface(0, ifc, bandwidth_priority); + return ret; + } + +void CBulkOnlyTransportUsbcLdd::ReleaseInterface() + { + iLdd.ReleaseInterface(0); + } + +TInt CBulkOnlyTransportUsbcLdd::StartControlInterface() + { + return iControlInterface->Start(); + } + +void CBulkOnlyTransportUsbcLdd::CancelControlInterface() + { + iControlInterface->Cancel(); + } + +void CBulkOnlyTransportUsbcLdd::ActivateDeviceStateNotifier() + { + iDeviceStateNotifier->Activate(); + } + +void CBulkOnlyTransportUsbcLdd::CancelDeviceStateNotifier() + { + iDeviceStateNotifier->Cancel(); + } + +void CBulkOnlyTransportUsbcLdd::CancelReadWriteRequests() + { + __FNLOG("CBulkOnlyTransportUsbcLdd::CancelReadWriteRequests"); + iLdd.WriteCancel(InEndpoint); + iLdd.ReadCancel(OutEndpoint); + } + +void CBulkOnlyTransportUsbcLdd::AllocateEndpointResources() + { + // Set up DMA if possible (errors are non-critical) + TInt err = iLdd.AllocateEndpointResource(OutEndpoint, EUsbcEndpointResourceDMA); + if (err != KErrNone) + { + __PRINT1(_L("Set DMA on OUT endpoint failed with error code: %d"), err); + } + err = iLdd.AllocateEndpointResource(InEndpoint, 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(OutEndpoint, EUsbcEndpointResourceDoubleBuffering); + if (err != KErrNone) + { + __PRINT1(_L("Set Double Buffering on OUT endpoint failed with error code: %d"), err); + } + err = iLdd.AllocateEndpointResource(InEndpoint, EUsbcEndpointResourceDoubleBuffering); + if (err != KErrNone) + { + __PRINT1(_L("Set Double Buffering on IN endpoint failed with error code: %d"), err); + } + } + +TInt CBulkOnlyTransportUsbcLdd::GetDeviceStatus(TUsbcDeviceState& deviceStatus) + { + return iLdd.DeviceStatus(deviceStatus); + } + +void CBulkOnlyTransportUsbcLdd::FlushData() + { + TInt bytes; + const TInt err = iLdd.QueryReceiveBuffer(OutEndpoint, bytes); + if (err != KErrNone || bytes <= 0) + { + __PRINT1(_L("Error: err=%d bytes=%d"), bytes); + } + else + { + __PRINT1(_L("RxBuffer has %d bytes"), bytes); + ReadAndDiscardData(bytes); + } + } +/** + * Read out rest data from OutEndpoint and discard them + */ +void CBulkOnlyTransportUsbcLdd::ReadAndDiscardData(TInt aBytes) + { + __FNLOG("CBulkOnlyTransportUsbcLdd::ReadAndDiscardData"); + iDiscardBuf.SetMax(); + const TUint bufsize = static_cast(iDiscardBuf.Length()); + TRequestStatus status; + while (aBytes > 0) + { + __PRINT1(_L("Bytes still to be read: %d\n"), aBytes); + iLdd.ReadOneOrMore(status, OutEndpoint, iDiscardBuf, bufsize); + User::WaitForRequest(status); + TInt err = status.Int(); + if (err != KErrNone) + { + // Bad. + break; + } + aBytes -= iDiscardBuf.Length(); + } + } + +/** +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 CBulkOnlyTransportUsbcLdd::BytesAvailable() + { + TInt bytes = 0; + TInt err = iLdd.QueryReceiveBuffer(OutEndpoint, bytes); + if (err != KErrNone) + bytes = 0; + return bytes; + } + + +void CBulkOnlyTransportUsbcLdd::StallEndpointAndWaitForClear() + { + __FNLOG("CBulkOnlyTransportUsbcLdd::StallEndpointAndWaitForClear"); + + // Now stall this endpoint + __PRINT1(_L("Stalling endpoint %d"), InEndpoint); + TInt r = iLdd.HaltEndpoint(InEndpoint); + if (r != KErrNone) + { + __PRINT2(_L("Error: stalling ep %d failed: %d"), InEndpoint, r); + } + TEndpointState ep_state; + TInt i = 0; + do + { + // Wait for 10ms before checking the ep status + User::After(10000); + iLdd.EndpointStatus(InEndpoint, 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"), InEndpoint); + // 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)"), InEndpoint, i); + } + + +/** +Read CBW data (KCbwLength) from the host into the read buffer. +*/ +void CBulkOnlyTransportUsbcLdd::ReadCBW() + { + __FNLOG("CBulkOnlyTransportUsbcLdd::ReadCBW"); + if (IsActive()) + { + __PRINT(_L("Still active\n")); + __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive)); + return; + } + + iCbwBuf.SetMax(); + iLdd.ReadUntilShort(iStatus, OutEndpoint, iCbwBuf, KCbwLength); + + iCurrentState = EWaitForCBW; + SetActive(); + } + +void CBulkOnlyTransportUsbcLdd::ExpireData(TAny* /*aAddress*/) + { + // Intentionally left blank + } + +void CBulkOnlyTransportUsbcLdd::ProcessCbwEvent() + { + DecodeCBW(); + } + + +/** +Request data form the host for the protocol + +@param aLength amount of data (in bytes) to be received from the host +*/ +void CBulkOnlyTransportUsbcLdd::ReadData(TUint aLength) + { + __FNLOG("CBulkOnlyTransportUsbcLdd::ReadData"); + if (IsActive()) + { + __PRINT(_L("Still active\n")); + __ASSERT_DEBUG(EFalse, User::Panic(KUsbMsSvrPncCat, EMsBulkOnlyStillActive)); + return; + } + + SetReadDataBufPtr(aLength); + iLdd.Read(iStatus, OutEndpoint, iReadBufPtr, aLength); + + iCurrentState = EReadingData; + SetActive(); + } + +void CBulkOnlyTransportUsbcLdd::WriteUsb(TRequestStatus& aStatus, TPtrC8& aDes, TUint aLength, TBool aZlpRequired) + { + iLdd.Write(aStatus, InEndpoint, aDes, aLength, aZlpRequired); + } + +void CBulkOnlyTransportUsbcLdd::SetCbwPtr() + { + iCbwBufPtr.Set(iCbwBuf.Ptr(), iCbwBuf.Length()); + } + +TPtr8& CBulkOnlyTransportUsbcLdd::SetCommandBufPtr(TUint aLength) + { + iCommandBufPtr.Set((TUint8*) iCommandBuf.Ptr(), aLength, aLength ); + return iCommandBufPtr; + } + +void CBulkOnlyTransportUsbcLdd::SetReadDataBufPtr(TUint aLength) //Write10(Host->Device + { + if (iSwap) + { + iDataBuf1.SetLength(aLength); + iReadBufPtr.Set(iDataBuf1.LeftTPtr(iDataBuf1.Length())); + iSwap = EFalse; + } + else + { + iDataBuf2.SetLength(aLength); + iReadBufPtr.Set(iDataBuf2.LeftTPtr(iDataBuf2.Length())); + iSwap = ETrue; + } + } + +TPtr8& CBulkOnlyTransportUsbcLdd::SetDataBufPtr() //Read10(Device->Host) + { + if (iSwap) + { + iDataBufPtr.Set((TUint8*) iDataBuf1.Ptr(), KMaxBufSize, KMaxBufSize); + iSwap = EFalse; + } + else + { + iDataBufPtr.Set((TUint8*) iDataBuf2.Ptr(), KMaxBufSize, KMaxBufSize); + iSwap = ETrue; + } + return iDataBufPtr; + } + +void CBulkOnlyTransportUsbcLdd::SetPaddingBufPtr(TUint aLength) + { + iPaddingBufPtr.Set((TUint8*) iBuf.Ptr(), aLength, aLength ); + } + + +void CBulkOnlyTransportUsbcLdd::SetCswBufPtr(TUint aLength) + { + iCswBufPtr.Set((TUint8*) iCswBuf.Ptr(), aLength, aLength ); + } + +void CBulkOnlyTransportUsbcLdd::ProcessReadingDataEvent() + { + TInt ret = KErrNone; + FOREVER + { + if (iReadSetUp) + { + ret = iProtocol->ReadComplete(KErrNone); + } + + TUint deviceDataLength = iBufSize; // This is the amount (maximum in case of SC Ldd) to be read next. + + if(ret == KErrCompletion) + { + // The protocol has indicated with KErrCompletion that sufficient + // data is available in the buffer to process the transfer immediately. + + iDataResidue -= iReadBufPtr.Length(); + SetReadDataBufPtr(deviceDataLength); + + iLdd.Read(iStatus, OutEndpoint, iReadBufPtr, deviceDataLength); + User::WaitForRequest(iStatus); + if (iStatus != KErrNone) + { + // An error occurred - halt endpoints for reset recovery + __PRINT1(_L("Error %d in EReadingData, halt endpoints \n"), iStatus.Int()); + SetPermError(); + return; + } + } + else if(ret == KErrNotReady) + { + // The protocol has indicated with KErrNotReady that insufficient + // data is available in the buffer, so should wait for it to arrive + + iDataResidue -= iReadBufPtr.Length(); + ReadData(deviceDataLength); + break; + } + else + { + // The protocol has indicated that transfer is + // complete, so send the CSW response to the host. + iDataResidue -= iReadBufPtr.Length(); + 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); + break; + } + } + + } + +void CBulkOnlyTransportUsbcLdd::DiscardData(TUint aLength) + { + iBuf.SetLength(KBOTMaxBufSize); + TUint c = 0; + TRequestStatus status; + while (c < aLength) + { + TInt len; + if (aLength - c > KBOTMaxBufSize) + { + len = KBOTMaxBufSize; + } + else + { + len = aLength - c; + } + + iLdd.Read(status, OutEndpoint, iBuf, len); + User::WaitForRequest(status); + c += KBOTMaxBufSize; + } + } + +void CBulkOnlyTransportUsbcLdd::WriteToClient(TUint aLength) + { + SetDataBufPtr(); + iLdd.Read(iStatus, OutEndpoint, iDataBufPtr, aLength); + User::WaitForRequest(iStatus); + iProtocol->ReadComplete(KErrGeneral); + } + +#ifdef MSDC_MULTITHREADED +void CBulkOnlyTransportUsbcLdd::GetBufferPointers(TPtr8& aDes1, TPtr8& aDes2) + { + aDes1.Set((TUint8*) iDataBuf1.Ptr(), KMaxBufSize, KMaxBufSize); + aDes2.Set((TUint8*) iDataBuf2.Ptr(), KMaxBufSize, KMaxBufSize); + } +#endif + +void CBulkOnlyTransportUsbcLdd::Activate(TRequestStatus& aStatus, TUint& aDeviceState) + { + iLdd.AlternateDeviceStatusNotify(aStatus, aDeviceState); + } + + +void CBulkOnlyTransportUsbcLdd::Cancel() + { + iLdd.AlternateDeviceStatusNotifyCancel(); + } + + + +