--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usbmgmt/usbmgr/device/classdrivers/acm/classimplementation/ecacm/src/CdcDataInterface.cpp Tue Feb 02 02:02:59 2010 +0200
@@ -0,0 +1,581 @@
+/*
+* Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "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:
+*
+*/
+
+#include <e32std.h>
+#include "CdcDataInterface.h"
+#include "ActiveReader.h"
+#include "ActiveWriter.h"
+#include "AcmPanic.h"
+#include "AcmUtils.h"
+#include "ActiveReadOneOrMoreReader.h"
+#include "ActiveDataAvailableNotifier.h"
+#include "inifile.h"
+#include <usb/usblogger.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, "ECACM");
+#endif
+
+#ifdef __HEADLESS_ACM_TEST_CODE__
+#pragma message ("Building headless ACM (performance test code for RDevUsbcClient)")
+#endif // __HEADLESS_ACM_TEST_CODE__
+
+CCdcDataInterface::CCdcDataInterface(const TDesC16& aIfcName)
+/**
+ * Overloaded Constructor using interface name.
+ * @param aIfcName contains the interface name
+ */
+ : CCdcInterfaceBase(aIfcName),
+ iPacketSize(KDefaultMaxPacketTypeBulk)
+ {
+ }
+
+CCdcDataInterface* CCdcDataInterface::NewL(const TDesC16& aIfcName)
+/**
+ * Create a new CCdcDataInterface object and construct it using interface name
+ * This call will return an object with a valid USB configuration
+ *
+ * @param aParent Observer.
+ * @param aIfcName Contains the interface name
+ * @return A pointer to the new object
+ */
+ {
+ LOG_STATIC_FUNC_ENTRY
+
+ LOGTEXT2(_L("\tData Ifc Name = %S"), &aIfcName);
+
+ CCdcDataInterface* self = new (ELeave) CCdcDataInterface(aIfcName);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+ CLEANUPSTACK_POP(self);
+ return self;
+ }
+
+void CCdcDataInterface::ConstructL()
+/**
+ * Construct the object
+ * This call registers the object with the USB device driver
+ *
+ * @param aParent Observer.
+ */
+ {
+ BaseConstructL();
+
+ iReadOneOrMoreReader = CActiveReadOneOrMoreReader::NewL(*this, iLdd, EEndpoint2);
+ iReader = CActiveReader::NewL(*this, iLdd, EEndpoint2);
+ iDataAvailableNotifier = CActiveDataAvailableNotifier::NewL(*this, iLdd, EEndpoint2);
+ iWriter = CActiveWriter::NewL(*this, iLdd, EEndpoint1);
+ iLinkState = CLinkStateNotifier::NewL(*this, iLdd);
+
+ iLinkState->Start();
+
+ LOGTEXT(_L8("\tchecking ecacm.ini"));
+ iHostCanHandleZLPs = EFalse;
+ GetHostZLPHandlingFromFile();
+ LOGTEXT(_L8("\tfinished checking ecacm.ini"));
+ }
+
+TInt CCdcDataInterface::SetUpInterface()
+/**
+ * Retrieves the device capabilities and searches for suitable input and
+ * output bulk endpoints. If suitable endpoints are found, an interface
+ * descriptor for the endpoints is registered with the LDD.
+ */
+ {
+ LOGTEXT(_L8(">>CCdcDataInterface::SetUpInterface"));
+
+ TUsbDeviceCaps dCaps;
+ TInt ret = iLdd.DeviceCaps(dCaps);
+ LOGTEXT(_L8("\tchecking result of DeviceCaps"));
+ if ( ret )
+ {
+ LOGTEXT2(_L8("<<CCdcDataInterface::SetUpInterface ret=%d"), ret);
+ return ret;
+ }
+
+ TInt maxBulkPacketSize = (dCaps().iHighSpeed) ? KMaxPacketTypeBulkHS : KMaxPacketTypeBulkFS;
+ const TUint KRequiredNumberOfEndpoints = 2;
+
+ const TUint totalEndpoints = static_cast<TUint>(dCaps().iTotalEndpoints);
+ LOGTEXT2(_L8("\tiTotalEndpoints = %d"), totalEndpoints);
+ if ( totalEndpoints < KRequiredNumberOfEndpoints )
+ {
+ LOGTEXT2(_L8("<<CCdcDataInterface::SetUpInterface ret=%d"),
+ KErrGeneral);
+ return KErrGeneral;
+ }
+
+ // Endpoints
+ TUsbcEndpointData data[KUsbcMaxEndpoints];
+ TPtr8 dataptr(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data));
+ ret = iLdd.EndpointCaps(dataptr);
+ LOGTEXT(_L8("\tchecking result of EndpointCaps"));
+ if ( ret )
+ {
+ LOGTEXT2(_L8("<<CCdcDataInterface::SetUpInterface ret=%d"), ret);
+ return ret;
+ }
+
+ //
+ TUsbcInterfaceInfoBuf ifc;
+ TBool foundIn = EFalse;
+ TBool foundOut = EFalse;
+
+ for ( TUint i = 0; !(foundIn && foundOut) && i < totalEndpoints; i++ )
+ {
+ const TUsbcEndpointCaps* caps = &data[i].iCaps;
+ __ASSERT_DEBUG(caps,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ if (data[i].iInUse)
+ continue;
+
+ //get the max packet size it can potentially support
+ //it's possible that it can support Isoch (1023) which is greater
+ //than max for Bulk at 64
+ const TInt maxSize = Min ( maxBulkPacketSize,
+ caps->MaxPacketSize() );
+
+ const TUint KBulkInFlags = KUsbEpTypeBulk | KUsbEpDirIn;
+ const TUint KBulkOutFlags = KUsbEpTypeBulk | KUsbEpDirOut;
+
+ // use EEndPoint1 for TX (IN) EEndpoint1
+ if (! foundIn && (caps->iTypesAndDir & KBulkInFlags) == KBulkInFlags)
+ {
+
+ ifc().iEndpointData[0].iType = KUsbEpTypeBulk;
+ ifc().iEndpointData[0].iDir = KUsbEpDirIn;
+
+ //get the max packet size it can potentially support
+ //it's possible that it can support Isoch (1023) which is greater
+ //than max for Bulk at 64
+ ifc().iEndpointData[0].iSize = maxSize;
+ foundIn = ETrue;
+ }
+ // use EEndPoint2 for RX (OUT) endpoint
+ else if ( !foundOut
+ && (caps->iTypesAndDir & KBulkOutFlags) == KBulkOutFlags
+ )
+ {
+ // EEndpoint2 is going to be our RX (OUT, read) endpoint
+ ifc().iEndpointData[1].iType = KUsbEpTypeBulk;
+ ifc().iEndpointData[1].iDir = KUsbEpDirOut;
+
+ //get the max packet size it can potentially support
+ //it's possible that it can support Isoch (1023) which is greater
+ //than max for Bulk at 64
+ ifc().iEndpointData[1].iSize = maxSize;
+ foundOut = ETrue;
+ }
+ }
+
+ if (! (foundIn && foundOut))
+ {
+ LOGTEXT2(_L8("<<CCdcDataInterface::SetUpInterface ret=%d"),
+ KErrGeneral);
+ return KErrGeneral;
+ }
+
+ // If the device supports USB High-speed, then we request 64KB buffers
+ // (otherwise the default 4KB ones will do).
+
+ TUint bandwidthPriority = (EUsbcBandwidthOUTDefault | EUsbcBandwidthINDefault);
+ if (dCaps().iHighSpeed)
+ {
+ bandwidthPriority = (EUsbcBandwidthOUTPlus2 | EUsbcBandwidthINPlus2);
+ }
+
+ ifc().iString = &iIfcName;
+ ifc().iTotalEndpointsUsed = KRequiredNumberOfEndpoints;
+ ifc().iClass.iClassNum = 0x0A; // Table 18- Data Interface Class
+ ifc().iClass.iSubClassNum = 0x00; // Section 4.6- unused.
+ ifc().iClass.iProtocolNum = 0x00; // Table 19- no class specific protocol required
+
+ // Indicate that this interface does not expect any control transfers
+ // from EP0.
+ ifc().iFeatureWord |= KUsbcInterfaceInfo_NoEp0RequestsPlease;
+
+ LOGTEXT(_L8("\tcalling SetInterface"));
+ // Zero effectively indicates that alternate interfaces are not used.
+ ret = iLdd.SetInterface(0, ifc, bandwidthPriority);
+
+ LOGTEXT2(_L8("<<CCdcDataInterface::SetUpInterface ret=%d"), ret);
+ return ret;
+ }
+
+
+void CCdcDataInterface::MLSOStateChange(TInt aPacketSize)
+ {
+ iPacketSize = aPacketSize;
+ }
+
+
+CCdcDataInterface::~CCdcDataInterface()
+/**
+ * Destructor. Cancel and destroy the child classes.
+ */
+ {
+ LOG_FUNC
+
+ delete iLinkState;
+ delete iReadOneOrMoreReader;
+ delete iReader;
+ delete iWriter;
+ delete iDataAvailableNotifier;
+ }
+
+void CCdcDataInterface::Write(MWriteObserver& aObserver,
+ const TDesC8& aDes,
+ TInt aLen)
+/**
+ * Write data down the interface
+ *
+ * @param aObserver The observer to notify of completion.
+ * @param aDes Descriptor containing the data to be sent
+ * @param aLen Length of the data to be sent
+ */
+ {
+ LOG_FUNC
+
+ __ASSERT_DEBUG(!iWriteObserver,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ iWriteObserver = &aObserver;
+
+ __ASSERT_DEBUG(iWriter, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ if ( iHostCanHandleZLPs )
+ {
+
+ // Make sure the driver sends a Zero Length Packet if required (i.e. if the
+ // data size is an exact multiple of the endpoint's packet size).
+ TBool requestZlp = ( aLen % iPacketSize ) ? EFalse : ETrue;
+ iWriter->Write(aDes, aLen, requestZlp);
+ }
+ else
+ {
+ iWriter->Write(aDes, aLen, EFalse);
+ }
+
+ LOGTEXT(_L8("<<CCdcDataInterface::Write"));
+ }
+
+void CCdcDataInterface::WriteCompleted(TInt aError)
+/**
+ * Called when a write request completes.
+ *
+ * @param aError Error.
+ */
+ {
+ LOGTEXT2(_L8(">>CCdcDataInterface::WriteCompleted aError=%d"), aError);
+
+#ifdef __HEADLESS_ACM_TEST_CODE__
+ // Issue another Read or ReadOneOrMore as appropriate.
+ // If the Write completed with an error, we panic, as it's invalidating
+ // the test.
+ __ASSERT_DEBUG(aError == KErrNone,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ switch ( iHeadlessReadType )
+ {
+ case ERead:
+ LOGTEXT2(_L8("__HEADLESS_ACM_TEST_CODE__- issuing Read for %d bytes"),
+ iHeadlessReadLength);
+ __ASSERT_DEBUG(iReader, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iReader->Read(iHeadlessAcmBuffer, iHeadlessReadLength);
+ break;
+ case EReadOneOrMore:
+ LOGTEXT2(_L8("__HEADLESS_ACM_TEST_CODE__- issuing ReadOneOrMore for %d bytes"),
+ iHeadlessReadLength);
+ __ASSERT_DEBUG(iReadOneOrMoreReader, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iReadOneOrMoreReader->ReadOneOrMore(iHeadlessAcmBuffer, iHeadlessReadLength);
+ break;
+ case EUnknown:
+ default:
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError);
+ break;
+ }
+#else
+ // In case the write observer wants to post another write synchronously on
+ // being informed that this write has completed, use this little 'temp'
+ // fiddle.
+ __ASSERT_DEBUG(iWriteObserver,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ MWriteObserver* temp = iWriteObserver;
+ iWriteObserver = NULL;
+ LOGTEXT(_L8("\tcalling WriteCompleted on observer"));
+ temp->WriteCompleted(aError);
+#endif // __HEADLESS_ACM_TEST_CODE__
+
+ LOGTEXT(_L8("<<CCdcDataInterface::WriteCompleted"));
+ }
+
+void CCdcDataInterface::CancelWrite()
+/**
+ * Cancel an outstanding write request
+ */
+ {
+ LOG_FUNC
+
+ __ASSERT_DEBUG(iWriter, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ iWriter->Cancel();
+
+ iWriteObserver = NULL;
+ }
+
+void CCdcDataInterface::Read(MReadObserver& aObserver,
+ TDes8& aDes,
+ TInt aMaxLen)
+/**
+ * Read data from the interface. As the LDD supports an appropriate function,
+ * this request can be passed straight down.
+ *
+ * @param aObserver The observer to notify of completion.
+ * @param aDes Descriptor to put the read data in
+ * @param aMaxLen Number of bytes to read
+ */
+ {
+ LOG_FUNC
+
+#ifdef __HEADLESS_ACM_TEST_CODE__
+ LOGTEXT(_L8("__HEADLESS_ACM_TEST_CODE__"));
+ // Issue a Read using our special internal buffer.
+ iHeadlessReadType = ERead;
+ iHeadlessReadLength = aMaxLen;
+ static_cast<void>(&aObserver);
+ static_cast<void>(&aDes);
+ __ASSERT_DEBUG(aMaxLen <= iHeadlessAcmBuffer.MaxLength(),
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ __ASSERT_DEBUG(iReader, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iReader->Read(iHeadlessAcmBuffer, aMaxLen);
+#else
+ __ASSERT_DEBUG(!iReadObserver,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iReadObserver = &aObserver;
+
+ __ASSERT_DEBUG(iReader, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iReader->Read(aDes, aMaxLen);
+#endif // __HEADLESS_ACM_TEST_CODE__
+ }
+
+void CCdcDataInterface::ReadOneOrMore(MReadOneOrMoreObserver& aObserver,
+ TDes8& aDes,
+ TInt aMaxLen)
+/**
+ * Read a given amount of data from the interface, but complete if any data
+ * arrives.
+ *
+ * @param aObserver The observer to notify of completion.
+ * @param aDes Descriptor to put the read data in
+ * @param aMaxLen Number of bytes to read
+ */
+ {
+ LOG_FUNC
+
+#ifdef __HEADLESS_ACM_TEST_CODE__
+ LOGTEXT(_L8("__HEADLESS_ACM_TEST_CODE__"));
+ // Issue a ReadOneOrMore using our special internal buffer.
+ iHeadlessReadType = EReadOneOrMore;
+ iHeadlessReadLength = aMaxLen;
+ static_cast<void>(&aObserver);
+ static_cast<void>(&aDes);
+ __ASSERT_DEBUG(aMaxLen <= iHeadlessAcmBuffer.MaxLength(),
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ __ASSERT_DEBUG(iReadOneOrMoreReader,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iReadOneOrMoreReader->ReadOneOrMore(iHeadlessAcmBuffer, aMaxLen);
+#else
+ __ASSERT_DEBUG(!iReadOneOrMoreObserver,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iReadOneOrMoreObserver = &aObserver;
+
+ __ASSERT_DEBUG(iReadOneOrMoreReader,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iReadOneOrMoreReader->ReadOneOrMore(aDes, aMaxLen);
+#endif // __HEADLESS_ACM_TEST_CODE__
+ }
+
+void CCdcDataInterface::ReadOneOrMoreCompleted(TInt aError)
+/**
+ * The completion function, called when a ReadOneOrMore request is completed
+ * by the LDD.
+ *
+ * @param aError The result of the read request.
+ */
+ {
+ LOGTEXT2(_L8(">>CCdcDataInterface::ReadOneOrMoreCompleted aError=%d"),
+ aError);
+
+#ifdef __HEADLESS_ACM_TEST_CODE__
+ LOGTEXT2(_L8("__HEADLESS_ACM_TEST_CODE__- issuing Write for %d bytes"),
+ iHeadlessAcmBuffer.Length());
+ // Write back the data just read.
+ // If the ReadOneOrMore completed with an error, we panic, as it's
+ // invalidating the test.
+ __ASSERT_DEBUG(aError == KErrNone,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ __ASSERT_DEBUG(iWriter, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iWriter->Write(iHeadlessAcmBuffer, iHeadlessAcmBuffer.Length(), EFalse);
+#else
+ __ASSERT_DEBUG(iReadOneOrMoreObserver,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ // See comment in WriteCompleted.
+ MReadOneOrMoreObserver* temp = iReadOneOrMoreObserver;
+ iReadOneOrMoreObserver = NULL;
+ LOGTEXT(_L8("\tcalling ReadOneOrMoreCompleted on observer"));
+ temp->ReadOneOrMoreCompleted(aError);
+#endif // __HEADLESS_ACM_TEST_CODE__
+
+ LOGTEXT(_L8("<<CCdcDataInterface::ReadOneOrMoreCompleted"));
+ }
+
+void CCdcDataInterface::ReadCompleted(TInt aError)
+/**
+ * Called by the active reader object when it completes.
+ *
+ * @param aError Error.
+ */
+ {
+ LOGTEXT2(_L8(">>CCdcDataInterface::ReadCompleted aError=%d"), aError);
+
+#ifdef __HEADLESS_ACM_TEST_CODE__
+ LOGTEXT2(_L8("__HEADLESS_ACM_TEST_CODE__- issuing Write for %d bytes"),
+ iHeadlessAcmBuffer.Length());
+ // Write back the data just read.
+ // If the Read completed with an error, we panic, as it's invalidating the
+ // test.
+ __ASSERT_DEBUG(aError == KErrNone,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ __ASSERT_DEBUG(iWriter, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iWriter->Write(iHeadlessAcmBuffer, iHeadlessAcmBuffer.Length(), EFalse);
+#else
+ __ASSERT_DEBUG(iReadObserver,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ // See comment in WriteCompleted.
+ MReadObserver* temp = iReadObserver;
+ iReadObserver = NULL;
+ LOGTEXT(_L8("\tcalled ReadCompleted on observer"));
+ temp->ReadCompleted(aError);
+#endif // __HEADLESS_ACM_TEST_CODE__
+
+ LOGTEXT(_L8("<<CCdcDataInterface::ReadCompleted"));
+ }
+
+void CCdcDataInterface::CancelRead()
+/**
+ * Cancel an outstanding read request
+ */
+ {
+ LOG_FUNC
+
+ __ASSERT_DEBUG(iReader, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ __ASSERT_DEBUG(iReadOneOrMoreReader,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ iReader->Cancel();
+ iReadOneOrMoreReader->Cancel();
+ iReadObserver = NULL;
+ iReadOneOrMoreObserver = NULL;
+ }
+
+
+void CCdcDataInterface::GetHostZLPHandlingFromFile()
+/**
+ * Opens the ECACM.ini file to check on the capabilities of the host device.
+ * If the ini file cannot be found or read successfully, the default setting i.e. the
+ * host device CANNOT handle Zero Length Packets (set in CCdcAcmClass::ConstructL()),
+ * is kept.
+ */
+ {
+ LOG_FUNC
+
+ CIniFile* iniFile = NULL;
+
+ _LIT(KEcacmIniFilename, "ecacm.ini" );
+ _LIT(KEcacmIniFilePath, "\\system\\data\\" );
+
+ TRAPD(error, iniFile = CIniFile::NewL(KEcacmIniFilename, KEcacmIniFilePath));
+
+ if (error == KErrNone)
+ {
+ TInt hostHandlesZLPs = 1;
+
+ _LIT(KHostUSBDeviceDriver, "HostUSBDeviceDriver");
+ _LIT(KCanHandleZLP, "CanHandleZLP");
+
+ if ( iniFile->FindVar(KHostUSBDeviceDriver, KCanHandleZLP(), hostHandlesZLPs))
+ {
+ iHostCanHandleZLPs = (( hostHandlesZLPs == 1 ) ? ETrue : EFalse );
+
+ LOGTEXT2(_L8("\tecacm.ini: CanHandleZLP=%d"), hostHandlesZLPs);
+ }
+
+ delete iniFile;
+ }
+ }
+
+void CCdcDataInterface::NotifyDataAvailableCompleted(TInt aError)
+/**
+ * Called by the active data available notifier object when it completes.
+ *
+ * @param aError Error.
+ */
+ {
+ LOGTEXT2(_L8(">>CCdcDataInterface::NotifyDataAvailableCompleted aError=%d"), aError);
+
+ // See comment in WriteCompleted.
+ MNotifyDataAvailableObserver* temp = iNotifyDataAvailableObserver;
+ iNotifyDataAvailableObserver = NULL;
+ LOGTEXT(_L8("\tcalled NotifyDataAvailableCompleted on observer"));
+ temp->NotifyDataAvailableCompleted(aError);
+
+ LOGTEXT(_L8("<<CCdcDataInterface::NotifyDataAvailableCompleted"));
+ }
+
+void CCdcDataInterface::NotifyDataAvailable(MNotifyDataAvailableObserver& aObserver)
+/**
+ * Complete if any data arrives.
+ *
+ * @param aObserver The observer to notify of completion.
+ */
+ {
+ LOG_FUNC
+
+ __ASSERT_DEBUG(!iNotifyDataAvailableObserver, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iNotifyDataAvailableObserver = &aObserver;
+
+ __ASSERT_DEBUG(iDataAvailableNotifier,
+ _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+ iDataAvailableNotifier->NotifyDataAvailable();
+ }
+
+void CCdcDataInterface::CancelNotifyDataAvailable()
+/**
+ * Cancel notification of arrival of data.
+ */
+ {
+ LOG_FUNC
+
+ __ASSERT_DEBUG(iDataAvailableNotifier, _USB_PANIC(KAcmPanicCat, EPanicInternalError));
+
+ iDataAvailableNotifier->Cancel();
+ iNotifyDataAvailableObserver = NULL;
+ }
+
+//
+// End of file