usbmgmt/usbmgr/device/classdrivers/obex/classcontroller/src/CUsbObexClassController.cpp
changeset 0 c9bc50fca66e
child 29 59aa7d6e3e0f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usbmgmt/usbmgr/device/classdrivers/obex/classcontroller/src/CUsbObexClassController.cpp	Tue Feb 02 02:02:59 2010 +0200
@@ -0,0 +1,394 @@
+/*
+* 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:
+* Implements part of UsbMan USB Class Framework.
+*
+*/
+
+/**
+ @file
+*/
+
+#include "CUsbObexClassController.h"
+#include <usb_std.h>
+#include <d32usbc.h>
+#include <usb/usblogger.h>
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, "OBEXCC");
+#endif
+
+
+// Panic category only used in debug builds
+#ifdef _DEBUG
+_LIT( KObexCcPanicCategory, "UsbObexCc" );
+#endif
+
+/**
+ * Panic codes for the USB OBEX Class Controller.
+ */
+enum TObexCCPanic
+	{
+	/** Asynchronous function called (not needed, as all requests complete synchronously) */
+	EUnusedFunction = 0,
+	/** Start() called while in an illegal state */
+	EBadApiCallStart = 1,
+	/** Stop() called while in an illegal state */
+	EBadApiCallStop = 2,
+	};
+
+const TInt KMaxPacketTypeBulk=64;
+
+/**
+ * Constructs a CUsbObexClassController object.
+ *
+ * @param aOwner USB Device that owns and manages the class
+ * @return A new CUsbObexClassController object
+ */
+CUsbObexClassController* CUsbObexClassController::NewL(
+	MUsbClassControllerNotify& aOwner)
+	{
+	LOG_STATIC_FUNC_ENTRY
+
+	CUsbObexClassController* self =
+		new (ELeave) CUsbObexClassController(aOwner);
+	return self;
+	}
+
+/**
+ * Constructor.
+ *
+ * @param aOwner USB Device that owns and manages the class
+ */
+CUsbObexClassController::CUsbObexClassController(
+		MUsbClassControllerNotify& aOwner)
+	: CUsbClassControllerPlugIn(aOwner, KObexClassPriority)
+	{
+	iState = EUsbServiceIdle;
+	}
+
+/**
+ * Destructor.
+ */
+CUsbObexClassController::~CUsbObexClassController()
+	{
+	Cancel();
+	if (iState == EUsbServiceStarted) 
+		{
+		iLdd.ReleaseInterface(0);
+		iLdd.Close();
+		iLdd2.ReleaseInterface(1);
+		iLdd2.ReleaseInterface(0);
+		iLdd2.Close();
+		}
+	}
+
+/**
+ * SetupClassAndInterface.
+ *
+ * Sets the interface for use. This involves finding an "Interrupt IN" endpoint
+ * and if found configuring the interface.
+ */
+
+
+TInt CUsbObexClassController::SetUpClassAndInterface()
+	{
+	TUsbcInterfaceInfoBuf ifc;
+	
+	HBufC16* string = KUsbObexIfc().Alloc();
+	if (!string)
+		return KErrNoMemory;
+	
+	ifc().iString = string;
+	ifc().iClass.iClassNum = KObexClassNumber;		
+	ifc().iClass.iSubClassNum = KObexSubClassNumber;
+	ifc().iClass.iProtocolNum = KObexProtocolNumber;
+	ifc().iTotalEndpointsUsed = 0;
+	
+	// Indicate that this interface does not expect any control transfers 
+	// from EP0.
+	ifc().iFeatureWord |= KUsbcInterfaceInfo_NoEp0RequestsPlease;
+
+	TInt err = iLdd.SetInterface(0, ifc);
+	
+	// Get the interface number for later 
+	TBuf8<100> interfaceDescriptor;
+	iLdd.GetInterfaceDescriptor(0, interfaceDescriptor);
+	TUint8 OBEXIntNo = interfaceDescriptor.Ptr()[2];
+
+	delete string;
+
+	if (err != KErrNone) 
+		{ 
+		return err;
+		}
+
+	TBuf8<200> desc(0);
+
+	//Comms Class Header Functional Descriptor
+
+	desc.Append(KObexFunctionalDescriptorLength);
+	desc.Append(KUsbDescType_CS_Interface);
+	desc.Append(0);
+	desc.Append(0x10);
+	desc.Append(0x01);
+
+	// Obex Functional Descriptor
+
+	desc.Append(KObexFunctionalDescriptorLength);
+	desc.Append(KUsbDescType_CS_Interface);
+	desc.Append(0x15);
+	desc.Append(0x00);
+	desc.Append(0x01);
+
+	// Union Functional Descriptor
+	
+	desc.Append(KObexFunctionalDescriptorLength);
+	desc.Append(KUsbDescType_CS_Interface);	
+	desc.Append(0x06);								// descriptor type (Union)
+	desc.Append(OBEXIntNo);	
+	int dataInt = OBEXIntNo + 1;
+	desc.Append(dataInt);		
+
+	err= iLdd.SetCSInterfaceDescriptorBlock(0, desc);
+	if (err!= KErrNone)
+		{
+        return err;
+        }
+
+	err = iLdd2.Open(0);
+	if (err != KErrNone)
+		{
+        return err;
+        }
+
+	TUsbcInterfaceInfoBuf dataifc;
+
+	// Set data class interfaces
+    dataifc().iString = NULL;
+	dataifc().iClass.iClassNum = KObexDataClass;		
+	dataifc().iClass.iSubClassNum = KObexDataSubClass;
+	dataifc().iClass.iProtocolNum = 0;
+	dataifc().iTotalEndpointsUsed = 0;
+
+	// Indicate that this interface does not expect any control transfers 
+	// from EP0.
+	dataifc().iFeatureWord |= KUsbcInterfaceInfo_NoEp0RequestsPlease;
+	
+	err = iLdd2.SetInterface(0, dataifc);
+	if (err != KErrNone) 
+		{
+		iLdd2.Close();
+		return err;
+		}
+
+	TUsbDeviceCaps dCaps;
+	TInt ret = iLdd.DeviceCaps(dCaps);
+	if (ret != KErrNone) 
+		return ret;
+	
+	
+	TInt n = dCaps().iTotalEndpoints;
+	if (n < KObexMinNumEndpoints) 
+		return KErrGeneral;
+	
+	// Endpoints
+	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
+	
+    TUsbcInterfaceInfoBuf dataifc2;
+	TBool foundIn = EFalse;
+	TBool foundOut = EFalse;
+
+    for (TInt i = 0; !(foundIn && foundOut) && i < n; i++)
+        {
+        const TUsbcEndpointCaps* caps = &data[i].iCaps;
+        if (data[i].iInUse)
+            continue;
+
+		const TUint KBulkInFlags = KUsbEpTypeBulk | KUsbEpDirIn;
+		const TUint KBulkOutFlags = KUsbEpTypeBulk | KUsbEpDirOut;
+
+        if (!foundIn && (caps->iTypesAndDir & KBulkInFlags) == KBulkInFlags)
+            {
+            dataifc2().iEndpointData[0].iType  = KUsbEpTypeBulk;
+            dataifc2().iEndpointData[0].iDir   = KUsbEpDirIn; 	
+			TInt maxSize = caps->MaxPacketSize();
+			if (maxSize > KMaxPacketTypeBulk)
+				maxSize = KMaxPacketTypeBulk;
+			dataifc2().iEndpointData[0].iSize  = maxSize;
+			foundIn = ETrue;
+            }
+		else if (!foundOut && (caps->iTypesAndDir & KBulkOutFlags) == KBulkOutFlags)
+			{
+			dataifc2().iEndpointData[1].iType = KUsbEpTypeBulk;
+			dataifc2().iEndpointData[1].iDir = KUsbEpDirOut;
+			TInt maxSize = caps->MaxPacketSize();
+			if (maxSize > KMaxPacketTypeBulk)
+				maxSize = KMaxPacketTypeBulk;
+			dataifc2().iEndpointData[1].iSize  = maxSize;
+			foundOut = ETrue;
+			}
+		}
+		
+    if (!(foundIn && foundOut)) 
+		return KErrGeneral;
+	
+	dataifc2().iString = NULL;
+	dataifc2().iClass.iClassNum = KObexDataClass;		
+	dataifc2().iClass.iSubClassNum = KObexDataSubClass;
+	dataifc2().iClass.iProtocolNum = 0;
+	dataifc2().iTotalEndpointsUsed = KObexTotalEndpoints;
+	
+	// Indicate that this interface does not expect any control transfers 
+	// from EP0.
+	dataifc2().iFeatureWord |= KUsbcInterfaceInfo_NoEp0RequestsPlease;
+	
+	err = iLdd2.SetInterface(1, dataifc2);
+	if (err != KErrNone) 
+		{
+		iLdd2.ReleaseInterface(0);
+		iLdd2.Close();
+		return err;
+
+		}
+	return KErrNone;
+	}
+
+/**
+ * Called by UsbMan to start this class.
+ *
+ * @param aStatus Will be completed with success or failure.
+ */
+void CUsbObexClassController::Start(TRequestStatus& aStatus)
+	{	
+	LOG_FUNC
+
+	//Start() should never be called if started, starting or stopping (or in state EUsbServiceFatalError)
+	__ASSERT_DEBUG( iState == EUsbServiceIdle, _USB_PANIC(KObexCcPanicCategory, EBadApiCallStart) );
+	
+	TRequestStatus* reportStatus = &aStatus;
+	
+	iState = EUsbServiceStarting;
+
+	TInt err = User::LoadLogicalDevice(KUsbObexLddName);
+	if (err != KErrNone && err != KErrAlreadyExists) 
+		{
+		User::RequestComplete(reportStatus, err);
+		iState = EUsbServiceIdle;
+		return;      
+		} 
+		
+	err = iLdd.Open(0);
+	if(err != KErrNone)
+		{
+		iState = EUsbServiceIdle;
+		User::RequestComplete(reportStatus, err);
+
+		return;	
+		}
+
+	err = SetUpClassAndInterface();
+	if (err != KErrNone) 
+		{
+		iLdd.Close();
+		iState = EUsbServiceIdle;
+		User::RequestComplete(reportStatus, err);
+		
+		return;
+		}
+		
+	iState = EUsbServiceStarted;
+	User::RequestComplete(reportStatus, KErrNone);
+	}
+
+
+/**
+ * Called by UsbMan to stop this class.
+ *
+ * @param aStatus Will be completed with success or failure.
+ */
+void CUsbObexClassController::Stop(TRequestStatus& aStatus)
+	{
+	LOG_FUNC
+
+	//Stop() should never be called if stopping, idle or starting (or in state EUsbServiceFatalError)
+	__ASSERT_DEBUG( iState == EUsbServiceStarted, _USB_PANIC(KObexCcPanicCategory, EBadApiCallStop) );
+
+	TRequestStatus* ReportStatus = &aStatus;
+
+	iState = EUsbServiceStopping;
+
+	// We should probably check the return codes of these calls and report that
+	// we couldn't stop if they fail.
+	iLdd.ReleaseInterface(0);
+	iLdd.Close();
+	iLdd2.ReleaseInterface(1);
+	iLdd2.ReleaseInterface(0);
+	iLdd2.Close();
+
+	iState = EUsbServiceIdle;
+
+	User::RequestComplete(ReportStatus, KErrNone);
+	}
+
+
+/**
+ * Returns information about the interfaces supported by this class.
+ *
+ * @param aDescriptorInfo Will be filled in with interface information.
+ */
+void CUsbObexClassController::GetDescriptorInfo(TUsbDescriptor& aDescriptorInfo) const
+	{
+	aDescriptorInfo.iNumInterfaces = KObexNumInterfaces;
+	aDescriptorInfo.iLength = KObexDescriptorLength;
+	}
+
+/**
+ * Standard active object RunL. 
+ *
+ * This is never called as this class does not have any asynchronous requests
+ */
+void CUsbObexClassController::RunL()
+	{
+	__ASSERT_DEBUG(EFalse, _USB_PANIC(KObexCcPanicCategory, EUnusedFunction));
+	}
+
+/**
+ * Standard active object cancellation function. 
+ *
+ * Will only be called when an asynchronous request is currently active.
+ */
+void CUsbObexClassController::DoCancel()
+	{
+	__ASSERT_DEBUG(EFalse, _USB_PANIC(KObexCcPanicCategory, EUnusedFunction));
+	}
+
+/**
+ * Standard active object error-handling function. 
+ *
+ * Should return KErrNone to avoid an active scheduler panic. This function
+ * should never be called as there is another mechanism for catching errors.
+ */
+
+TInt CUsbObexClassController::RunError(TInt /*aError*/)
+	{
+	__ASSERT_DEBUG(EFalse, _USB_PANIC(KObexCcPanicCategory, EUnusedFunction));
+	return KErrNone;
+	}