diff -r 000000000000 -r 96e5fb8b040d userlibandfileserver/fileserver/shostmassstorage/server/transport/cbulkonlytransport.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/userlibandfileserver/fileserver/shostmassstorage/server/transport/cbulkonlytransport.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,728 @@ +// Copyright (c) 2008-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 +#include +#include +#include +#include +#include +#ifdef MASSSTORAGE_PUBLISHER +#include +#endif +#include "botmsctypes.h" +#include "msctypes.h" +#include "mscutils.h" +#include "mtransport.h" +#include "mprotocol.h" +#include "cusbifacehandler.h" +#include "cbulkonlytransport.h" +#include "debug.h" +#include "msdebug.h" + +CBulkOnlyTransport::CBulkOnlyTransport() +: iBulkOutCbwTd(KCbwPacketSize), + iBulkDataTd(KResponsePacketSize), + iBulkInCswTd(KCswPacketSize) + { + __MSFNLOG + } + +CBulkOnlyTransport::~CBulkOnlyTransport() + { + __MSFNLOG + delete iUsbInterfaceHandler; + UnInitialiseTransport(); + iInterface.Close(); + } + +/** +Create CBulkOnlyTransport object. + +@param aInterfaceId The interface ID of the device + +@return CBulkOnlyTransport* Pointer to the created object +*/ +CBulkOnlyTransport* CBulkOnlyTransport::NewL(TUint aInterfaceId) + { + __MSFNSLOG + CBulkOnlyTransport* transport = new (ELeave) CBulkOnlyTransport(); + CleanupStack::PushL(transport); + transport->ConstructL(aInterfaceId); + CleanupStack::Pop(transport); + return transport; + } + + +void CBulkOnlyTransport::ConstructL(TUint aInterfaceId) + { + __MSFNSLOG + User::LeaveIfError(iInterface.Open(aInterfaceId)); + iUsbInterfaceHandler = CUsbInterfaceHandler::NewL(iInterface); + InitialiseTransport(); + } + + +void CBulkOnlyTransport::Resume() + { + __MSFNSLOG + __BOTPRINT(_L("BOT RESUME")); + + iInterface.CancelPermitSuspend(); + } + +void CBulkOnlyTransport::Suspend(TRequestStatus& aStatus) + { + __MSFNSLOG + __BOTPRINT(_L("BOT SUSPEND")); +// iInterface.PermitRemoteWakeup(ETrue); + iInterface.PermitSuspendAndWaitForResume(aStatus); + } + +TInt CBulkOnlyTransport::InitialiseTransport() + { + __MSFNLOG + TInt BulkOutEpAddr; + TInt BulkInEpAddr; + const TUint8 KEpDirectionIn = 0x80; + const TUint8 KEpDirectionOut = 0x00; + const TUint8 KTransferTypeBulk = 0x02; + + GetEndpointAddress(iInterface,0,KTransferTypeBulk,KEpDirectionOut,BulkOutEpAddr); + GetEndpointAddress(iInterface,0,KTransferTypeBulk,KEpDirectionIn,BulkInEpAddr); + iInterface.OpenPipeForEndpoint(iBulkPipeOut, BulkOutEpAddr, EFalse); + iInterface.OpenPipeForEndpoint(iBulkPipeIn, BulkInEpAddr, EFalse); + + if (iInterface.RegisterTransferDescriptor(iBulkOutCbwTd) != KErrNone || + iInterface.RegisterTransferDescriptor(iBulkDataTd) != KErrNone || + iInterface.RegisterTransferDescriptor(iBulkInCswTd) != KErrNone) + { + return KErrGeneral; + } + + if (iInterface.InitialiseTransferDescriptors() != KErrNone) + { + return KErrGeneral; + } + return KErrNone; + } + + +void CBulkOnlyTransport::UnInitialiseTransport() + { + __MSFNLOG + iBulkPipeOut.Close(); + iBulkPipeIn.Close(); + } + +TInt CBulkOnlyTransport::GetEndpointAddress(RUsbInterface& aUsbInterface, + TInt aInterfaceSetting, + TUint8 aTransferType, + TUint8 aDirection, + TInt& aEndpointAddress) + { + __MSFNLOG + TUsbInterfaceDescriptor alternateInterfaceDescriptor; + + if (aUsbInterface.GetAlternateInterfaceDescriptor(aInterfaceSetting, alternateInterfaceDescriptor)) + { + __BOTPRINT1(_L("GetEndpointAddress : Unable to get alternate interface (%x) descriptor"),aInterfaceSetting); + return KErrGeneral; + } + + TUsbGenericDescriptor* descriptor = alternateInterfaceDescriptor.iFirstChild; + + while (descriptor) + { + TUsbEndpointDescriptor* endpoint = TUsbEndpointDescriptor::Cast(descriptor); + if (endpoint) + { + if ((endpoint->Attributes() & aTransferType) == aTransferType) + { + // Found the endpoint address + if ( (endpoint->EndpointAddress() & 0x80) == aDirection) + { + aEndpointAddress = endpoint->EndpointAddress(); + __BOTPRINT(_L("GetEndpointAddress : Endpoint address found")); + return KErrNone; + } + } + } + descriptor = descriptor->iNextPeer; + } + + // Unable to find the endpoint address + __BOTPRINT(_L("GetEndpointAddress : Unable to find endpoint address matching the specified attributes")); + return KErrNotFound; + } + +void CBulkOnlyTransport::GetMaxLun(TLun* aMaxLun, const RMessage2& aMessage) + { + __MSFNLOG + iUsbInterfaceHandler->GetMaxLun(aMaxLun, aMessage); + } + +TInt CBulkOnlyTransport::Reset() + { + __MSFNLOG + RUsbInterface::TUsbTransferRequestDetails reqDetails; + _LIT8(KNullDesC8,""); + + reqDetails.iRequestType = 0x21; + reqDetails.iRequest = 0xFF; + reqDetails.iValue = 0x0000; + reqDetails.iIndex = 0x0000; + reqDetails.iFlags = 0x04; // Short transfer OK + + iInterface.Ep0Transfer(reqDetails, KNullDesC8, (TDes8 &) KNullDesC8, iStatus); + User::WaitForRequest(iStatus); + __BOTPRINT1(_L("BOT RESET[%d]"), iStatus.Int()); + + if (iStatus.Int() != KErrNone) + { + return KErrGeneral; + } + + return KErrNone; + } + +void CBulkOnlyTransport::DoResetRecovery() + { + __MSFNLOG + + __BOTPRINT(_L("BOT RESET RECOVERY")); +#ifdef MASSSTORAGE_PUBLISHER + TMsPublisher publisher(TMsPublisher::KBotResetProperty); +#endif + Reset(); + iBulkPipeIn.ClearRemoteStall(); + iBulkPipeOut.ClearRemoteStall(); + } + + +void CBulkOnlyTransport::SendCbwL(const MClientCommandServiceReq* aReq, + TBotCbw::TCbwDirection aDirection, + TUint32 aTransferLength) + { + __MSFNLOG + __BOTPRINT1(_L("Cbw Tag=0x%x"), iCbwTag); + + iCbw.SetTag(iCbwTag++); + iCbw.SetDataTransferLength(aTransferLength); + iCbw.SetDataTransferDirection(aDirection); + iCbw.SetLun(iLun); + + TPtr8 buf = iBulkOutCbwTd.WritableBuffer(); + iCbw.EncodeL(buf, aReq); + + iBulkOutCbwTd.SaveData(buf.Length()); + iBulkPipeOut.Transfer(iBulkOutCbwTd, iStatus); + User::WaitForRequest(iStatus); + + TInt r = iStatus.Int(); + if (r != KErrNone) + { + if (r == KErrUsbStalled) + { + __BOTPRINT(_L("Cbw: BulkOut stalled")); + DoResetRecovery(); + } + __BOTPRINT1(_L("Usb transfer error %d"),r); + User::Leave(KErrGeneral); + } + } + + +void CBulkOnlyTransport::ReceiveCswL() + { + __MSFNLOG + iBulkInCswTd.SaveData(KCswPacketSize); + iBulkPipeIn.Transfer(iBulkInCswTd, iStatus); + User::WaitForRequest(iStatus); + + TInt r = iStatus.Int(); + if (r != KErrNone) + { + if (r == KErrUsbStalled) + { + __BOTPRINT(_L("Csw: Clearing BulkIn stall")); + iBulkPipeIn.ClearRemoteStall(); + iBulkInCswTd.SaveData(KCswPacketSize); + iBulkPipeIn.Transfer(iBulkInCswTd, iStatus); + User::WaitForRequest(iStatus); +#ifdef MASSSTORAGE_PUBLISHER + TMsPublisher publisher(TMsPublisher::KStallProperty); +#endif + r = iStatus.Int(); + if (r == KErrUsbStalled) + { + __BOTPRINT(_L("Csw: BulkIn stalled")); + DoResetRecovery(); + } + } + // Handle other usb error and retry failures + if (r != KErrNone) + { + __BOTPRINT1(_L("Usb transfer error %d"), r); + User::Leave(KErrGeneral); + } + } + + TPtrC8 data = iBulkInCswTd.Buffer(); + r = iCsw.Decode(data); + if (r != KErrNone) + { + __BOTPRINT(_L("Csw: Invalid")); + DoResetRecovery(); + User::Leave(KErrGeneral); + } + } + + +TInt CBulkOnlyTransport::SendControlCmdL(const MClientCommandServiceReq* aCommand) + { + __MSFNLOG + SendCbwL(aCommand, TBotCbw::EDataOut, 0); + ReceiveCswL(); + return ProcessZeroTransferL(); + } + + +TInt CBulkOnlyTransport::SendControlCmdL(const MClientCommandServiceReq* aCommand, + MClientCommandServiceResp* aResp) + { + __MSFNLOG + + SendCbwL(aCommand, TBotCbw::EDataIn, aResp->DataLength()); + + if (aResp->DataLength() > KResponsePacketSize) + { + __BOTPRINT(_L("Control command response length not supported")); + User::Leave(KErrGeneral); + } + + iBulkDataTd.SaveData(KResponsePacketSize); + iBulkPipeIn.Transfer(iBulkDataTd, iStatus); + User::WaitForRequest(iStatus); + TInt r = iStatus.Int(); + if (r != KErrNone) + { + if (r != KErrUsbStalled) + { + __BOTPRINT1(_L("Usb transfer error %d"),r); + User::Leave(KErrGeneral); + } + __BOTPRINT(_L("SendControlCmdL ClearRemoteStall")); + iBulkPipeIn.ClearRemoteStall(); + ReceiveCswL(); + return KErrCommandStalled; + } + TPtrC8 data = iBulkDataTd.Buffer(); + + ReceiveCswL(); + + TUint32 dataReceived = 0; + r = ProcessInTransferL(dataReceived); + if (!r) + { + + if (dataReceived == 0) + { + __BOTPRINT1(_L("Warning: No data received"), dataReceived); + return KErrCommandNotSupported; + } + + TRAP(r, aResp->DecodeL(data)); + } + return r; + } + + +TInt CBulkOnlyTransport::SendDataRxCmdL(const MClientCommandServiceReq* aCommand, + TDes8& aCopyBuf, + TInt& aLen) + { + __MSFNLOG + + TInt r = KErrNone; + SendCbwL(aCommand, TBotCbw::EDataIn, aLen); + + // store initial length as data is appended to the buffer + TInt startPos = aCopyBuf.Length(); + + TInt len = aLen; + + while (len) + { + if(len > KResponsePacketSize) + iBulkDataTd.SaveData(KResponsePacketSize); + else + iBulkDataTd.SaveData(len); + iBulkPipeIn.Transfer(iBulkDataTd, iStatus); + User::WaitForRequest(iStatus); + + r = iStatus.Int(); + if (r != KErrNone) + { + if (r == KErrUsbStalled) + { + __BOTPRINT(_L("SendDataRxCmdL ClearRemoteStall")); + iBulkPipeIn.ClearRemoteStall(); +#ifdef MASSSTORAGE_PUBLISHER + TMsPublisher publisher(TMsPublisher::KStallProperty); +#endif + break; + } + DoResetRecovery(); + __BOTPRINT1(_L("Usb transfer error %d"),r); + User::Leave(KErrGeneral); + } + + TPtrC8 data = iBulkDataTd.Buffer(); + aCopyBuf.Append(data.Ptr(), data.Length()); + if(len > KResponsePacketSize) + len -= KResponsePacketSize; + else + len = 0; + } + + ReceiveCswL(); + TUint32 lenReceived = 0; + + r = ProcessInTransferL(lenReceived); + aLen = lenReceived; + aCopyBuf.SetLength(startPos + lenReceived); + + return r; + } + +TInt CBulkOnlyTransport::SendDataTxCmdL(const MClientCommandServiceReq* aCommand, + TDesC8& aData, + TUint aPos, + TInt& aLen) + { + __MSFNLOG + TInt r = KErrNone; + + SendCbwL(aCommand, TBotCbw::EDataOut, aLen); + + TInt len = aLen; + TInt length = 0; + iBulkDataTd.SetZlpStatus(RUsbTransferDescriptor::ESuppressZlp); + while (len) + { + TPtr8 senddata = iBulkDataTd.WritableBuffer(); + senddata.Append(aData.Ptr() + length + aPos, len > KResponsePacketSize? KResponsePacketSize : len); + + iBulkDataTd.SaveData(senddata.Length()); + iBulkPipeOut.Transfer(iBulkDataTd, iStatus); + User::WaitForRequest(iStatus); + + if (iStatus.Int() != KErrNone) + { + if (iStatus.Int() == KErrUsbStalled) + { + __BOTPRINT(_L("SendDataTxCmdL ClearRemoteStall")); + iBulkPipeOut.ClearRemoteStall(); +#ifdef MASSSTORAGE_PUBLISHER + TMsPublisher publisher(TMsPublisher::KStallProperty); +#endif + break; + } + DoResetRecovery(); + __BOTPRINT1(_L("Usb transfer error %d"), r); + User::Leave(KErrGeneral); + } + + if(len > KResponsePacketSize) + { + len -= KResponsePacketSize; + length += KResponsePacketSize; + } + else + { + length += len; + len = 0; + } + } + + ReceiveCswL(); + + TUint32 lenSent = 0; + r = ProcessOutTransferL(lenSent); + aLen = lenSent; + + return r; + } + + +TInt CBulkOnlyTransport::ProcessZeroTransferL() + { + __MSFNLOG + // process 13 cases + + __ASSERT_DEBUG(iCbw.iDirection == TBotCbw::EDataOut, User::Invariant()); + __ASSERT_DEBUG(iCbw.iDataTransferLength == 0, User::Invariant()); + + // Hn - Host expects no data transfers + if (!iCsw.IsValidCsw(iCbw.iTag)) + { + __BOTPRINT(_L("BOT CSW Invalid")); + DoResetRecovery(); + User::Leave(KErrGeneral); + } + if (!iCsw.IsMeaningfulCsw(iCbw.iDataTransferLength)) + { + __BOTPRINT(_L("BOT CSW not meaningful")); + DoResetRecovery(); + User::Leave(KErrGeneral); + } + + if (iCsw.iStatus == TBotCsw::EPhaseError) + { + // Case (2) or (3) + __BOTPRINT(_L("BOT Phase Error")); + // Reset Recovery + DoResetRecovery(); + User::Leave(KErrGeneral); + } + + if (iCsw.iDataResidue != 0) + { + // should not happen + __BOTPRINT(_L("BOT Residue is invalid!")); + // Reset Recovery + DoResetRecovery(); + User::Leave(KErrGeneral); + } + + // all ok if here + return (iCsw.iStatus == TBotCsw::ECommandPassed) ? KErrNone : KErrCommandFailed; + } + + +TInt CBulkOnlyTransport::ProcessInTransferL(TUint32& aDataReceived) + { + __MSFNLOG + aDataReceived = 0; + // process 13 cases + + __ASSERT_DEBUG(iCbw.iDirection == TBotCbw::EDataIn, User::Invariant()); + + // Hi - Host expects to receive data from the device + if (!iCsw.IsValidCsw(iCbw.iTag)) + { + __BOTPRINT(_L("BOT CSW Invalid")); + DoResetRecovery(); + User::Leave(KErrGeneral); + } + if (!iCsw.IsMeaningfulCsw(iCbw.iDataTransferLength)) + { + __BOTPRINT(_L("BOT CSW not meaningful")); + DoResetRecovery(); + User::Leave(KErrGeneral); + } + + + if (iCsw.iStatus == TBotCsw::EPhaseError) + { + __BOTPRINT(_L("BOT Phase Error")); + // Case (7) or (8) + // Reset Recovery + DoResetRecovery(); + User::Leave(KErrGeneral); + } + + // all ok if here + // Case (4), (5) or (6) + aDataReceived = iCbw.iDataTransferLength - iCsw.iDataResidue; + return (iCsw.iStatus == TBotCsw::ECommandPassed) ? KErrNone : KErrCommandFailed; + } + + +TInt CBulkOnlyTransport::ProcessOutTransferL(TUint32& aDataReceived) + { + __MSFNLOG + aDataReceived = 0; + // process 13 cases + + __ASSERT_DEBUG(iCbw.iDirection == TBotCbw::EDataOut, User::Invariant()); + + // Ho - Host expects to send data to the device + if (!iCsw.IsValidCsw(iCbw.iTag)) + { + __BOTPRINT(_L("BOT CSW Invalid")); + DoResetRecovery(); + User::Leave(KErrGeneral); + } + if (!iCsw.IsMeaningfulCsw(iCbw.iDataTransferLength)) + { + __BOTPRINT(_L("BOT CSW not meaningful")); + DoResetRecovery(); + User::Leave(KErrGeneral); + } + + if (iCsw.iStatus == TBotCsw::EPhaseError) + { + __BOTPRINT(_L("BOT Phase Error")); + // Case (10) or (13) + // Reset Recovery + DoResetRecovery(); + User::Leave(KErrGeneral); + } + + // all ok if here + // Case (9), (11) or (12) + aDataReceived = iCbw.iDataTransferLength - iCsw.iDataResidue; + return (iCsw.iStatus == TBotCsw::ECommandPassed) ? KErrNone : KErrCommandFailed; + } + + +void CBulkOnlyTransport::SetLun(TLun aLun) + { + __MSFNLOG + iLun = aLun; + __BOTPRINT1(_L("CBulkOnlyTransport::SetLun(%d)"), aLun) + } + + +/** +Encode CBW into the supplied buffer. The command is also encoded using the +supplied encoding method of MClientCommandServiceReq. + +@param aBuffer The buffer to copy the encoded stream in to +@param aCommand The command to be encoded into the Command Block field +*/ +void TBotCbw::EncodeL(TPtr8 &aBuffer, const MClientCommandServiceReq* aCommand) const + { + __MSFNSLOG + aBuffer.SetLength(KCbwLength); + + TPtr8 commandBlock = aBuffer.MidTPtr(TBotCbw::KCbwCbOffset); + + aBuffer.FillZ(); + + TInt cbLength = aCommand->EncodeRequestL(commandBlock); + + TUint8* ptr = (TUint8 *) aBuffer.Ptr(); + LittleEndian::Put32(&ptr[KCbwSignatureOffset], 0x43425355); + LittleEndian::Put32(&ptr[KCbwTagOffset], iTag); + LittleEndian::Put32(&ptr[KCbwDataTransferLengthOffset], iDataTransferLength); + aBuffer[KCbwFlagOffset] = (iDirection == EDataOut) ? 0x00 : 0x80; + aBuffer[KCbwLunOffset] = iLun; + aBuffer[KCbwCbLengthOffset] = cbLength; + __BOTPRINT1(_L("BOT TBotCbw::Encode Lun=%d"), iLun); + } + + +/** +Decode stream into TBotCsw. + +@param aPtr A buffer containing CSW stream +*/ +TInt TBotCsw::Decode(const TDesC8& aPtr) + { + __MSFNLOG + if (aPtr.Length() != KCswLength) + { + __BOTPRINT1(_L("Invalid CSW length %d"), aPtr.Length()); + return KErrGeneral; + } + + iSignature = LittleEndian::Get32(&aPtr[KCswSignatureOffset]); + iTag = LittleEndian::Get32(&aPtr[KCswTagOffset]); + iDataResidue = LittleEndian::Get32(&aPtr[KCswDataResidueOffset]); + + TInt status = aPtr[KCswStatusOffset]; + iStatus = static_cast(status); + __BOTPRINT1(_L("BOT CSW Status = %d"), iStatus); + return KErrNone; + } + + +/** +Checks that CSW contents are valid, USB Mass Storage Class Bulk-Only +Transport 6.3. + +@param aTag The tag value received from the device + +@return TBool Return ETrue if valid else EFalse +*/ +TBool TBotCsw::IsValidCsw(TUint32 aTag) const + { + __MSFNSLOG + if (iSignature != 0x53425355) + { + return EFalse; + } + if (iTag != aTag) + { + return EFalse; + } + return ETrue; + } + + +/** +Checks that CSW contents are meaningful, USB Mass Storage Class Bulk-Only +Transport 6.3. + +@param aTransferLength Number of bytes transferred + +@return TBool Return ETrue if meaningful else EFalse +*/ +TBool TBotCsw::IsMeaningfulCsw(TUint32 aTransferLength) const + { + __MSFNSLOG + if (iStatus != EPhaseError) + { + if (iDataResidue > aTransferLength) + { + return EFalse; + } + } + return ETrue; + } + +#ifdef MASSSTORAGE_PUBLISHER +TMsPublisher::TMsPublisher(TPropertyKeys aKey) + { + RProperty prop; + + const TUid KUidHostMassStorageCategory = {KMyUid}; + + TInt ret = prop.Attach(KUidHostMassStorageCategory, aKey); + __BOTPRINT2(_L("Property Key[%d] attach ret=%d"), aKey, ret); + if (ret == KErrNone) + { + TInt flag; + ret = prop.Get(KUidHostMassStorageCategory, aKey, flag); + if (ret == KErrNone) + { + flag++; + ret = prop.Set(KUidHostMassStorageCategory, aKey, flag); + } + __BOTPRINT3(_L("Property Set[%d] ret=%d Counter=%d"), aKey, ret, flag); + prop.Close(); + } + } + +#endif +