diff -r 000000000000 -r c9bc50fca66e usbmgmt/usbmgr/device/classdrivers/obex/classcontroller/src/CUsbObexClassController.cpp --- /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 +#include +#include + +#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; + }