diff -r f92a4f87e424 -r 012cc2ee6408 usbdrv/peripheral/pdd/pil/src/ps_usbc.cpp --- a/usbdrv/peripheral/pdd/pil/src/ps_usbc.cpp Tue Aug 31 17:01:47 2010 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4832 +0,0 @@ -// Copyright (c) 2000-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: -// e32/drivers/usbcc/ps_usbc.cpp -// Platform independent layer (PIL) of the USB Device controller driver (PDD). -// Interface to the USB LDD. -// -// - -/** - @file ps_usbc.cpp - @internalTechnology -*/ -//#include -#include - -#include "controltransfersm.h" -/** - TUsbcInterfaceSet and TUsbcInterface - ==================================== - - TUsbcInterfaceSet represents a 'USB Interface' and TUsbcInterface - represents an 'Alternate Setting of a USB Interface'. - - Since every LDD governs exactly one interface, the above distinction is - made only within the USB implementation. At the LDD API, there is/are - simply one or more settings for this single interface, numbered from '0' - (the default) to 'n', and specified by the parameter 'TInt aInterfaceNum'. - - Within the PDD implementation, for a TUsbcInterfaceSet number the parameter - 'TInt aIfcSet' is used (local variable ifcset); for a TUsbcInterface number - the parameter 'TInt aIfc' is used (local variable ifc). - - - iConfigs[0] and CurrentConfig() - =============================== - - One problem with this file is that it always uses iConfigs[0] and not - CurrentConfig(). This is mainly because the API to the LDD doesn't know - about the concept of multiple configurations, and thus always assumes one - single configuration (which is also always active: a further problem). - - In the file chapter9.cpp this issue doesn't exist, since there we always - have to obey the USB protocol, and in this way will use the configuration - which is selected by the host (which will then again currently always be - iConfigs[0].) - - iEp0ClientId - ================================== - - The purpose of these two members of class DUsbClientController is the - following. - - They are used only during Ep0 control transactions which have an OUT (Rx) - data stage. We cannot deduce from the received data itself to whom - it is addressed (that's because of the shared nature of Ep0). - - In order to be able to tell whether received Ep0 data is to be processed by - the PIL or a LDD, we use iEp0ClientId. iEp0ClientId is usually NULL, which - means it is our data. However it is set to the client ID of an LDD in case - 2) above. That way we can subsequently hand over received data to the - correct client LDD. - - iEp0DataReceived tracks the amount of data already received - it is used to - determine the end of the DATA_OUT phase, irrespective of the owner of the - data. The total amount that is to be received can be obtained via - iConTransferMgr->PktParser().Length(). (iConTransferMgr->PktParser() holds in - that case the Setup packet of the current Control transfer.) - - iEp0ClientDataTransmitting is only set to TRUE if a client sets up an Ep0 - write. After that transmission has completed we use this value to decide - whether we have to report the completion to a client or not. (If this - variable is FALSE, we did set up the write and thus no client notification - is necessary.) - -*/ - -// -// === Global and Local Variables ================================================================== -// - -// Currently we support at most 2 peripheral stack -GLDEF_D DUsbClientController* DUsbClientController::UsbClientController[] = {NULL, NULL}; - -static const TInt KUsbReconnectDelay = 500; // milliseconds - -// Charger detector is the guy(PSL) who can detect the charger type and report -// it via a charger type observer -static UsbShai::MChargerDetectorIf* gChargerDetector = NULL; - -// Charger observer is the guy who want to monitor the chager type event. -static UsbShai::MChargerDetectorObserverIf* gChargerObsever = NULL; - - -// Those const variables are used to construct the default -// Usb descriptors, Upper layer can change them later. -/** Default vendor ID to set in device descriptor */ -static const TUint16 KUsbVendorId = KUsbVendorId_Symbian; -/** Default product ID to set in device descriptor */ -static const TUint16 KUsbProductId = 0x1111; -/** Default language ID (US English) to set in device descriptor */ -static const TUint16 KUsbLangId = 0x0409; -static const TUint8 KUsbNumberOfConfiguration = 0x01; -/** Default manufacturer string */ -static const wchar_t KStringManufacturer[] = L"Nokia Corporation"; -/** Default product name string */ -static const wchar_t KStringProduct[] = L"Nokia USB Driver"; -/** Default configuration name string */ -static const wchar_t KStringConfig[] = L"Bulk transfer method configuration"; -/** Default configuration name string */ -static const wchar_t KStringSerial[] = L"Serial Not defined"; - - -// -// === USB Controller member function implementations - LDD API (public) =========================== -// - -DECLARE_STANDARD_EXTENSION()//lint !e1717 !e960 defined by symbian - { - __KTRACE_OPT(KUSB, Kern::Printf("> Peripheral PIL Extension entry")); - // Don't need to do anything here, using extension just to make sure - // we're loaded when peripheral PSL trying to register itself to us. - __KTRACE_OPT(KUSB, Kern::Printf("< Peripheral PIL Extension exit")); - return KErrNone; - } - -/** The class destructor. - - This rarely gets called, except, for example when something goes - wrong during construction. - - It's not exported because it is virtual. -*/ -DUsbClientController::~DUsbClientController() - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::~DUsbClientController()")); - if (iPowerHandler) - { - iPowerHandler->Remove(); - delete iPowerHandler; - } - - // ResetAndDestroy() will call for every array element the destructor of the pointed-to object, - // before deleting the element itself, and closing the array. - iConfigs.ResetAndDestroy(); - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::~DUsbClientController(): Done.")); - } - -EXPORT_C DUsbClientController* DUsbClientController::Create(UsbShai::MPeripheralControllerIf& aPeripheralControllerIf, - const UsbShai::TPeripheralControllerProperties& aProperties, - TBool aIsOtgPort) - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::Create")); - // Attempt to create the object - DUsbClientController* usbcc = new DUsbClientController(aPeripheralControllerIf, - aProperties, - aIsOtgPort); - - __ASSERT_DEBUG( (usbcc != NULL), Kern::Fault( " USB PSL Out of memory, DUsbClientController", __LINE__ ) ); - - if (usbcc != NULL) - { - // Second phase constructor - TInt err = usbcc->Construct(); - __ASSERT_DEBUG( (err == KErrNone), Kern::Fault( "DUsbClientController::Construct failed", err) ); - - if (err != KErrNone) - { - delete usbcc; - usbcc = NULL; - } - } - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::Create instance = %d",usbcc)); - - return usbcc; - } - -/** - * FIXME: This function used to be called by the dummy DCD to disable - * the peripheral stack. It has been deprecated and we currently use - * DisablePeripheralStack() to achieve the same effect. - */ -EXPORT_C void DUsbClientController::DisableClientStack() - { - __KTRACE_OPT(KUSB, Kern::Printf("CALL TO OBSOLETE FUNCTION: DUsbClientController::DisableClientStack()")); - } - - -/** - * FIXME: This function used to be called by the dummy DCD to enable - * the peripheral stack. It has been deprecated and we currently use - * EnablePeripheralStack() to achieve the same effect. - */ -EXPORT_C void DUsbClientController::EnableClientStack() - { - __KTRACE_OPT(KUSB, Kern::Printf("CALL TO OBSOLETE FUNCTION: DUsbClientController::EnableClientStack()")); - } - - -/** Called by LDD to see if controller is usable. - - @return ETrue if controller is in normal state, EFalse if it is disabled. -*/ -EXPORT_C TBool DUsbClientController::IsActive() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::IsActive = %d",iStackIsActive)); - return iStackIsActive; - } - - -/** Called by LDD to register client callbacks. - - @return KErrNone if successful, KErrAlreadyExists callback exists. -*/ -EXPORT_C TInt DUsbClientController::RegisterClientCallback(TUsbcClientCallback& aCallback) - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::RegisterClientCallback()")); - if (iClientCallbacks.Elements() == KUsbcMaxListLength) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", - KUsbcMaxListLength)); - return KErrGeneral; - } - TSglQueIter iter(iClientCallbacks); - TUsbcClientCallback* p; - while ((p = iter++) != NULL) - if (p == &aCallback) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Error: ClientCallback @ 0x%x already registered", &aCallback)); - return KErrAlreadyExists; - } - iClientCallbacks.AddLast(aCallback); - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::RegisterClientCallback()")); - return KErrNone; - } - - -/** Returns a pointer to the USB client controller object. - - This function is static. - - @param aUdc The number of the UDC (0..n) for which the pointer is to be returned. - - @return A pointer to the USB client controller object. -*/ -EXPORT_C DUsbClientController* DUsbClientController::UsbcControllerPointer(TInt aUdc) - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::UsbcControllerPointer()")); - - if (aUdc < 0 || aUdc > 1) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aUdc out of range (%d)", aUdc)); - return NULL; - } - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::UsbcControllerPointer()")); - - return UsbClientController[aUdc]; - } - - -/** Fills the buffer passed in as an argument with endpoint capability information. - - @see DUsbClientController::DeviceCaps() - @see TUsbcEndpointData - @see TUsbDeviceCaps - - @param aClientId A pointer to the LDD making the enquiry. - @param aCapsBuf A reference to a descriptor buffer, which, on return, contains an array of - TUsbcEndpointData elements; there are TUsbDeviceCaps::iTotalEndpoints elements in the array; - call DeviceCaps() to get the number of elements required. -*/ -EXPORT_C void DUsbClientController::EndpointCaps(const DBase* aClientId, TDes8& aCapsBuf) const - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::EndpointCaps()")); - // Here we do not simply call DUsbClientController::DeviceEndpointCaps(), - // because that function fills an array which comprises of _all_ endpoints, - // whereas this function omits ep0 and all unusable endpoints. - // Apart from that, we have to fill an array of TUsbcEndpointData, not TUsbcEndpointCaps. - TUsbcEndpointData data[KUsbcMaxEndpoints]; - const TInt ifcset_num = ClientId2InterfaceNumber(aClientId); - for (TInt i = 2, j = 0; i < iDeviceTotalEndpoints; ++i) - { - __KTRACE_OPT(KUSB, Kern::Printf(" DUsbClientController::Caps: RealEndpoint #%d", i)); - if (iRealEndpoints[i].iCaps.iTypesAndDir != UsbShai::KUsbEpNotAvailable) - { - __KTRACE_OPT(KUSB, Kern::Printf(" DUsbClientController::Caps: --> UsableEndpoint #%d", j)); - - data[j].iCaps.iSizes = iRealEndpoints[i].iCaps.iSizes; - data[j].iCaps.iTypesAndDir = iRealEndpoints[i].iCaps.iTypesAndDir; - data[j].iCaps.iHighBandwidth = iRealEndpoints[i].iCaps.iHighBandwidth; - data[j].iCaps.iReserved[0] = iRealEndpoints[i].iCaps.iReserved[0]; - data[j].iCaps.iReserved[1] = iRealEndpoints[i].iCaps.iReserved[1]; - - if (ifcset_num < 0) - { - // If this LDD doesn't own an interface, but the Ep points to one, - // then that must be the interface of a different LDD. Hence the Ep - // is not available for this LDD. - data[j].iInUse = (iRealEndpoints[i].iIfcNumber != NULL); - } - else - { - // If this LDD does already own an interface, and the Ep also points to one, - // then the Ep is not available for this LDD only if that interface is owned - // by a different LDD (i.e. if the interface number is different). - // Reason: Even though the endpoint might already be part of an interface setting, - // it is still available for a different alternate setting of the same interface. - data[j].iInUse = ((iRealEndpoints[i].iIfcNumber != NULL) && - (*(iRealEndpoints[i].iIfcNumber) != ifcset_num)); - } - - j++; - } - } - // aCapsBuf resides in userland - TPtrC8 des((TUint8*)data, sizeof(data)); - const TInt r = Kern::ThreadDesWrite((reinterpret_cast(aClientId))->Client(), - &aCapsBuf, des, 0, KChunkShiftBy0, NULL); - if (r != KErrNone) - { - Kern::ThreadKill((reinterpret_cast(aClientId))->Client(), - EExitPanic, r, KUsbPILKillCat); - } - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::EndpointCaps()")); - } - - -/** Fills the buffer passed in as an argument with device capability information. - - @see TUsbDeviceCaps - @see TUsbDeviceCapsV01 - - @param aClientId A pointer to the LDD making the enquiry. - @param aCapsBuf A reference to a descriptor buffer which, on return, contains - a TUsbDeviceCaps structure. -*/ -EXPORT_C void DUsbClientController::DeviceCaps(const DBase* aClientId, TDes8& aCapsBuf) const - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::DeviceCaps()")); - TUsbDeviceCaps caps; - caps().iTotalEndpoints = iDeviceUsableEndpoints; // not DeviceTotalEndpoints()! - - caps().iSelfPowered = iSelfPowered; - caps().iRemoteWakeup = iRemoteWakeup; - caps().iHighSpeed = (iControllerProperties.iControllerCaps & UsbShai::KDevCapHighSpeed)?ETrue:EFalse; - - // PIL always assume controller support this caps, see explaination in peripheral shai header - caps().iFeatureWord1 = caps().iFeatureWord1 | KUsbDevCapsFeatureWord1_CableDetectWithoutPower; - - caps().iFeatureWord1 = caps().iFeatureWord1 | KUsbDevCapsFeatureWord1_EndpointResourceAllocV2; - caps().iReserved = 0; - - // aCapsBuf resides in userland - const TInt r = Kern::ThreadDesWrite((reinterpret_cast(aClientId))->Client(), - &aCapsBuf, caps, 0, KChunkShiftBy0, NULL); - if (r != KErrNone) - { - Kern::ThreadKill((reinterpret_cast(aClientId))->Client(), - EExitPanic, r, KUsbPILKillCat); - } - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::DeviceCaps()")); - } - - -TUsbcEndpointInfoArray::TUsbcEndpointInfoArray(const TUsbcEndpointInfo* aData, TInt aDataSize) - { - iType = EUsbcEndpointInfo; - iData = (TUint8*) aData; - if (aDataSize > 0) - iDataSize = aDataSize; - else - iDataSize = sizeof(TUsbcEndpointInfo); - } - - -inline TUsbcEndpointInfo& TUsbcEndpointInfoArray::operator[](TInt aIndex) const - { - return *(TUsbcEndpointInfo*) &iData[aIndex * iDataSize]; - } - - -EXPORT_C TInt DUsbClientController::SetInterface(const DBase* aClientId, DThread* aThread, - TInt aInterfaceNum, TUsbcClassInfo& aClass, - TDesC8* aString, TInt aTotalEndpointsUsed, - const TUsbcEndpointInfo aEndpointData[], - TInt (*aRealEpNumbers)[6], TUint32 aFeatureWord) - { - TUsbcEndpointInfoArray endpointData = TUsbcEndpointInfoArray(aEndpointData); - return SetInterface(aClientId, aThread, aInterfaceNum, aClass, aString, aTotalEndpointsUsed, - endpointData, (TInt*) aRealEpNumbers, aFeatureWord); - } - - -/** Creates a new USB interface (one setting), complete with endpoints, descriptors, etc., - and chains it into the internal device configuration tree. - - @param aClientId A pointer to the LDD owning the new interface. - @param aThread A pointer to the thread the owning LDD is running in. - @param aInterfaceNum The interface setting number of the new interface setting. This must be 0 - if it is the first setting of the interface that gets created, or 1 more than the last setting - that was created for this interface. - @param aClass Contains information about the device class this interface might belong to. - @param aString A pointer to a string that is used for the string descriptor of this interface. - @param aTotalEndpointsUsed The number of endpoints used by this interface (and also the number of - elements of the following array). - @param aEndpointData An array with aTotalEndpointsUsed elements, containing information about the - endpoints of this interface. - - @return KErrNotSupported if Control endpoints are requested by the LDD but aren't supported by the PIL, - KErrInUse if at least one requested endpoint is - temporarily or permanently - not available for use, - KErrNoMemory if (endpoint, interface, string) descriptor allocation fails, KErrGeneral if something else - goes wrong during endpoint or interface or descriptor creation, KErrNone if interface successfully set up. -*/ -EXPORT_C TInt DUsbClientController::SetInterface(const DBase* aClientId, DThread* aThread, - TInt aInterfaceNum, TUsbcClassInfo& aClass, - TDesC8* aString, TInt aTotalEndpointsUsed, - const TUsbcEndpointInfoArray aEndpointData, - TInt aRealEpNumbers[], TUint32 aFeatureWord) - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::SetInterface()")); - if (aInterfaceNum != 0) - { - __KTRACE_OPT(KUSB, Kern::Printf(" alternate interface setting request: #%d", aInterfaceNum)); - } - -#ifndef USB_SUPPORTS_CONTROLENDPOINTS - for (TInt i = 0; i < aTotalEndpointsUsed; ++i) - { - if (aEndpointData[i].iType == UsbShai::KUsbEpTypeControl) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: control endpoints not supported")); - return KErrNotSupported; - } - } -#endif - - // Check for endpoint availability & check those endpoint's capabilities - const TInt ifcset_num = ClientId2InterfaceNumber(aClientId); - - // The passed-in ifcset_num may be -1 now, but that's intended. - if (!CheckEpAvailability(aTotalEndpointsUsed, aEndpointData, ifcset_num)) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: endpoints not (all) available")); - return KErrInUse; - } - - // Create & setup new interface - TUsbcInterface* ifc = CreateInterface(aClientId, aInterfaceNum, aFeatureWord); - if (ifc == NULL) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ifc == NULL")); - return KErrGeneral; - } - - // Create logical endpoints - TInt r = CreateEndpoints(ifc, aTotalEndpointsUsed, aEndpointData, aRealEpNumbers); - if (r != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: CreateEndpoints() err = %d ",r)); - DeleteInterface(ifc->iInterfaceSet->iInterfaceNumber, aInterfaceNum); - return r; - } - - // Create & setup interface, string, and endpoint descriptors - r = SetupIfcDescriptor(ifc, aClass, aThread, aString, aEndpointData); - if (r != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: SetupIfcDescriptor() err = %d",r)); - return r; - } - - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::SetInterface()")); - return KErrNone; - } - - -/** Releases an existing USB interface (one setting), complete with endpoints, descriptors, etc., - and removes it from the internal device configuration tree. - - @param aClientId A pointer to the LDD owning the interface. - @param aInterfaceNum The setting number of the interface setting to be deleted. This must be - the highest numbered (or 'last') setting for this interface. - - @return KErrNotFound if interface (not setting) for some reason cannot be found, KErrArgument if an - invalid interface setting number is specified (not existing or existing but too small), KErrNone if - interface successfully released or if this client doesn't own any interface. -*/ -EXPORT_C TInt DUsbClientController::ReleaseInterface(const DBase* aClientId, TInt aInterfaceNum) - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::ReleaseInterface(..., %d)", aInterfaceNum)); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KUSB, Kern::Printf(" interface not found")); // no error - return KErrNone; - } - TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); - if (!ifcset_ptr) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Error: interface number %d doesn't exist", ifcset)); - return KErrNotFound; - } - const TInt setting_count = ifcset_ptr->iInterfaces.Count(); - if ((setting_count - 1) != aInterfaceNum) - { - __KTRACE_OPT(KUSB, - Kern::Printf(" Error: interface settings must be released in descending order:\n\r" - " %d setting(s) exist, #%d was requested to be released.\n\r" - " (#%d has to be released first)", - setting_count, aInterfaceNum, setting_count - 1)); - return KErrArgument; - } - // Tear down current setting (invalidate configured state) - __KTRACE_OPT(KUSB, Kern::Printf(" tearing down InterfaceSet %d", ifcset)); - // Cancel all transfers on the current setting of this interface and deconfigure all its endpoints. - InterfaceSetTeardown(ifcset_ptr); - // 'Setting 0' means: delete all existing settings. - if (aInterfaceNum == 0) - { - TInt m = ifcset_ptr->iInterfaces.Count(); - while (m > 0) - { - m--; - // Ground the physical endpoints' logical_endpoint_pointers - const TInt n = ifcset_ptr->iInterfaces[m]->iEndpoints.Count(); - for (TInt i = 0; i < n; ++i) - { - TUsbcPhysicalEndpoint* ptr = const_cast - (ifcset_ptr->iInterfaces[m]->iEndpoints[i]->iPEndpoint); - ptr->iLEndpoint = NULL; - } - // Delete the setting itself + its ifc & ep descriptors - DeleteInterface(ifcset, m); - iDescriptors.DeleteIfcDescriptor(ifcset, m); - } - } - else - { - // Ground the physical endpoints' logical_endpoint_pointers - const TInt n = ifcset_ptr->iInterfaces[aInterfaceNum]->iEndpoints.Count(); - for (TInt i = 0; i < n; ++i) - { - TUsbcPhysicalEndpoint* ptr = const_cast - (ifcset_ptr->iInterfaces[aInterfaceNum]->iEndpoints[i]->iPEndpoint); - ptr->iLEndpoint = NULL; - } - // Delete the setting itself + its ifc & ep descriptors - DeleteInterface(ifcset, aInterfaceNum); - iDescriptors.DeleteIfcDescriptor(ifcset, aInterfaceNum); - } - // Delete the whole interface if all settings are gone - if (ifcset_ptr->iInterfaces.Count() == 0) - { - DeleteInterfaceSet(ifcset); - } - // We now no longer have a valid current configuration - iCurrentConfig = 0; - if (iDeviceState == UsbShai::EUsbPeripheralStateConfigured) - { - NextDeviceState(UsbShai::EUsbPeripheralStateAddress); - } - // If it was the last interface(set)... - if (iConfigs[0]->iInterfaceSets.Count() == 0) - { - __KTRACE_OPT(KUSB, Kern::Printf(" No ifc left -> turning off UDC")); - // First disconnect the device from the bus - UsbDisconnect(); - DeActivateHardwareController(); - // (this also disables endpoint zero; we cannot have a USB device w/o interface, see 9.6.3) - } - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::ReleaseInterface")); - return KErrNone; - } - - -/** Enforces a USB re-enumeration by disconnecting the UDC from the bus (if it is currently connected) and - re-connecting it. - - This only works if the PSL supports it, i.e. if SoftConnectCaps() returns ETrue. -*/ -EXPORT_C TInt DUsbClientController::ReEnumerate() - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::ReEnumerate()")); - - // ReEnumerate is possible only when stack is enabled - if (!iStackIsActive) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Client stack disabled -> returning here")); - return KErrNotReady; - } - - // If no interfaces setup, there is no point to reenumerate - if (iConfigs[0]->iInterfaceSets.Count() == 0) - { - __KTRACE_OPT(KUSB, Kern::Printf(" > No interface registered -> no need to re-enumerate")); - return KErrNone;; - } - - if (!iHardwareActivated) - { - // If the UDC is still off, we switch it on here. - const TInt r = ActivateHardwareController(); - if (r != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ActivateHardwareController() failed: %d", r)); - return r; - } - - // Finally connect the device to the bus - UsbConnect(); - } - else - { - UsbDisconnect(); - - // Now we have to wait a certain amount of time, in order to give the host the opportunity - // to come to terms with the new situation. - // (The ETrue parameter makes the callback get called in DFC instead of in ISR context.) - iReconnectTimer.OneShot(KUsbReconnectDelay, ETrue); - } - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::ReEnumerate()")); - return KErrNone;; - } - - -/** Powers up the UDC if one or more interfaces exist. - - @return KErrNone if UDC successfully powered up, KErrNotReady if no - interfaces have been registered yet, KErrHardwareNotAvailable if UDC - couldn't be activated. -*/ -EXPORT_C TInt DUsbClientController::PowerUpUdc() - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::PowerUpUdc()")); - - // we need to check whether Stack is activate or not(can be done by otg sw in otg setup - // or by vBus risen/fallen event in a non-otg env) - if (!iStackIsActive) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Client stack disabled -> returning here")); - return KErrNotReady; - } - - if (iConfigs[0]->iInterfaceSets.Count() == 0) - { - __KTRACE_OPT(KUSB, Kern::Printf(" No interface registered -> won't power up UDC")); - return KErrNotReady; - } - - // If the UDC is still off, we switch it on here. - const TInt r = ActivateHardwareController(); - if (r != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ActivateHardwareController() failed: %d", r)); - } - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::PowerUpUdc() returns %d",r)); - return r; - } - - -/** Connects the UDC to the bus. - - @return KErrNone if UDC successfully connected, - KErrNotSupported if KDevCapSoftConnect not supported - KErrGeneral if there was an error. - -*/ -EXPORT_C TInt DUsbClientController::UsbConnect() - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::UsbConnect()")); - iClientSupportReady = ETrue; - - // If a deferred reset is pending, service it now - const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); - if (iUsbResetDeferred) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Resetting USB Reset 'defer' flag")); - iUsbResetDeferred = EFalse; - (void) ProcessResetEvent(EFalse); - } - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - - // Indicate readiness to connect to the PSL - const TInt r = iController.PeripheralConnect(); - - // Check whether Stack is activated by OTG controller - // or Vbus Risen had been detected. - // If either of them is true and HW is not activated yet, do it here. - if (iStackIsActive && !iHardwareActivated ) - { - // PowerUpUdc only do Activating Hardware when there are at least 1 - // Iterface registered - PowerUpUdc(); - } - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::UsbConnect()")); - return r; - } - - -/** Disconnects the UDC from the bus. - - This only works if the PSL supports it, i.e. if SoftConnectCaps() returns ETrue. - - @return KErrNone if UDC successfully disconnected, KErrGeneral if there was an error. -*/ -EXPORT_C TInt DUsbClientController::UsbDisconnect() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::UsbDisconnect()")); - iClientSupportReady = EFalse; - - // Indicate to PSL that we are no longer ready to connect - const TInt r = iController.PeripheralDisconnect(); - - // There won't be any notification by the PSL about this, - // so we have to notify the LDD/user ourselves: - if ((r == KErrNone) && (iDeviceState != UsbShai::EUsbPeripheralStateUndefined)) - { - // Not being in state UNDEFINED implies that the cable is inserted. - if (iHardwareActivated) - { - NextDeviceState(UsbShai::EUsbPeripheralStatePowered); - } - // (If the hardware is NOT activated at this point, we can only be in - // state UsbShai::EUsbPeripheralStateAttached, so we don't have to move to it.) - } - return r; - } - - -/** Registers a notification callback for changes of the USB device state. - - In the event of a device state change, the callback's state member gets updated (using SetState) with a - new UsbShai::TUsbPeripheralState value, and then the callback is executed (DoCallback). 'USB device state' here refers - to the Visible Device States as defined in chapter 9 of the USB specification. - - @param aCallback A reference to a properly filled in status callback structure. - - @return KErrNone if callback successfully registered, KErrGeneral if this callback is already registered - (it won't be registered twice). -*/ -EXPORT_C TInt DUsbClientController::RegisterForStatusChange(TUsbcStatusCallback& aCallback) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterForStatusChange()")); - if (iStatusCallbacks.Elements() == KUsbcMaxListLength) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", - KUsbcMaxListLength)); - return KErrGeneral; - } - if (IsInTheStatusList(aCallback)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Error: StatusCallback @ 0x%x already registered", &aCallback)); - return KErrGeneral; - } - const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); - iStatusCallbacks.AddLast(aCallback); - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - return KErrNone; - } - - -/** De-registers (removes from the list of pending requests) a notification callback for the USB device - status. - - @param aClientId A pointer to the LDD owning the status change callback. - - @return KErrNone if callback successfully unregistered, KErrNotFound if the callback couldn't be found. -*/ -EXPORT_C TInt DUsbClientController::DeRegisterForStatusChange(const DBase* aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterForStatusChange()")); - __ASSERT_DEBUG((aClientId != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); - const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); - TSglQueIter iter(iStatusCallbacks); - TUsbcStatusCallback* p; - while ((p = iter++) != NULL) - { - if (p->Owner() == aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf(" removing StatusCallback @ 0x%x", p)); - iStatusCallbacks.Remove(*p); - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - return KErrNone; - } - } - __KTRACE_OPT(KUSB, Kern::Printf(" client not found")); - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - return KErrNotFound; - } - - -/** Registers a notification callback for changes of the state of endpoints. - - In the event of a state change of an endpoint that is spart of an interface which is owned by the LDD - specified in the callback structure, the callback's state member gets updated (using SetState) with a new - value, and the callback is executed (DoCallback). 'Endpoint state' here refers to the state of the - ENDPOINT_HALT feature of an endpoint as described in chapter 9 of the USB specification. The contents of - the state variable reflects the state of the halt features for all endpoints of the current interface - setting: bit 0 represents endpoint 1, bit 1 endpoint 2, etc. A set bit means 'endpoint halted', a cleared - bit 'endpoint not halted'. - - @param aCallback A reference to a properly filled in endpoint status callback structure. - - @return KErrNone if callback successfully registered, KErrGeneral if this callback is already registered - (it won't be registered twice). -*/ -EXPORT_C TInt DUsbClientController::RegisterForEndpointStatusChange(TUsbcEndpointStatusCallback& aCallback) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterForEndpointStatusChange()")); - if (iEpStatusCallbacks.Elements() == KUsbcMaxListLength) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", - KUsbcMaxListLength)); - return KErrGeneral; - } - if (IsInTheEpStatusList(aCallback)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Error: EpStatusCallback @ 0x%x already registered", &aCallback)); - return KErrGeneral; - } - const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); - iEpStatusCallbacks.AddLast(aCallback); - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - return KErrNone; - } - - -/** De-registers (removes from the list of pending requests) a notification callback for changes of the state - of endpoints. - - @param aClientId A pointer to the LDD owning the endpoint status change callback. - - @return KErrNone if callback successfully unregistered, KErrNotFound if the callback couldn't be found. -*/ -EXPORT_C TInt DUsbClientController::DeRegisterForEndpointStatusChange(const DBase* aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterForEndpointStatusChange()")); - __ASSERT_DEBUG((aClientId != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); - const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); - TSglQueIter iter(iEpStatusCallbacks); - TUsbcEndpointStatusCallback* p; - while ((p = iter++) != NULL) - { - if (p->Owner() == aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf(" removing EpStatusCallback @ 0x%x", p)); - iEpStatusCallbacks.Remove(*p); - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - return KErrNone; - } - } - __KTRACE_OPT(KUSB, Kern::Printf(" client not found")); - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - return KErrNotFound; - } - - -/** Returns the number of the currently active alternate interface setting for this interface. - - @param aClientId A pointer to the LDD owning the interface. - @param aInterfaceNum Here the interface gets written to. - - @return KErrNotFound if an interface for this client couldn't be found, KErrNone if setting value was - successfully written. -*/ -EXPORT_C TInt DUsbClientController::GetInterfaceNumber(const DBase* aClientId, TInt& aInterfaceNum) const - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetInterfaceNumber()")); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error (ifc < 0)")); - return KErrNotFound; - } - const TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); - if (!ifcset_ptr) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface number %d doesn't exist", ifcset)); - return KErrNotFound; - } - aInterfaceNum = ifcset_ptr->iCurrentInterface; - return KErrNone; - } - - -/** This is normally called once by an LDD's destructor, either after a Close() on the user side, - or during general cleanup. - - It might also be called by the LDD when some internal unrecoverable error occurs. - - This function - - de-registers a possibly pending device state change notification request, - - de-registers a possibly pending endpoint state change notification request, - - releases all interfaces + settings owned by this LDD, - - cancels all remaining (if any) read/write requests. - - @param aClientId A pointer to the LDD to be unregistered. - - @return KErrNone. -*/ -EXPORT_C TInt DUsbClientController::DeRegisterClient(const DBase* aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterClient(0x%x)", aClientId)); - // Cancel all device state notification requests - DeRegisterForStatusChange(aClientId); - // Cancel all endpoint state notification requests - DeRegisterForEndpointStatusChange(aClientId); - DeRegisterForOtgFeatureChange(aClientId); - DeRegisterClientCallback(aClientId); - // Delete the interface including all its alternate settings which might exist. - // (If we release the default setting (0), all alternate settings are deleted as well.) - const TInt r = ReleaseInterface(aClientId, 0); - // Cancel all remaining (if any) read/write requests - DeleteRequestCallbacks(aClientId); - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterClient: Done.")); - return r; - } - - -/** Returns the currently used Ep0 max packet size. - - @return The currently used Ep0 max packet size. -*/ -EXPORT_C TInt DUsbClientController::Ep0PacketSize() const - { - const TUsbcLogicalEndpoint* const ep = iRealEndpoints[0].iLEndpoint; - if (iHighSpeed) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Ep0 size = %d (HS)", ep->iEpSize_Hs)); - return ep->iEpSize_Hs; - } - else - { - __KTRACE_OPT(KUSB, Kern::Printf(" Ep0 size = %d (FS)", ep->iEpSize_Fs)); - return ep->iEpSize_Fs; - } - } - - -/** Stalls Ep0. - - @param aClientId A pointer to the LDD wishing to stall Ep0 (this is for PIL internal purposes only). - - @return KErrNone if endpoint zero successfully stalled, KErrGeneral otherwise. -*/ -EXPORT_C TInt DUsbClientController::Ep0Stall(const DBase* aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::Ep0Stall()")); - if (aClientId == iEp0ClientId) - { - ResetEp0DataOutVars(); - } - const TInt err = iConTransferMgr->StallEndpoint(KEp0_Out); - if (err < 0) - { - return err; - } - else - return iConTransferMgr->StallEndpoint(KEp0_In); - } - - -/** Sends a zero-byte status packet on Ep0. - - @param aClientId A pointer to the LDD wishing to send the status packet (not used at present). -*/ -EXPORT_C void DUsbClientController::SendEp0StatusPacket(const DBase* /* aClientId */) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SendEp0StatusPacket()")); - iConTransferMgr->SendEp0ZeroByteStatusPacket(); - } - - -/** Returns the current USB device state. - - 'USB device state' here refers to the Visible Device States as defined in chapter 9 of the USB - specification. - - @return The current USB device state, or UsbShai::EUsbPeripheralStateUndefined -*/ -EXPORT_C UsbShai::TUsbPeripheralState DUsbClientController::GetDeviceStatus() const - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetDeviceStatus()")); - return iDeviceState; - } - - -/** Returns the state of an endpoint. - - 'Endpoint state' here refers to the state of the ENDPOINT_HALT feature of - an endpoint as described in chapter 9 of the USB specification. - - @param aClientId A pointer to the LDD owning the interface which contains the endpoint to be queried. - @param aEndpointNum The number of the endpoint to be queried. - - @return The current endpoint state, or EEndpointStateUnknown if the endpoint couldn't be found. -*/ -EXPORT_C TEndpointState DUsbClientController::GetEndpointStatus(const DBase* aClientId, TInt aEndpointNum) const - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::GetEndpointStatus()")); - - TEndpointState ret = (iRealEndpoints[aEndpointNum].iHalt)?EEndpointStateStalled : EEndpointStateNotStalled; - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::GetEndpointStatus() %d",ret)); - - return ret; - } - - -/** Sets up a data read request for an endpoint. - - @param aCallback A reference to a properly filled in data transfer request callback structure. - - @return KErrNone if callback successfully registered or if this callback is already registered - (but it won't be registered twice), KErrNotFound if the endpoint couldn't be found, KErrArgument if - endpoint number invalid (PSL), KErrGeneral if something else goes wrong. -*/ -EXPORT_C TInt DUsbClientController::SetupReadBuffer(TUsbcRequestCallback& aCallback) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetupReadBuffer()")); - const TInt ep = aCallback.iRealEpNum; - __KTRACE_OPT(KUSB, Kern::Printf(" logical ep: #%d", aCallback.iEndpointNum)); - __KTRACE_OPT(KUSB, Kern::Printf(" real ep: #%d", ep)); - TInt err = KErrGeneral; - if (ep != 0) - { - if (iRequestCallbacks[ep]) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: RequestCallback already registered for that ep")); - if (iRequestCallbacks[ep] == &aCallback) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" (this same RequestCallback @ 0x%x)", &aCallback)); - } - else - { - __KTRACE_OPT(KPANIC, Kern::Printf(" (a different RequestCallback @ 0x%x)", &aCallback)); - } - return KErrNone; - } - // This may seem awkward: - // First we add a callback, and then, in case of an error, we remove it again. - // However this is necessary because the transfer request might complete (through - // an ISR) _before_ the SetupEndpointRead function returns. Since we don't know the - // outcome, we have to provide the callback before making the setup call. - // - __KTRACE_OPT(KUSB, Kern::Printf(" adding RequestCallback[%d] @ 0x%x", ep, &aCallback)); - iRequestCallbacks[ep] = &aCallback; - if ((err = iController.SetupEndpointRead(ep, aCallback)) != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" removing RequestCallback @ 0x%x (due to error)", - &aCallback)); - iRequestCallbacks[ep] = NULL; - } - } - else // (ep == 0) - { - if (iEp0ReadRequestCallbacks.Elements() == KUsbcMaxListLength) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", - KUsbcMaxListLength)); - return KErrGeneral; - } - if (IsInTheRequestList(aCallback)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" RequestCallback @ 0x%x already registered", &aCallback)); - return KErrNone; - } - // Ep0 reads don't need to be prepared - there's always one pending - __KTRACE_OPT(KUSB, Kern::Printf(" adding RequestCallback @ 0x%x (ep0)", &aCallback)); - const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); - iEp0ReadRequestCallbacks.AddLast(aCallback); - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - err = KErrNone; - if (iEp0_RxExtraCount != 0) - { - __KTRACE_OPT(KUSB, Kern::Printf(" iEp0_RxExtraData: trying again...")); - - const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); - - // Extra data is either a setup packet or a data packet - // They are not possible to be both - // And, the error code must be KErrNone, otherwise, we can not arrive here - if( iSetupPacketPending ) - { - ProcessSetupPacket(iEp0_RxExtraCount,KErrNone); - } - else - { - ProcessDataOutPacket(iEp0_RxExtraCount,KErrNone); - } - - // clear it since already completed to client - iEp0_RxExtraCount = 0; - - err = iLastError; - - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - if (err == KErrNone) - { - //iEp0_RxExtraData = EFalse; - // Queue a new Ep0 read (because xxxProceed only re-enables the interrupt) - iConTransferMgr->SetupEndpointZeroRead(); - if (iSetupPacketPending) - { - iConTransferMgr->Ep0SetupPacketProceed(); - iSetupPacketPending = EFalse; - } - else - { - iConTransferMgr->Ep0DataPacketProceed(); - } - - __KTRACE_OPT(KUSB, Kern::Printf(" :-)")); - } - else - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: :-(")); - err = KErrGeneral; - } - return err; - } - } - return err; - } - - -/** Sets up a data write request for an endpoint. - - @param aCallback A reference to a properly filled in data transfer request callback structure. - - @return KErrNone if callback successfully registered or if this callback is already registered - (but it won't be registered twice), KErrNotFound if the endpoint couldn't be found, KErrArgument if - endpoint number invalid (PSL), KErrGeneral if something else goes wrong. -*/ -EXPORT_C TInt DUsbClientController::SetupWriteBuffer(TUsbcRequestCallback& aCallback) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetupWriteBuffer()")); - TInt ep = aCallback.iRealEpNum; - __KTRACE_OPT(KUSB, Kern::Printf(" logical ep: #%d", aCallback.iEndpointNum)); - __KTRACE_OPT(KUSB, Kern::Printf(" real ep: #%d", ep)); - if (iRequestCallbacks[ep]) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: RequestCallback already registered for that ep")); - if (iRequestCallbacks[ep] == &aCallback) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" (this same RequestCallback @ 0x%x)", &aCallback)); - return KErrNone; - } - else - { - __KTRACE_OPT(KPANIC, Kern::Printf(" (a different RequestCallback @ 0x%x - poss. error)", - &aCallback)); - return KErrGeneral; - } - } - if (ep == 0) - { - if (iEp0_TxNonStdCount) - { - if (iEp0_TxNonStdCount > aCallback.iLength) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Ep0 is sending less data than requested")); - if ((aCallback.iLength % iEp0MaxPacketSize == 0) && !aCallback.iZlpReqd) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Zlp should probably be requested")); - } - } - else if (iEp0_TxNonStdCount < aCallback.iLength) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Ep0 is sending more data than requested")); - } - iEp0_TxNonStdCount = 0; - } - // Ep0 IN needs to be adjusted: the LDD uses 0 for both Ep0 directions. - ep = KEp0_Tx; - } - // This may seem awkward: - // First we add a callback, and then, in case of an error, we remove it again. - // However this is necessary because the transfer request might complete (through - // an ISR) _before_ the SetupEndpointWrite function returns. Since we don't know the - // outcome, we have to provide the callback before making the setup call. - // - __KTRACE_OPT(KUSB, Kern::Printf(" adding RequestCallback[%d] @ 0x%x", ep, &aCallback)); - iRequestCallbacks[ep] = &aCallback; - if (ep == KEp0_Tx) - { - iEp0ClientDataTransmitting = ETrue; // this must be set before calling SetupEndpointZeroWrite - TInt ret = iConTransferMgr->SetupEndpointZeroWrite(aCallback.iBufferStart, aCallback.iLength, aCallback.iZlpReqd); - if (ret != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" removing RequestCallback @ 0x%x (due to error)", &aCallback)); - iRequestCallbacks[ep] = NULL; - iEp0ClientDataTransmitting = EFalse; - return ret; - } - } - else if (iController.SetupEndpointWrite(ep, aCallback) != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" removing RequestCallback @ 0x%x (due to error)", &aCallback)); - iRequestCallbacks[ep] = NULL; - } - return KErrNone; - } - - -/** Cancels a data read request for an endpoint. - - The request callback will be removed from the queue and the - callback function won't be executed. - - @param aClientId A pointer to the LDD owning the interface which contains the endpoint. - @param aRealEndpoint The number of the endpoint for which the transfer request is to be cancelled. -*/ -EXPORT_C void DUsbClientController::CancelReadBuffer(const DBase* aClientId, TInt aRealEndpoint) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CancelReadBuffer(%d)", aRealEndpoint)); - if (aRealEndpoint < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ep # < 0: %d", aRealEndpoint)); - return; - } - // Note that we here don't cancel Ep0 read requests at the PSL level! - if (aRealEndpoint > 0) - { - iController.CancelEndpointRead(aRealEndpoint); - } - DeleteRequestCallback(aClientId, aRealEndpoint, UsbShai::EControllerRead); - } - - -/** Cancels a data write request for an endpoint. - - It cannot be guaranteed that the data is not sent nonetheless, as some UDCs don't permit a flushing of a - TX FIFO once it has been filled. The request callback will be removed from the queue in any case and the - callback function won't be executed. - - @param aClientId A pointer to the LDD owning the interface which contains the endpoint. - @param aRealEndpoint The number of the endpoint for which the transfer request is to be cancelled. -*/ -EXPORT_C void DUsbClientController::CancelWriteBuffer(const DBase* aClientId, TInt aRealEndpoint) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CancelWriteBuffer(%d)", aRealEndpoint)); - if (aRealEndpoint < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ep # < 0: %d", aRealEndpoint)); - return; - } - if (aRealEndpoint == 0) - { - // Ep0 IN needs to be adjusted: the LDD uses 0 for both Ep0 directions. - aRealEndpoint = KEp0_Tx; - } - iController.CancelEndpointWrite(aRealEndpoint); - if (aRealEndpoint == KEp0_Tx) - { - // Since Ep0 is shared among clients, we don't have to care about the client id. - iEp0WritePending = EFalse; - } - DeleteRequestCallback(aClientId, aRealEndpoint, UsbShai::EControllerWrite); - } - - -/** Halts (stalls) an endpoint (but not Ep0). - - @param aClientId A pointer to the LDD owning the interface which contains the endpoint to be stalled. - @param aEndpointNum The number of the endpoint. - - @return KErrNotFound if endpoint couldn't be found (includes Ep0), KErrNone if endpoint successfully - stalled, KErrGeneral otherwise. -*/ -EXPORT_C TInt DUsbClientController::HaltEndpoint(const DBase* aClientId, TInt aEndpointNum) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::HaltEndpoint(%d)", aEndpointNum)); - const TInt r = iController.StallEndpoint(aEndpointNum); - if (r == KErrNone) - { - iRealEndpoints[aEndpointNum].iHalt = ETrue; - } - else if (r == KErrArgument) - { - return KErrNotFound; - } - return r; - } - - -/** Clears the halt condition of an endpoint (but not Ep0). - - @param aClientId A pointer to the LDD owning the interface which contains the endpoint to be un-stalled. - @param aEndpointNum The number of the endpoint. - - @return KErrNotFound if endpoint couldn't be found (includes Ep0), KErrNone if endpoint successfully - stalled, KErrGeneral otherwise. -*/ -EXPORT_C TInt DUsbClientController::ClearHaltEndpoint(const DBase* aClientId, TInt aEndpointNum) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ClearHaltEndpoint(%d)", aEndpointNum)); - const TInt r = iController.ClearStallEndpoint(aEndpointNum); - if (r == KErrNone) - { - iRealEndpoints[aEndpointNum].iHalt = EFalse; - } - else if (r == KErrArgument) - { - return KErrNotFound; - } - return r; - } - - -/** This function requests 'device control' for an LDD. - - Class or vendor specific Ep0 requests addressed to the USB device as a whole (Recipient field in - bmRequestType byte of a Setup packet set to zero) are delivered to the LDD that owns device control. For - obvious reasons only one USB LDD can have device control at any given time. - - @param aClientId A pointer to the LDD requesting device control. - - @return KErrNone if device control successfully claimed or if this LDD already owns it, KErrGeneral if - device control already owned by a different client. -*/ -EXPORT_C TInt DUsbClientController::SetDeviceControl(const DBase* aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetDeviceControl()")); - if (iEp0DeviceControl) - { - if (iEp0DeviceControl == aClientId) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Device Control already owned by this client")); - return KErrNone; - } - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device Control already claimed by a different client")); - return KErrGeneral; - } - iEp0DeviceControl = aClientId; - return KErrNone; - } - - -/** This function releases device control for an LDD. - - @see DUsbClientController::SetDeviceControl() - - @param aClientId A pointer to the LDD releasing device control. - - @return KErrNone if device control successfully released, KErrGeneral if device control owned by a - different client or by no client at all. -*/ -EXPORT_C TInt DUsbClientController::ReleaseDeviceControl(const DBase* aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ReleaseDeviceControl()")); - if (iEp0DeviceControl) - { - if (iEp0DeviceControl == aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Releasing Device Control")); - iEp0DeviceControl = NULL; - return KErrNone; - } - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device Control owned by a different client")); - } - else - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device Control not owned by any client")); - } - return KErrGeneral; - } - - -/** Returns all available (configurable) max packet sizes for Ep0. - - The information is coded as bitwise OR'ed values of KUsbEpSizeXXX constants (the bitmap format used for - TUsbcEndpointCaps.iSupportedSizes). - - @return All available (configurable) max packet sizes for Ep0. -*/ -EXPORT_C TUint DUsbClientController::EndpointZeroMaxPacketSizes() const - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EndpointZeroMaxPacketSizes()")); - return iRealEndpoints[0].iCaps.iSizes; - } - - -/** Sets (configures) the max packet size for Ep0. - - For available sizes as returned by DUsbClientController::EndpointZeroMaxPacketSizes() - - Note that for HS operation the Ep0 size cannot be chosen, but is fixed at 64 bytes. - - @return KErrNotSupported if invalid size specified, KErrNone if new max packet size successfully set or - requested size was already set. -*/ -EXPORT_C TInt DUsbClientController::SetEndpointZeroMaxPacketSize(TInt aMaxPacketSize) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetEndpointZeroMaxPacketSize(%d)", - aMaxPacketSize)); - - if (iControllerProperties.iControllerCaps & UsbShai::KDevCapHighSpeed) - { - // We're not going to mess with this on a HS device. - return KErrNone; - } - - if (!(iRealEndpoints[0].iCaps.iSizes & PacketSize2Mask(aMaxPacketSize))) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid size")); - return KErrNotSupported; - } - if (iRealEndpoints[0].iLEndpoint->iEpSize_Fs == aMaxPacketSize) - { - __KTRACE_OPT(KUSB, Kern::Printf(" this packet size already set -> returning")); - return KErrNone; - } - const TUsbcLogicalEndpoint* const ep0_0 = iRealEndpoints[0].iLEndpoint; - const TUsbcLogicalEndpoint* const ep0_1 = iRealEndpoints[1].iLEndpoint; - const_cast(ep0_0)->iEpSize_Fs = aMaxPacketSize; - const_cast(ep0_1)->iEpSize_Fs = aMaxPacketSize; - - // @@@ We should probably modify the device descriptor here as well... - - if (iHardwareActivated) - { - // De-configure endpoint zero - iController.DeConfigureEndpoint(KEp0_Out); - iController.DeConfigureEndpoint(KEp0_In); - // Re-configure endpoint zero - const_cast(ep0_0)->iInfo.iSize = ep0_0->iEpSize_Fs; - const_cast(ep0_1)->iInfo.iSize = ep0_1->iEpSize_Fs; - iController.ConfigureEndpoint(0, ep0_0->iInfo); - iController.ConfigureEndpoint(1, ep0_1->iInfo); - iEp0MaxPacketSize = ep0_0->iInfo.iSize; - } - return KErrNone; - } - - -/** Returns the current USB Device descriptor. - - @param aThread A pointer to the thread the LDD requesting the descriptor is running in. - @param aDeviceDescriptor A reference to a buffer into which the requested descriptor should be written - (most likely located user-side). - - @return The return value of the thread write operation, Kern::ThreadWrite(), when writing to the target - buffer. -*/ -EXPORT_C TInt DUsbClientController::GetDeviceDescriptor(DThread* aThread, TDes8& aDeviceDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetDeviceDescriptor()")); - return iDescriptors.GetDeviceDescriptorTC(aThread, aDeviceDescriptor); - } - - -/** Sets a new USB Device descriptor. - - @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. - @param aDeviceDescriptor A reference to a buffer which contains the descriptor to be set (most likely - located user-side). - - @return The return value of the thread read operation, Kern::ThreadRead(), when reading from the source - buffer in case of a failure, KErrNone if the new descriptor was successfully set. -*/ -EXPORT_C TInt DUsbClientController::SetDeviceDescriptor(DThread* aThread, const TDes8& aDeviceDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetDeviceDescriptor()")); - return iDescriptors.SetDeviceDescriptorTC(aThread, aDeviceDescriptor); - } - - -/** Returns the current USB Device descriptor size. - - @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. - @param aSize A reference to a buffer into which the requested descriptor size should be written - (most likely located user-side). - - @return The return value of the thread write operation, Kern::ThreadWrite(), when writing to the target - buffer. -*/ -EXPORT_C TInt DUsbClientController::GetDeviceDescriptorSize(DThread* aThread, TDes8& aSize) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetDeviceDescriptorSize()")); - // We do not really enquire here.... - const TPtrC8 size(reinterpret_cast(&KUsbDescSize_Device), sizeof(KUsbDescSize_Device)); - return Kern::ThreadDesWrite(aThread, &aSize, size, 0); - } - - -/** Returns the current USB configuration descriptor. - - @param aThread A pointer to the thread the LDD requesting the descriptor is running in. - @param aConfigurationDescriptor A reference to a buffer into which the requested descriptor should be - written (most likely located user-side). - - @return The return value of the thread write operation, Kern::ThreadWrite(), when writing to the target - buffer. -*/ -EXPORT_C TInt DUsbClientController::GetConfigurationDescriptor(DThread* aThread, TDes8& aConfigurationDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetConfigurationDescriptor()")); - return iDescriptors.GetConfigurationDescriptorTC(aThread, aConfigurationDescriptor); - } - - -/** Sets a new USB configuration descriptor. - - @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. - @param aConfigurationDescriptor A reference to a buffer which contains the descriptor to be set (most - likely located user-side). - - @return The return value of the thread read operation, Kern::ThreadRead() when reading from the source - buffer in case of a failure, KErrNone if the new descriptor was successfully set. -*/ -EXPORT_C TInt DUsbClientController::SetConfigurationDescriptor(DThread* aThread, - const TDes8& aConfigurationDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetConfigurationDescriptor()")); - return iDescriptors.SetConfigurationDescriptorTC(aThread, aConfigurationDescriptor); - } - - -/** Returns the current USB configuration descriptor size. - - @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. - @param aSize A reference to a buffer into which the requested descriptor size should be written - (most likely located user-side). - - @return The return value of the thread write operation, Kern::ThreadWrite(), when writing to the target - buffer. -*/ -EXPORT_C TInt DUsbClientController::GetConfigurationDescriptorSize(DThread* aThread, TDes8& aSize) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetConfigurationDescriptorSize()")); - // We do not really enquire here.... - const TPtrC8 size(reinterpret_cast(&KUsbDescSize_Config), sizeof(KUsbDescSize_Config)); - return Kern::ThreadDesWrite(aThread, &aSize, size, 0); - } - - -/** Returns the current USB OTG descriptor. - - @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. - @param aOtgDesc A reference to a buffer into which the requested descriptor should be - written (most likely located user-side). - - @return KErrNotSupported or the return value of the thread write operation, Kern::ThreadDesWrite(), - when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetOtgDescriptor(DThread* aThread, TDes8& aOtgDesc) const - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetOtgDescriptor()")); - if (!iOtgSupport) - { - return KErrNotSupported; - } - return iDescriptors.GetOtgDescriptorTC(aThread, aOtgDesc); - } - - -/** Sets a new OTG descriptor. - - @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. - @param aOtgDesc A reference to a buffer which contains new OTG descriptor. - - @return KErrNotSupported or the return value of the thread read operation, Kern::ThreadDesRead(). -*/ -EXPORT_C TInt DUsbClientController::SetOtgDescriptor(DThread* aThread, const TDesC8& aOtgDesc) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetOtgDescriptor()")); - if (!iOtgSupport) - { - return KErrNotSupported; - } - TBuf8 otg; - const TInt r = Kern::ThreadDesRead(aThread, &aOtgDesc, otg, 0); - if (r != KErrNone) - { - return r; - } - // Check descriptor validity - if (otg[0] != KUsbDescSize_Otg || otg[1] != KUsbDescType_Otg || otg[2] > 3) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid OTG descriptor")); - return KErrGeneral; - } - __KTRACE_OPT(KUSB, Kern::Printf(" iOtgFuncMap before: 0x%x", iOtgFuncMap)); - // Update value in controller as well - const TUint8 hnp = otg[2] & KUsbOtgAttr_HnpSupp; - const TUint8 srp = otg[2] & KUsbOtgAttr_SrpSupp; - if (hnp && !srp) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Invalid OTG attribute combination (HNP && !SRP")); - } - if (hnp && !(iOtgFuncMap & KUsbOtgAttr_HnpSupp)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Setting attribute KUsbOtgAttr_HnpSupp")); - iOtgFuncMap |= KUsbOtgAttr_HnpSupp; - } - else if (!hnp && (iOtgFuncMap & KUsbOtgAttr_HnpSupp)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Removing attribute KUsbOtgAttr_HnpSupp")); - iOtgFuncMap &= ~KUsbOtgAttr_HnpSupp; - } - if (srp && !(iOtgFuncMap & KUsbOtgAttr_SrpSupp)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Setting attribute KUsbOtgAttr_SrpSupp")); - iOtgFuncMap |= KUsbOtgAttr_SrpSupp; - } - else if (!srp && (iOtgFuncMap & KUsbOtgAttr_SrpSupp)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Removing attribute KUsbOtgAttr_SrpSupp")); - iOtgFuncMap &= ~KUsbOtgAttr_SrpSupp; - } - __KTRACE_OPT(KUSB, Kern::Printf(" iOtgFuncMap after: 0x%x", iOtgFuncMap)); - return iDescriptors.SetOtgDescriptor(otg); - } - - -/** Returns current OTG features of USB device. - - @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. - @param aFeatures A reference to a buffer into which the requested OTG features should be written. - - @return KErrNotSupported or the return value of the thread write operation, Kern::ThreadDesWrite(). -*/ -EXPORT_C TInt DUsbClientController::GetOtgFeatures(DThread* aThread, TDes8& aFeatures) const - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetOtgFeatures()")); - if (!iOtgSupport) - { - return KErrNotSupported; - } - TBuf8<1> features(1); - features[0] = iOtgFuncMap & 0x1C; - return Kern::ThreadDesWrite(aThread, &aFeatures, features, 0); - } - - -/** Returns current OTG features of USB device. This function is intended to be - called only from kernel side. - - @param aFeatures The reference to which the current features should be set at. - @return KErrNone if successful, KErrNotSupported if OTG is unavailable. -*/ -EXPORT_C TInt DUsbClientController::GetCurrentOtgFeatures(TUint8& aFeatures) const - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetCurrentOtgFeatures()")); - if (!iOtgSupport) - { - return KErrNotSupported; - } - aFeatures = iOtgFuncMap & 0x1C; - return KErrNone; - } - - -/** Registers client request for OTG feature change. Client is notified when any OTG - feature is changed. - - @see KUsbOtgAttr_B_HnpEnable, KUsbOtgAttr_A_HnpSupport, KUsbOtgAttr_A_AltHnpSupport - - @param aCallback Callback function. Gets called when OTG features change - - @return KErrNone if successful, KErrAlreadyExists if aCallback is already in the queue. -*/ -EXPORT_C TInt DUsbClientController::RegisterForOtgFeatureChange(TUsbcOtgFeatureCallback& aCallback) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterForOtgFeatureChange()")); - if (iOtgCallbacks.Elements() == KUsbcMaxListLength) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", - KUsbcMaxListLength)); - return KErrGeneral; - } - if (IsInTheOtgFeatureList(aCallback)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Error: OtgFeatureCallback @ 0x%x already registered", &aCallback)); - return KErrAlreadyExists; - } - const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); - iOtgCallbacks.AddLast(aCallback); - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - return KErrNone; - } - - -/** De-registers (removes from the list of pending requests) a notification callback for - OTG feature change. - - @param aClientId A pointer to the LDD owning the endpoint status change callback. - - @return KErrNone if callback successfully unregistered, KErrNotFound if the callback couldn't be found. -*/ -EXPORT_C TInt DUsbClientController::DeRegisterForOtgFeatureChange(const DBase* aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterForOtgFeatureChange()")); - __ASSERT_DEBUG((aClientId != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); - const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); - TSglQueIter iter(iOtgCallbacks); - TUsbcOtgFeatureCallback* p; - while ((p = iter++) != NULL) - { - if (!aClientId || p->Owner() == aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf(" removing OtgFeatureCallback @ 0x%x", p)); - iOtgCallbacks.Remove(*p); - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - return KErrNone; - } - } - __KTRACE_OPT(KUSB, Kern::Printf(" client not found")); - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - return KErrNotFound; - } - - -/** Returns a specific standard USB interface descriptor. - - @param aThread A pointer to the thread the LDD requesting the descriptor is running in. - @param aClientId A pointer to the LDD requesting the descriptor. - @param aSettingNum The setting number of the interface for which the descriptor is requested. - @param aInterfaceDescriptor A reference to a buffer into which the requested descriptor should be written - (most likely located user-side). - - @return KErrNotFound if the specified interface couldn't be found, otherwise the return value of the thread - write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetInterfaceDescriptor(DThread* aThread, const DBase* aClientId, - TInt aSettingNum, TDes8& aInterfaceDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetInterfaceDescriptor(x, 0x%08x, %d, y)", - aClientId, aSettingNum)); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); - return KErrNotFound; - } - return iDescriptors.GetInterfaceDescriptorTC(aThread, aInterfaceDescriptor, ifcset, aSettingNum); - } - - -/** Sets a new standard USB interface descriptor. - - This function can also be used, by the user, and under certain conditions, to change an interface's number - (reported as bInterfaceNumber in the descriptor). The conditions are: 1) We cannot accept a number that is - already used by another interface, 2) We allow the interface number to be changed only when it's still the - only setting, and 3) We allow the interface number to be changed only for the default setting (0). (All - alternate settings created for that interface thereafter will inherit the new, changed number.) - - @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. - @param aClientId A pointer to the LDD requesting the setting of the descriptor. - @param aSettingNum The setting number of the interface for which the descriptor is to be set. - @param aInterfaceDescriptor A reference to a buffer which contains the descriptor to be set (most - likely located user-side). - - @return KErrNotFound if the specified interface couldn't be found, the return value of the thread read - operation, Kern::ThreadRead(), when reading from the source buffer in case of a failure, KErrArgument if the - interface number is to be changed (via bInterfaceNumber in the descriptor) and either the requested - interface number is already used by another interface or the interface has more than one setting. KErrNone - if the new descriptor was successfully set. -*/ -EXPORT_C TInt DUsbClientController::SetInterfaceDescriptor(DThread* aThread, const DBase* aClientId, - TInt aSettingNum, const TDes8& aInterfaceDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetInterfaceDescriptor(x, 0x%08x, %d, y)", - aClientId, aSettingNum)); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); - return KErrNotFound; - } - TBuf8 new_ifc; - TInt r = Kern::ThreadDesRead(aThread, &aInterfaceDescriptor, new_ifc, 0); - if (r != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Copying interface descriptor buffer failed (%d)", r)); - return r; - } - const TInt ifcset_new = new_ifc[2]; - const TBool ifc_num_changes = (ifcset != ifcset_new); - TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); - if (!ifcset_ptr) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface number %d doesn't exist", ifcset)); - return KErrNotFound; - } - if (ifc_num_changes) - { - // If the user wants to change the interface number, we need to do some sanity checks: - if (InterfaceExists(ifcset_new)) - { - // Obviously we cannot accept a number that is already used by another interface. - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface number %d already in use", ifcset_new)); - return KErrArgument; - } - if (ifcset_ptr->iInterfaces.Count() > 1) - { - // We allow the interface number to be changed only when it's the only setting. - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface has more than one alternate setting")); - return KErrArgument; - } - if (aSettingNum != 0) - { - // We allow the interface number to be changed only when it's the default setting. - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface number can only be changed for setting 0")); - return KErrArgument; - } - } - if ((r = iDescriptors.SetInterfaceDescriptor(new_ifc, ifcset, aSettingNum)) != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: iDescriptors.SetInterfaceDescriptorfailed")); - return r; - } - if (ifc_num_changes) - { - // Alright then, let's do it... - __KTRACE_OPT(KUSB, Kern::Printf(" about to change interface number from %d to %d", - ifcset, ifcset_new)); - ifcset_ptr->iInterfaceNumber = ifcset_new; - } - return KErrNone; - } - - -/** Returns the size of a specific standard USB interface descriptor. - - @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. - @param aClientId A pointer to the LDD requesting the descriptor size. - @param aSettingNum The setting number of the interface for which the descriptor size is requested. - @param aSize A reference to a buffer into which the requested descriptor size should be written (most - likely located user-side). - - @return KErrNotFound if the specified interface couldn't be found, otherwise the return value of the thread - write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetInterfaceDescriptorSize(DThread* aThread, const DBase* aClientId, - TInt /*aSettingNum*/, TDes8& aSize) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetInterfaceDescriptorSize()")); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); - return KErrNotFound; - } - // Actually, we do not really enquire here.... - const TPtrC8 size(reinterpret_cast(&KUsbDescSize_Interface), sizeof(KUsbDescSize_Interface)); - Kern::ThreadDesWrite(aThread, &aSize, size, 0); - return KErrNone; - } - - -/** Returns a specific standard USB endpoint descriptor. - - @param aThread A pointer to the thread the LDD requesting the descriptor is running in. - @param aClientId A pointer to the LDD requesting the descriptor. - @param aSettingNum The setting number of the interface that contains the endpoint for which the - descriptor is requested. - @param aEndpointNum The endpoint for which the descriptor is requested. - @param aEndpointDescriptor A reference to a buffer into which the requested descriptor should be written - (most likely located user-side). - - @return KErrNotFound if the specified interface or endpoint couldn't be found, otherwise the return value - of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetEndpointDescriptor(DThread* aThread, const DBase* aClientId, - TInt aSettingNum, TInt aEndpointNum, - TDes8& aEndpointDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetEndpointDescriptor(x, 0x%08x, %d, %d, y)", - aClientId, aSettingNum, aEndpointNum)); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); - return KErrNotFound; - } - return iDescriptors.GetEndpointDescriptorTC(aThread, aEndpointDescriptor, ifcset, - aSettingNum, EpIdx2Addr(aEndpointNum)); - } - - -/** Sets a new standard USB endpoint descriptor. - - @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. - @param aClientId A pointer to the LDD requesting the setting of the descriptor. - @param aSettingNum The setting number of the interface that contains the endpoint for which the - descriptor is to be set. - @param aEndpointNum The endpoint for which the descriptor is to be set. - @param aEndpointDescriptor A reference to a buffer which contains the descriptor to be set (most - likely located user-side). - - @return KErrNotFound if the specified interface or endpoint couldn't be found, the return value of the - thread read operation, Kern::ThreadRead(), when reading from the source buffer in case of a read failure, - KErrNone if the new descriptor was successfully set. -*/ -EXPORT_C TInt DUsbClientController::SetEndpointDescriptor(DThread* aThread, const DBase* aClientId, - TInt aSettingNum, TInt aEndpointNum, - const TDes8& aEndpointDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetEndpointDescriptor(x, 0x%08x, %d, %d, y)", - aClientId, aSettingNum, aEndpointNum)); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); - return KErrNotFound; - } - return iDescriptors.SetEndpointDescriptorTC(aThread, aEndpointDescriptor, ifcset, - aSettingNum, EpIdx2Addr(aEndpointNum)); - } - - -/** Returns the size of a specific standard USB endpoint descriptor. - - @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. - @param aClientId A pointer to the LDD requesting the descriptor size. - @param aSettingNum The setting number of the interface that contains the endpoint for which the - descriptor size is requested. - @param aEndpointNum The endpoint for which the descriptor size is requested. - @param aEndpointDescriptor A reference to a buffer into which the requested descriptor size should be - written (most likely located user-side). - - @return KErrNotFound if the specified interface or endpoint couldn't be found, otherwise the return value - of the thread write operation, kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetEndpointDescriptorSize(DThread* aThread, const DBase* aClientId, - TInt aSettingNum, TInt aEndpointNum, - TDes8& aSize) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetEndpointDescriptorSize(x, 0x%08x, %d, %d, y)", - aClientId, aSettingNum, aEndpointNum)); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); - return KErrNotFound; - } - TInt s; - TInt r = iDescriptors.GetEndpointDescriptorSize(ifcset, aSettingNum, - EpIdx2Addr(aEndpointNum), s); - if (r == KErrNone) - { - TPtrC8 size(reinterpret_cast(&s), sizeof(s)); - r = Kern::ThreadDesWrite(aThread, &aSize, size, 0); - } - else - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: endpoint descriptor not found")); - } - return r; - } - - -/** Returns the current Device_Qualifier descriptor. On a USB device which doesn't support high-speed - operation this function will return an error. Note that the contents of the descriptor depend on - the current device speed (full-speed or high-speed). - - @param aThread A pointer to the thread the LDD requesting the descriptor is running in. - @param aDeviceQualifierDescriptor A reference to a buffer into which the requested descriptor - should be written (most likely located user-side). - - @return KErrNotSupported if this descriptor is not supported, otherwise the return value of the thread - write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetDeviceQualifierDescriptor(DThread* aThread, - TDes8& aDeviceQualifierDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetDeviceQualifierDescriptor()")); - return iDescriptors.GetDeviceQualifierDescriptorTC(aThread, aDeviceQualifierDescriptor); - } - - -/** Sets a new Device_Qualifier descriptor. On a USB device which doesn't support high-speed - operation this function will return an error. Note that the contents of the descriptor should take - into account the current device speed (full-speed or high-speed) as it is dependent on it. - - @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. - @param aDeviceQualifierDescriptor A reference to a buffer which contains the descriptor to be set (most - likely located user-side). - - @return KErrNotSupported if this descriptor is not supported, otherwise the return value of the thread - read operation, Kern::ThreadRead(), when reading from the source buffer in case of a failure, KErrNone if - the new descriptor was successfully set. -*/ -EXPORT_C TInt DUsbClientController::SetDeviceQualifierDescriptor(DThread* aThread, - const TDes8& aDeviceQualifierDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetDeviceQualifierDescriptor()")); - return iDescriptors.SetDeviceQualifierDescriptorTC(aThread, aDeviceQualifierDescriptor); - } - - -/** Returns the current Other_Speed_Configuration descriptor. On a USB device which doesn't support high-speed - operation this function will return an error. Note that the contents of the descriptor depend on the - current device speed (full-speed or high-speed). - - @param aThread A pointer to the thread the LDD requesting the descriptor is running in. - @param aConfigurationDescriptor A reference to a buffer into which the requested descriptor - should be written (most likely located user-side). - - @return KErrNotSupported if this descriptor is not supported, otherwise the return value of the thread - write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetOtherSpeedConfigurationDescriptor(DThread* aThread, - TDes8& aConfigurationDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetOtherSpeedConfigurationDescriptor()")); - return iDescriptors.GetOtherSpeedConfigurationDescriptorTC(aThread, aConfigurationDescriptor); - } - - -/** Sets a new Other_Speed_Configuration descriptor. On a USB device which doesn't support high-speed - operation this function will return an error. Note that the contents of the descriptor should take - into account the current device speed (full-speed or high-speed) as it is dependent on it. - - @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. - @param aConfigurationDescriptor A reference to a buffer which contains the descriptor to be set (most - likely located user-side). - - @return KErrNotSupported if this descriptor is not supported, otherwise the return value of the thread - read operation, Kern::ThreadRead(), when reading from the source buffer in case of a failure, KErrNone if - the new descriptor was successfully set. -*/ -EXPORT_C TInt DUsbClientController::SetOtherSpeedConfigurationDescriptor(DThread* aThread, - const TDes8& aConfigurationDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetOtherSpeedConfigurationDescriptor()")); - return iDescriptors.SetOtherSpeedConfigurationDescriptorTC(aThread, aConfigurationDescriptor); - } - - -/** Returns a block of all available non-standard (class-specific) interface descriptors for a specific - interface. - - @param aThread A pointer to the thread the LDD requesting the descriptor block is running in. - @param aClientId A pointer to the LDD requesting the descriptor block. - @param aSettingNum The setting number of the interface for which the descriptor block is requested. - @param aInterfaceDescriptor A reference to a buffer into which the requested descriptor(s) should be - written (most likely located user-side). - - @return KErrNotFound if the specified interface couldn't be found, otherwise the return value of the thread - write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetCSInterfaceDescriptorBlock(DThread* aThread, const DBase* aClientId, - TInt aSettingNum, - TDes8& aInterfaceDescriptor) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetCSInterfaceDescriptorBlock(x, 0x%08x, %d, y)", - aClientId, aSettingNum)); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); - return KErrNotFound; - } - return iDescriptors.GetCSInterfaceDescriptorTC(aThread, aInterfaceDescriptor, ifcset, aSettingNum); - } - - -/** Sets a block of (i.e. one or more) non-standard (class-specific) interface descriptors for a specific - interface. - - @param aThread A pointer to the thread the LDD requesting the setting of the descriptor block is running - in. - @param aClientId A pointer to the LDD requesting the setting of the descriptor block. - @param aSettingNum The setting number of the interface for which the setting of the descriptor block is - requested. - @param aInterfaceDescriptor A reference to a buffer which contains the descriptor block to be set (most - likely located user-side). - @param aSize The size of the descriptor block to be set. - - @return KErrNotFound if the specified interface couldn't be found, KErrArgument if aSize is less than 2, - KErrNoMemory if enough memory for the new descriptor(s) couldn't be allocated, otherwise the return value - of the thread read operation, Kern::ThreadRead(), when reading from the source buffer. -*/ -EXPORT_C TInt DUsbClientController::SetCSInterfaceDescriptorBlock(DThread* aThread, const DBase* aClientId, - TInt aSettingNum, - const TDes8& aInterfaceDescriptor, TInt aSize) - { - __KTRACE_OPT(KUSB, - Kern::Printf("DUsbClientController::SetCSInterfaceDescriptorBlock(x, 0x%08x, %d, y, %d)", - aClientId, aSettingNum, aSize)); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); - return KErrNotFound; - } - if (aSize < 2) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aSize < 2 (%d)", aSize)); - return KErrArgument; - } - return iDescriptors.SetCSInterfaceDescriptorTC(aThread, aInterfaceDescriptor, ifcset, aSettingNum, aSize); - } - - -/** Returns the total size all non-standard (class-specific) interface descriptors for a specific interface. - - @param aThread A pointer to the thread the LDD requesting the descriptor block size is running in. - @param aClientId A pointer to the LDD requesting the descriptor block size. - @param aSettingNum The setting number of the interface for which the descriptor block size is - requested. - @param aSize A reference to a buffer into which the requested descriptor block size should be written (most - likely located user-side). - - @return KErrNotFound if the specified interface couldn't be found, otherwise the return value of the thread - write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetCSInterfaceDescriptorBlockSize(DThread* aThread, const DBase* aClientId, - TInt aSettingNum, TDes8& aSize) - { - __KTRACE_OPT(KUSB, - Kern::Printf("DUsbClientController::GetCSInterfaceDescriptorBlockSize(x, 0x%08x, %d, y)", - aClientId, aSettingNum)); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); - return KErrNotFound; - } - TInt s; - const TInt r = iDescriptors.GetCSInterfaceDescriptorSize(ifcset, aSettingNum, s); - if (r == KErrNone) - { - const TPtrC8 size(reinterpret_cast(&s), sizeof(s)); - Kern::ThreadDesWrite(aThread, &aSize, size, 0); - } - else - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: cs interface descriptor not found")); - } - return r; - } - - -/** Returns a block of all available non-standard (class-specific) endpoint descriptors for a specific endpoint. - - @param aThread A pointer to the thread the LDD requesting the descriptor block is running in. - @param aClientId A pointer to the LDD requesting the descriptor block. - @param aSettingNum The setting number of the interface that contains the endpoint for which the - descriptor block is requested. - @param aEndpointNum The endpoint for which the descriptor block is requested. - @param aEndpointDescriptor A reference to a buffer into which the requested descriptor(s) should be written - (most likely located user-side). - - @return KErrNotFound if the specified interface or endpoint couldn't be found, otherwise the return value - of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetCSEndpointDescriptorBlock(DThread* aThread, const DBase* aClientId, - TInt aSettingNum, TInt aEndpointNum, - TDes8& aEndpointDescriptor) - { - __KTRACE_OPT(KUSB, - Kern::Printf("DUsbClientController::GetCSEndpointDescriptorBlock(x, 0x%08x, %d, %d, y)", - aClientId, aSettingNum, aEndpointNum)); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); - return KErrNotFound; - } - return iDescriptors.GetCSEndpointDescriptorTC(aThread, aEndpointDescriptor, ifcset, - aSettingNum, EpIdx2Addr(aEndpointNum)); - } - - -/** Sets a block of (i.e. one or more) non-standard (class-specific) endpoint descriptors for a specific - endpoint. - - @param aThread A pointer to the thread the LDD requesting the setting of the descriptor block is running - in. - @param aClientId A pointer to the LDD requesting the setting of the descriptor block. - @param aSettingNum The setting number of the interface that contains the endpoint for which the - descriptor block is to be set. - @param aEndpointNum The endpoint for which the descriptor block is to be set. - @param aEndpointDescriptor A reference to a buffer which contains the descriptor block to be set (most - likely located user-side). - @param aSize The size of the descriptor block to be set. - - @return KErrNotFound if the specified interface or endpoint couldn't be found, KErrArgument if aSize is - less than 2, KErrNoMemory if enough memory for the new descriptor(s) couldn't be allocated, otherwise the - return value of the thread read operation, Kern::ThreadRead(), when reading from the source buffer. -*/ -EXPORT_C TInt DUsbClientController::SetCSEndpointDescriptorBlock(DThread* aThread, const DBase* aClientId, - TInt aSettingNum, TInt aEndpointNum, - const TDes8& aEndpointDescriptor, TInt aSize) - { - __KTRACE_OPT(KUSB, - Kern::Printf("DUsbClientController::SetCSEndpointDescriptorBlock(x, 0x%08x, %d, %d, y)", - aClientId, aSettingNum, aEndpointNum)); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); - return KErrNotFound; - } - if (aSize < 2) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aSize < 2 (%d)", aSize)); - return KErrArgument; - } - return iDescriptors.SetCSEndpointDescriptorTC(aThread, aEndpointDescriptor, ifcset, - aSettingNum, EpIdx2Addr(aEndpointNum), aSize); - } - - -/** Returns the total size all non-standard (class-specific) endpoint descriptors for a specific endpoint. - - @param aThread A pointer to the thread the LDD requesting the descriptor block size is running in. - @param aClientId A pointer to the LDD requesting the descriptor block size. - @param aSettingNum The setting number of the interface for which the descriptor block size is - requested. - @param aEndpointNum The endpoint for which the descriptor block size is requested. - @param aSize A reference to a buffer into which the requested descriptor block size should be written (most - likely located user-side). - - @return KErrNotFound if the specified interface or endpoint couldn't be found, otherwise the return value - of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetCSEndpointDescriptorBlockSize(DThread* aThread, const DBase* aClientId, - TInt aSettingNum, TInt aEndpointNum, - TDes8& aSize) - { - __KTRACE_OPT(KUSB, - Kern::Printf("DUsbClientController::GetCSEndpointDescriptorBlockSize(x, 0x%08x, %d, %d, y)", - aClientId, aSettingNum, aEndpointNum)); - const TInt ifcset = ClientId2InterfaceNumber(aClientId); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); - return KErrNotFound; - } - TInt s; - const TInt r = iDescriptors.GetCSEndpointDescriptorSize(ifcset, aSettingNum, - EpIdx2Addr(aEndpointNum), s); - if (r == KErrNone) - { - const TPtrC8 size(reinterpret_cast(&s), sizeof(s)); - Kern::ThreadDesWrite(aThread, &aSize, size, 0); - } - else - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: cs endpoint descriptor not found")); - } - return r; - } - - -/** Returns the currently set string descriptor language ID (LANGID) code. - - @param aThread A pointer to the thread the LDD requesting the LANGID is running in. - @param aLangId A reference to a buffer into which the requested code should be written (most likely - located user-side). - - @return The return value of the thread write operation, Kern::ThreadDesWrite(), - when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetStringDescriptorLangId(DThread* aThread, TDes8& aLangId) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetStringDescriptorLangId()")); - return iDescriptors.GetStringDescriptorLangIdTC(aThread, aLangId); - } - - -/** Sets the string descriptor language ID (LANGID) code. - - @param aLangId The langauge ID code to be written. - - @return KErrNone. -*/ -EXPORT_C TInt DUsbClientController::SetStringDescriptorLangId(TUint16 aLangId) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetStringDescriptorLangId()")); - return iDescriptors.SetStringDescriptorLangId(aLangId); - } - - -/** Returns the currently set Manufacturer string (which is referenced by the iManufacturer field in the device - descriptor). - - (Thus, the function should actually be called either 'GetManufacturerString' - or 'GetManufacturerStringDescriptorString'.) - - @param aThread A pointer to the thread the LDD requesting the string is running in. - @param aString A reference to a buffer into which the requested string should be written (most likely - located user-side). - - @return KErrNotFound if the string descriptor couldn't be found (PIL internal error), otherwise the return - value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetManufacturerStringDescriptor(DThread* aThread, TDes8& aString) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetManufacturerStringDescriptor()")); - return iDescriptors.GetManufacturerStringDescriptorTC(aThread, aString); - } - - -/** Sets a new Manufacturer string in the Manufacturer string descriptor (which is referenced by the - iManufacturer field in the device descriptor). - - (Thus, the function should actually be called either - 'SetManufacturerString' or 'SetManufacturerStringDescriptorString'.) - - @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. - @param aString A reference to a buffer which contains the string to be set (most likely located - user-side). - - @return KErrNoMemory if not enough memory for the new descriptor or the string could be allocated, the - return value of the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong, - KErrNone if new string descriptor successfully set. -*/ -EXPORT_C TInt DUsbClientController::SetManufacturerStringDescriptor(DThread* aThread, const TDes8& aString) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetManufacturerStringDescriptor()")); - return iDescriptors.SetManufacturerStringDescriptorTC(aThread, aString); - } - - -/** Removes (deletes) the Manufacturer string descriptor (which is referenced by the - iManufacturer field in the device descriptor). - - @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found -*/ -EXPORT_C TInt DUsbClientController::RemoveManufacturerStringDescriptor() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveManufacturerStringDescriptor()")); - return iDescriptors.RemoveManufacturerStringDescriptor(); - } - - -/** Returns the currently set Product string (which is referenced by the iProduct field in the device - descriptor). - - (Thus, the function should actually be called either 'GetProductString' or - 'GetProductStringDescriptorString'.) - - @param aThread A pointer to the thread the LDD requesting the string is running in. - @param aString A reference to a buffer into which the requested string should be written (most likely - located user-side). - - @return KErrNotFound if the string descriptor couldn't be found (PIL internal error), otherwise the return - value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetProductStringDescriptor(DThread* aThread, TDes8& aString) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetProductStringDescriptor()")); - return iDescriptors.GetProductStringDescriptorTC(aThread, aString); - } - - -/** Sets a new Product string in the Product string descriptor (which is referenced by the iProduct field in - the device descriptor). - - (Thus, the function should actually be called either 'SetProductString' or - 'SetProductStringDescriptorString'.) - - @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. - @param aString A reference to a buffer which contains the string to be set (most likely located - user-side). - - @return KErrNoMemory if not enough memory for the new descriptor or the string could be allocated, the - return value of the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong, - KErrNone if new string descriptor successfully set. -*/ -EXPORT_C TInt DUsbClientController::SetProductStringDescriptor(DThread* aThread, const TDes8& aString) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetProductStringDescriptor()")); - return iDescriptors.SetProductStringDescriptorTC(aThread, aString); - } - - -/** Removes (deletes) the Product string descriptor (which is referenced by the - iProduct field in the device descriptor). - - @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found -*/ -EXPORT_C TInt DUsbClientController::RemoveProductStringDescriptor() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveProductStringDescriptor()")); - return iDescriptors.RemoveProductStringDescriptor(); - } - - -/** Returns the currently set SerialNumber string (which is referenced by the iSerialNumber field in the device - descriptor). - - (Thus, the function should actually be called either 'GetSerialNumberString' or - 'GetSerialNumberStringDescriptorString'.) - - @param aThread A pointer to the thread the LDD requesting the string is running in. - @param aString A reference to a buffer into which the requested string should be written (most likely - located user-side). - - @return KErrNotFound if the string descriptor couldn't be found (PIL internal error), otherwise the return - value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetSerialNumberStringDescriptor(DThread* aThread, TDes8& aString) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetSerialNumberStringDescriptor()")); - return iDescriptors.GetSerialNumberStringDescriptorTC(aThread, aString); - } - - -/** Sets a new SerialNumber string in the SerialNumber string descriptor (which is referenced by the - iSerialNumber field in the device descriptor). - - (Thus, the function should actually be called either - 'SetSerialNumberString' or 'SetSerialNumberStringDescriptorString'.) - - @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. - @param aString A reference to a buffer which contains the string to be set (most likely located - user-side). - - @return KErrNoMemory if not enough memory for the new descriptor or the string could be allocated, the - return value of the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong, - KErrNone if new string descriptor successfully set. -*/ -EXPORT_C TInt DUsbClientController::SetSerialNumberStringDescriptor(DThread* aThread, const TDes8& aString) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetSerialNumberStringDescriptor()")); - return iDescriptors.SetSerialNumberStringDescriptorTC(aThread, aString); - } - - -/** Removes (deletes) the Serial Number string descriptor (which is referenced by the - iSerialNumber field in the device descriptor). - - @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found -*/ -EXPORT_C TInt DUsbClientController::RemoveSerialNumberStringDescriptor() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveSerialNumberStringDescriptor()")); - return iDescriptors.RemoveSerialNumberStringDescriptor(); - } - - -/** Returns the currently set Configuration string (which is referenced by the iConfiguration field in the - configuration descriptor). - - (Thus, the function should actually be called either 'GetConfigurationString' or - 'GetConfigurationStringDescriptorString'.) - - @param aThread A pointer to the thread the LDD requesting the string is running in. - @param aString A reference to a buffer into which the requested string should be written (most likely - located user-side). - - @return KErrNotFound if the string descriptor couldn't be found (PIL internal error), otherwise the return - value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetConfigurationStringDescriptor(DThread* aThread, TDes8& aString) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetConfigurationStringDescriptor()")); - return iDescriptors.GetConfigurationStringDescriptorTC(aThread, aString); - } - - -/** Sets a new Configuration string in the Configuration string descriptor (which is referenced by the - iConfiguration field in the configuration descriptor). - - (Thus, the function should actually be called either - 'SetConfigurationString' or 'SetConfigurationStringDescriptorString'.) - - @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. - @param aString A reference to a buffer which contains the string to be set (most likely located - user-side). - - @return KErrNoMemory if not enough memory for the new descriptor or the string could be allocated, the - return value of the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong, - KErrNone if new string descriptor successfully set. -*/ -EXPORT_C TInt DUsbClientController::SetConfigurationStringDescriptor(DThread* aThread, const TDes8& aString) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetConfigurationStringDescriptor()")); - return iDescriptors.SetConfigurationStringDescriptorTC(aThread, aString); - } - - -/** Removes (deletes) the Configuration string descriptor (which is referenced by the - iConfiguration field in the configuration descriptor). - - @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found. -*/ -EXPORT_C TInt DUsbClientController::RemoveConfigurationStringDescriptor() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveConfigurationStringDescriptor()")); - return iDescriptors.RemoveConfigurationStringDescriptor(); - } - - -/** Copies the string descriptor at the specified index in the string descriptor array into - the aString argument. - - @param aIndex The position of the string descriptor in the string descriptor array. - @param aThread A pointer to the thread the LDD requesting the string is running in. - @param aString A reference to a buffer into which the requested string should be written (most likely - located user-side). - - @return KErrNone if successful, KErrNotFound if no string descriptor exists at the specified index, or the - return value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. -*/ -EXPORT_C TInt DUsbClientController::GetStringDescriptor(DThread* aThread, TUint8 aIndex, TDes8& aString) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetStringDescriptor(%d)", aIndex)); - return iDescriptors.GetStringDescriptorTC(aThread, aIndex, aString); - } - - -/** Sets the aString argument to be a string descriptor at the specified index in the string - descriptor array. If a string descriptor already exists at that position then it will be replaced. - - @param aIndex The position of the string descriptor in the string descriptor array. - @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. - @param aString A reference to a buffer which contains the string to be set (most likely located - user-side). - - @return KErrNone if successful, KErrArgument if aIndex is invalid, KErrNoMemory if no memory is available - to store the new string (an existing descriptor at that index will be preserved), or the return value of - the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong. -*/ -EXPORT_C TInt DUsbClientController::SetStringDescriptor(DThread* aThread, TUint8 aIndex, const TDes8& aString) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetStringDescriptor(%d)", aIndex)); - return iDescriptors.SetStringDescriptorTC(aThread, aIndex, aString); - } - - -/** Removes (deletes) the string descriptor at the specified index in the string descriptor array. - - @param aIndex The position of the string descriptor in the string descriptor array. - - @return KErrNone if successful, KErrNotFound if no string descriptor exists at the specified index. -*/ -EXPORT_C TInt DUsbClientController::RemoveStringDescriptor(TUint8 aIndex) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveStringDescriptor(%d)", aIndex)); - return iDescriptors.RemoveStringDescriptor(aIndex); - } - - -/** Queries the use of and endpoint resource. - - If the resource gets successfully allocated, it will be used from when the current bus transfer - has been completed. - - @param aClientId A pointer to the LDD querying the endpoint resource. - @param aEndpointNum The number of the endpoint. - @param aResource The endpoint resource to be queried. - - @return ETrue if the specified resource is in use at the endpoint, EFalse if not or if there was any error - during the execution of the function. -*/ -EXPORT_C TBool DUsbClientController::QueryEndpointResource(const DBase* /*aClientId*/, TInt aEndpointNum, - TUsbcEndpointResource aResource) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::QueryEndpointResource()")); - return iController.QueryEndpointResource(aEndpointNum, aResource); - } - - -EXPORT_C TInt DUsbClientController::EndpointPacketSize(const DBase* aClientId, TInt aEndpointNum) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EndpointPacketSize(0x%08x, %d)", - aClientId, aEndpointNum)); - - const TUsbcInterfaceSet* const ifcset_ptr = ClientId2InterfacePointer(aClientId); - if (!ifcset_ptr) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface or clientid not found")); - return -1; - } - const TUsbcInterface* const ifc_ptr = ifcset_ptr->iInterfaces[ifcset_ptr->iCurrentInterface]; - const RPointerArray& ep_array = ifc_ptr->iEndpoints; - const TInt n = ep_array.Count(); - for (TInt i = 0; i < n; i++) - { - const TUsbcLogicalEndpoint* const ep = ep_array[i]; - if (EpAddr2Idx(ep->iPEndpoint->iEndpointAddr) == static_cast(aEndpointNum)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Endpoint packet sizes: FS = %d HS = %d", - ep->iEpSize_Fs, ep->iEpSize_Hs)); - const TInt size = iHighSpeed ? ep->iEpSize_Hs : ep->iEpSize_Fs; - __KTRACE_OPT(KUSB, Kern::Printf(" Returning %d", size)); - return size; - } - } - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: endpoint not found")); - return -1; - } - -EXPORT_C TDfcQue* DUsbClientController::DfcQ(TInt /*aIndex*/) - { - return iControllerProperties.iDfcQueue; - } - -EXPORT_C void DUsbClientController::DumpRegisters() - { - return; - } - -EXPORT_C TInt DUsbClientController::SignalRemoteWakeup() - { - return iController.SignalRemoteWakeup(); - } - -EXPORT_C TBool DUsbClientController::CurrentlyUsingHighSpeed() - { - UsbShai::TSpeed speed = iController.DeviceOperatingSpeed(); - - return (speed == UsbShai::EHighSpeed)?ETrue:EFalse; - } - -// -// === USB Controller member function implementations - PSL API (public) =========================== -// - -/** Gets called by the PSL to register a newly created derived class controller object. - - @param aUdc The number of the new UDC. It should be 0 for the first (or only) UDC in the system, 1 for the - second one, and so forth. KUsbcMaxUdcs determines how many UDCs are supported. - - @return A pointer to the controller if successfully registered, NULL if aUdc out of (static) range. - - @publishedPartner @released -*/ -TInt DUsbClientController::RegisterUdc(TInt aUdc) - { - TInt err = KErrNone; - - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterUdc()")); - - if (aUdc < 0 || aUdc > (KUsbcMaxUdcs - 1)) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aUdc out of range (%d)", aUdc)); - return KErrInUse; - } - else - { - UsbClientController[aUdc] = this; - } - - return err; - } - - -// -// === USB Controller member function implementations - PSL API (protected) ======================== -// - -/** Initialises an instance of this class, which is the base class of the derived class (= PSL, which is - supposed to call this function). - - It does the following things: - - - disconnects the UDC from the bus, - - initialises the USB descriptor pool, uses data from the PSL (see function argument list) - - creates and initialises the basic USB device configuration - - initialises the array of physical endpoints - - initialises Ep0 structures (but doesn't configure & enable Ep0 yet) - - creates and installs the USB power handler - - @param aDeviceDesc A pointer to a valid standard USB device descriptor or NULL. The values initially - required in the descriptor follow from its constructor. The descriptor is not copied over, but rather this - pointer is queued directly into the descriptor pool. Must be writable memory. - - @param aConfigDesc A pointer to a valid standard USB configuration descriptor or NULL. The values - initially required in the descriptor follow from its constructor. The descriptor is not copied over, but - rather this pointer is queued directly into the descriptor pool. Must be writable memory. - - @param aLangId A pointer to a valid USB language ID (string) descriptor. The values initially required in - the descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is - queued directly into the descriptor pool. Must be writable memory. Other than the remaining four string - descriptors, this one is not optional. The reason is that the USB spec mandates a LangId descriptor as - soon as a single string descriptor gets returned by the device. So, even though the device might omit the - Manufacturer, Product, SerialNumber, and Configuration string descriptors, it is at this point not known - whether there will be any Interface string descriptors. Since any USB API user can create an interface - with an Interface string descriptor, we have to insist here on the provision of a LangId string - descriptor. (The PIL decides at run-time whether or not to return the LangId string descriptor to the - host, depending on whether there exist any string descriptors at that time.) - - @param aManufacturer A pointer to a valid USB string descriptor or NULL. The values initially required in - the descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is - queued directly into the descriptor pool. Must be writable memory. This descriptor will be referenced by - the iManufacturer field in the device descriptor. - - @param aProduct A pointer to a valid USB string descriptor or NULL. The values initially required in the - descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is - queued directly into the descriptor pool. Must be writable memory. This descriptor will be referenced by - the iProduct field in the device descriptor. - - @param aSerialNum A pointer to a valid USB string descriptor or NULL. The values initially required in the - descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is - queued directly into the descriptor pool. Must be writable memory. This descriptor will be referenced by - the iSerialNumber field in the device descriptor. - - @param aConfig A pointer to a valid USB string descriptor or NULL. The values initially required in the - descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is - queued directly into the descriptor pool. Must be writable memory. This descriptor will be referenced by - the iConfiguration field in the configuration descriptor. - - @param aOtgDesc A pointer to a valid USB OTG descriptor (if OTG is supported by this device and is to be - supported by the driver) or NULL. The values initially required in the descriptor follow from its - constructor. The descriptor is not copied over, but rather this pointer is queued directly into the - descriptor pool. Must be writable memory. - - @return EFalse, if USB descriptor pool initialisation fails, or if configuration creation fails, or if the - PSL reports more endpoints than the constant KUsbcMaxEndpoints permits, or if the Ep0 logical endpoint - creation fails, or if the creation of the power handler fails; ETrue, if base class object successfully - initialised. - - @publishedPartner @released -*/ -TBool DUsbClientController::Initialise(TUsbPeripheralDescriptorPool& aDescPool, - const UsbShai::TUsbPeripheralEndpointCaps* aEndpointCaps, - TInt aTotalEndpoints) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::InitialiseBaseClass()")); - - // We don't want the host to see us (at least not yet): - UsbDisconnect(); - - iDeviceTotalEndpoints = aTotalEndpoints; - - // Initialise USB descriptor pool - if (iDescriptors.Init(aDescPool.iDeviceDesc, - aDescPool.iConfigDesc, - aDescPool.iLangId, - aDescPool.iManufacturer, - aDescPool.iProduct, - aDescPool.iSerialNum, - aDescPool.iConfig, - aDescPool.iOtgDesc) != KErrNone) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Error: Descriptor initialization failed")); - return EFalse; - } - - if (aDescPool.iOtgDesc) - { - iOtgSupport = ETrue; - iOtgFuncMap = aDescPool.iOtgDesc->DescriptorData()[2]; - } - - // Some member variables - iSelfPowered = aDescPool.iConfigDesc->Byte(7) & (1 << 6); // Byte 7: bmAttributes - iRemoteWakeup = aDescPool.iConfigDesc->Byte(7) & (1 << 5); - - if (iControllerProperties.iControllerCaps & UsbShai::KDevCapHighSpeed) - { - if (iDescriptors.InitHs() != KErrNone) - { - return EFalse; - } - } - - // Create and initialise our first (and only) configuration - TUsbcConfiguration* config = new TUsbcConfiguration(1); - if (!config) - { - return EFalse; - } - iConfigs.Append(config); - - // Initialise the array of physical endpoints - __KTRACE_OPT(KUSB, Kern::Printf(" DeviceTotalEndpoints: %d", aTotalEndpoints)); - - // KUsbcMaxEndpoints doesn't include ep 0 - if ((aTotalEndpoints > (KUsbcMaxEndpoints + 2)) || - ((aTotalEndpoints * sizeof(TUsbcPhysicalEndpoint)) > sizeof(iRealEndpoints))) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: too many endpoints! (change KUsbcMaxEndpoints: %d)", - KUsbcMaxEndpoints)); - return EFalse; - } - - for (TInt i = 0; i < aTotalEndpoints; ++i) - { - iRealEndpoints[i].iEndpointAddr = EpIdx2Addr(i); - - __KTRACE_OPT(KUSB, Kern::Printf(" aEndpointCaps[%02d] - iTypes: 0x%08x iSizes: 0x%08x", - i, aEndpointCaps[i].iTypesAndDir, aEndpointCaps[i].iSizes)); - - iRealEndpoints[i].iCaps = aEndpointCaps[i]; - - // Reset revered bytes to zero - iRealEndpoints[i].iCaps.iReserved[0] = 0; - iRealEndpoints[i].iCaps.iReserved[1] = 0; - - if ((i > 1) && (aEndpointCaps[i].iTypesAndDir != UsbShai::KUsbEpNotAvailable)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" --> UsableEndpoint: #%d", i)); - iDeviceUsableEndpoints++; - } - } - - // Initialise Ep0 structures (logical endpoints are numbered 1..KMaxEndpointsPerClient, - // and virtual 0 is real 0): - // -- Ep0 OUT - iEp0MaxPacketSize = MaxEndpointPacketSize(aEndpointCaps[0].iSizes); - __KTRACE_OPT(KUSB, Kern::Printf(" using Ep0 maxpacketsize of %d bytes", iEp0MaxPacketSize)); - - TUsbcEndpointInfo info(UsbShai::KUsbEpTypeControl, UsbShai::KUsbEpDirOut, 0); - TUsbcLogicalEndpoint* ep = NULL; - - info.iSize = iEp0MaxPacketSize; - ep = new TUsbcLogicalEndpoint(this, 0, info, NULL, &iRealEndpoints[KEp0_Out]); - if (!ep) - { - return EFalse; - } - - __KTRACE_OPT(KUSB, Kern::Printf(" creating ep: mapping real ep %d --> logical ep 0", KEp0_Out)); - iRealEndpoints[KEp0_Out].iLEndpoint = ep; - - // -- Ep0 IN - info.iDir = UsbShai::KUsbEpDirIn; - ep = new TUsbcLogicalEndpoint(this, 0, info, NULL, &iRealEndpoints[KEp0_In]); - if (!ep) - { - delete iRealEndpoints[KEp0_Out].iLEndpoint; - iRealEndpoints[KEp0_Out].iLEndpoint = NULL; - return EFalse; - } - __KTRACE_OPT(KUSB, Kern::Printf(" creating ep: mapping real ep %d --> logical ep 0", KEp0_In)); - iRealEndpoints[KEp0_In].iLEndpoint = ep; - - iPowerHandler = new DUsbcPowerHandler(this); - if (!iPowerHandler) - { - delete iRealEndpoints[KEp0_Out].iLEndpoint; - iRealEndpoints[KEp0_Out].iLEndpoint = NULL; - delete iRealEndpoints[KEp0_In].iLEndpoint; - iRealEndpoints[KEp0_In].iLEndpoint = NULL; - return EFalse; - } - iPowerHandler->Add(); - - return ETrue; - } - -/** The standard constructor for this class. - - @publishedPartner @released - */ -DUsbClientController::DUsbClientController(UsbShai::MPeripheralControllerIf& aPeripheralControllerIf, - const UsbShai::TPeripheralControllerProperties& aProperties, - TBool aIsOtgPort) - : iEp0ReceivedNonStdRequest(EFalse), - iRmWakeupStatus_Enabled(EFalse), - iEp0_RxBuf(), - iDeviceTotalEndpoints(0), - iDeviceUsableEndpoints(0), - iDeviceState(UsbShai::EUsbPeripheralStateUndefined), - iDeviceStateB4Suspend(UsbShai::EUsbPeripheralStateUndefined), - iSelfPowered(EFalse), - iRemoteWakeup(EFalse), - iHardwareActivated(EFalse), - iOtgSupport(EFalse), - iOtgFuncMap(0), - iHighSpeed(EFalse), - iEp0MaxPacketSize(0), - iEp0ClientId(NULL), - iEp0DataReceived(0), - iEp0WritePending(EFalse), - iEp0ClientDataTransmitting(EFalse), - iEp0DeviceControl(NULL), - iDescriptors(iEp0_TxBuf), - iCurrentConfig(0), - iConfigs(1), - iRealEndpoints(), - iEp0_TxBuf(), - iEp0_RxExtraCount(0), - iEp0_TxNonStdCount(0), - iEp0ReadRequestCallbacks(_FOFF(TUsbcRequestCallback, iLink)), - iClientCallbacks(_FOFF(TUsbcClientCallback, iLink)), - iStatusCallbacks(_FOFF(TUsbcStatusCallback, iLink)), - iEpStatusCallbacks(_FOFF(TUsbcEndpointStatusCallback, iLink)), - iOtgCallbacks(_FOFF(TUsbcOtgFeatureCallback, iLink)), - iReconnectTimer(ReconnectTimerCallback, this), - iUsbLock(TSpinLock::EOrderGenericIrqLow3), - iController(aPeripheralControllerIf), - iControllerProperties(aProperties), - iIsOtgPort(aIsOtgPort), - iOtgObserver(NULL), - iConTransferMgr(NULL), - iLastError(EFalse), - iSetupPacketPending(EFalse), - iCommonDfcQThread(NULL), - iPowerUpDfc(PowerUpDfc, this, 3), - iPowerDownDfc(PowerDownDfc, this, 3), - iDeviceEventNotifyDfc(DeviceEventNotifyDfc,this,3), - iThreadContextFinder(ThreadContextFinderDfc,this,3), - iStandby(EFalse), - iStackIsActive(EFalse), - iClientSupportReady(EFalse), - iUsbResetDeferred(EFalse), - iEnablePullUpOnDPlus(NULL), - iDisablePullUpOnDPlus(NULL), - iOtgContext(NULL) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DUsbClientController()")); - - iLastError = KErrNone; - -#ifndef SEPARATE_USB_DFC_QUEUE - iPowerUpDfc.SetDfcQ(Kern::DfcQue0()); - iPowerDownDfc.SetDfcQ(Kern::DfcQue0()); -#endif // SEPARATE_USB_DFC_QUEUE - - for (TInt i = 0; i < KUsbcEpArraySize; i++) - iRequestCallbacks[i] = NULL; - } - -TInt DUsbClientController::Construct() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::Construct")); - - // Setup the state machines of ep0 - TInt err = SetupEp0StateMachine(); - if( err != KErrNone) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Can not setup state machines, exit")); - return err; - } - -#ifdef SEPARATE_USB_DFC_QUEUE - iPowerUpDfc.SetDfcQ(iControllerProperties.iDfcQueue); - iPowerDownDfc.SetDfcQ(iControllerProperties.iDfcQueue); -#endif // SEPARATE_USB_DFC_QUEUE - - iDeviceEventNotifyDfc.SetDfcQ(iControllerProperties.iDfcQueue); - iThreadContextFinder.SetDfcQ(iControllerProperties.iDfcQueue); - - // Register - if( RegisterUdc(0) != KErrNone) - { - // This is the only reason. - return KErrInUse; - } - - __KTRACE_OPT(KUSB, Kern::Printf(" peripheral controller registered")); - TUsbPeripheralDescriptorPool descPool; - - if( CreateDescriptors(descPool) == KErrNone) - { - __KTRACE_OPT(KUSB, Kern::Printf(" descriptors created")); - - // Initialise the array of physical endpoints - __KTRACE_OPT(KUSB, Kern::Printf(" initialising PIL ")); - TBool initOk = Initialise(descPool, - iControllerProperties.iDeviceEndpointCaps, - iControllerProperties.iDeviceTotalEndpoints); - - // Let UDC has a changes to know the callback interface is ready. - // Any further initialization/startup/preparation etc can be performed now. - if ( initOk ) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Initializing PSL ")); - - // Set Rx buffer for endpoint zero - iController.SetEp0RxBuffer(iEp0_RxBuf,KUsbcBufSzControl); - - // Set pil callback interface for PSL. - iController.SetPilCallbackInterface(*this); - - } - else - { - return KErrNoMemory; - } - } - - // Register ourself as the ONLY one client of charger detection observer - gChargerObsever = this; - - // In case the charger detector already registered, start monitor - // Charger type notifications - if( gChargerDetector != NULL ) - { - gChargerDetector->SetChargerDetectorObserver(*gChargerObsever); - } - - iThreadContextFinder.Enque(); - - return KErrNone; - } - -// This function doesn't consider the situation of OOM. -// Because, this function will be call during extension's entry point, -// There is no way to start up phone successfully if anything failed anyway... -TInt DUsbClientController::SetupEp0StateMachine() - { - // Create the state machine first - __ASSERT_DEBUG((iConTransferMgr == NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); - iConTransferMgr = new DControlTransferManager(*this); - if(iConTransferMgr == 0) - { - return KErrNoMemory; - } - - // Add UsbShai::EControlTransferStageSetup stage machine - TControlStageSm* stageSm = new DSetupStageSm(*iConTransferMgr); - __ASSERT_DEBUG((stageSm != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); - if(stageSm != NULL) - { - iConTransferMgr->AddState(UsbShai::EControlTransferStageSetup,*stageSm); - } - else - { - return KErrNoMemory; - } - - // Add EControlTransferStageDataOut stage state machine - stageSm = new DDataOutStageSm(*iConTransferMgr); - __ASSERT_DEBUG((stageSm != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); - if(stageSm != NULL) - { - iConTransferMgr->AddState(UsbShai::EControlTransferStageDataOut,*stageSm); - } - else - { - // we don't need bother to delete the previous allocated memory - // system can not bootup if we return error - return KErrNoMemory; - } - - // Add EControlTransferStageStatusIn stage state machine - stageSm = new DStatusInStageSm(*iConTransferMgr); - __ASSERT_DEBUG((stageSm != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); - if(stageSm != NULL) - { - iConTransferMgr->AddState(UsbShai::EControlTransferStageStatusIn,*stageSm); - } - else - { - return KErrNoMemory; - } - - // Add EControlTransferStageDataIn stage state machine - stageSm = new DDataInStageSm(*iConTransferMgr); - __ASSERT_DEBUG((stageSm != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); - if(stageSm != NULL) - { - iConTransferMgr->AddState(UsbShai::EControlTransferStageDataIn,*stageSm); - } - else - { - return KErrNoMemory; - } - - // Add EControlTransferStageStatusOut stage state machine - stageSm = new DStatusOutStageSm(*iConTransferMgr); - __ASSERT_DEBUG((stageSm != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); - if(stageSm != NULL) - { - iConTransferMgr->AddState(UsbShai::EControlTransferStageStatusOut,*stageSm); - } - else - { - return KErrNoMemory; - } - - return KErrNone; - } - -// --------------------------------------------------------------------------- -// From MUsbPeripheralPilCallbackIf. -// Enable the peripheral stack -// --------------------------------------------------------------------------- -// -void DUsbClientController::EnablePeripheralStack() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EnablePeripheralStack")); - - if (iStackIsActive) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Already enabled - returning")); - return; - } - - // Mark stack is enabled, Waiting upper application to power controller - // Anyway, this will lead us to attached state - iStackIsActive = ETrue; - NextDeviceState(UsbShai::EUsbPeripheralStateAttached); - - // If hardware is not activated yet, do it here. - if(iClientSupportReady && !iHardwareActivated) - { - // PowerUpUdc only do Activating Hardware when there are at least 1 - // Iterface registered. - PowerUpUdc(); - } - - } - - -// --------------------------------------------------------------------------- -// From MUsbPeripheralPilCallbackIf. -// Disable the peripheral stack -// --------------------------------------------------------------------------- -// -void DUsbClientController::DisablePeripheralStack() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DisablePeripheralStack")); - - if (!iStackIsActive) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Already disabled - returning")); - return; - } - - // Reset OTG features, leave attributes as is (just as in USB Reset case) - // (OTG spec 1.3 sections 6.5.x all say "... on a bus reset or at the end - // of a session." VBus drop is the end of a session.) - iOtgFuncMap &= KUsbOtgAttr_SrpSupp | KUsbOtgAttr_HnpSupp; - OtgFeaturesNotify(); - // Tear down the current configuration (if any) - ChangeConfiguration(0); - - if (iDeviceState != UsbShai::EUsbPeripheralStateUndefined) - { - // Not being in state UNDEFINED implies that the cable is inserted. - if (iHardwareActivated) - { - NextDeviceState(UsbShai::EUsbPeripheralStatePowered); - } - // (If the hardware is NOT activated at this point, we can only be in - // state UsbShai::EUsbPeripheralStateAttached, so we don't have to move to it.) - } - DeActivateHardwareController(); // turn off UDC altogether - iStackIsActive = EFalse; - // Notify registered clients on the user side about a USB device state - // change event and a transition to the "Undefined" state. - // Note: the state should be changed to "Undefined" before calling RunClientCallbacks(), - // otherwise the "Undefined" state will probably be lost. - NextDeviceState(UsbShai::EUsbPeripheralStateUndefined); - // Complete all pending requests, returning KErrDisconnected - RunClientCallbacks(); - } - - -// --------------------------------------------------------------------------- -// From MUsbPeripheralPilCallbackIf. -// Set the OTG Observer -// --------------------------------------------------------------------------- -// -void DUsbClientController::SetOtgObserver(MUsbOtgPeripheralObserverIf* aObserver) - { - iOtgObserver = aObserver; - } - - -/** This function gets called by the PSL upon detection of either of the following events: - - USB Reset, - - USB Suspend event, - - USB Resume signalling, - - The USB cable has been attached (inserted) or detached (removed). - - @param anEvent An enum denoting the event that has occured. - - @return KErrArgument if the event is not recognized, otherwise KErrNone. - - @publishedPartner @released -*/ -TInt DUsbClientController::DeviceEventNotification(UsbShai::TUsbPeripheralEvent anEvent) - { - TInt err = KErrNone; - - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeviceEventNotification(anEvent=%d)", anEvent)); - - switch (anEvent) - { - case UsbShai::EUsbEventSuspend: - case UsbShai::EUsbEventResume: - case UsbShai::EUsbEventReset: - case UsbShai::EUsbEventVbusRisen: - case UsbShai::EUsbEventVbusFallen: - { - TInt nkern_curr_ctx= NKern::CurrentContext(); - - if( (nkern_curr_ctx != NKern::EInterrupt) && (nkern_curr_ctx != NKern::EIDFC)) - { - // Normal context - __ASSERT_DEBUG((iCommonDfcQThread != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); - if(iCommonDfcQThread == &(Kern::CurrentThread().iNThread)) - { - // we already in the correct context, just run processes here directly. - __KTRACE_OPT(KUSB, Kern::Printf(" Correct thread context")); - ProcessDeviceEventNotification(anEvent); - } - else - { - // we're in a normal thread, but it is not the same as the DfcQ context - // passed by PSL, queue it - __KTRACE_OPT(KUSB, Kern::Printf(" Incorrect thread context")); - iDevEventQueue.FifoAdd(anEvent); - iDeviceEventNotifyDfc.Enque(); - } - } - else - { - // We're in a ISR or IDFC context - __KTRACE_OPT(KUSB, Kern::Printf(" ISR|IDFC context")); - iDevEventQueue.FifoAdd(anEvent); - iDeviceEventNotifyDfc.Add(); - } - } - break; - - default: - err = KErrArgument; - } - - return err; - } - - -/** This function gets called by the PSL upon completion of a pending data transfer request. - - This function is not to be used for endpoint zero completions (use Ep0RequestComplete instead). - - @param aCallback A pointer to a data transfer request callback structure which was previously passed to - the PSL in a SetupReadBuffer() or SetupWriteBuffer() call. - - @publishedPartner @released -*/ -void DUsbClientController::EndpointRequestComplete(UsbShai::TUsbPeripheralRequest* aCallback) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EndpointRequestComplete(%p)", aCallback)); - - TUsbcRequestCallback* cb = static_cast(aCallback); - // This function may be called by the PSL from within an ISR -- so we have - // to take care what we do here (and also in all functions that get called - // from here). - - // We don't test aCallback for NULL here (and therefore risk a crash) - // because the PSL should never give us a NULL argument. If it does it - // means the PSL is buggy and ought to be fixed. - ProcessDataTransferDone(*cb); - } - - -/** This function should be called by the PSL after reception of an Ep0 - SET_FEATURE request with a feature selector of either {b_hnp_enable, - a_hnp_support, a_alt_hnp_support}, but only when that Setup packet is not - handed up to the PIL (for instance because it is auto-decoded and - 'swallowed' by the UDC hardware). - - @param aHnpState A bitmask indicating the present state of the three OTG - feature selectors as follows: - - bit.0 == a_alt_hnp_support - bit.1 == a_hnp_support - bit.2 == b_hnp_enable - - @see DUsbClientController::ProcessSetClearDevFeature() - - @publishedPartner @released -*/ -void DUsbClientController::HandleHnpRequest(TInt aHnpState) -// This function is called by the PSL from within an ISR -- so we have to take care what we do here -// (and also in all functions that get called from here). - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::HandleHnpRequest(%d)", aHnpState)); - - if (!iOtgSupport) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only supported on a OTG device")); - return; - } - if (!(iOtgFuncMap & KUsbOtgAttr_HnpSupp)) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only valid if OTG device supports HNP")); - return; - } - // (case KUsbFeature_B_HnpEnable:) - if (aHnpState & 0x04) - { - iOtgFuncMap |= KUsbOtgAttr_B_HnpEnable; - } - // (case KUsbFeature_A_HnpSupport:) - if (aHnpState & 0x02) - { - iOtgFuncMap |= KUsbOtgAttr_A_HnpSupport; - } - // (case KUsbFeature_A_AltHnpSupport:) - if (aHnpState & 0x01) - { - iOtgFuncMap |= KUsbOtgAttr_A_AltHnpSupport; - } - OtgFeaturesNotify(); - } - -void DUsbClientController::GetEp0RxBufferInfo(TUint8*& aBuffer, TInt& aBufferLen) - { - aBuffer = iEp0_RxBuf; - aBufferLen = KUsbcBufSzControl; - } - -UsbShai::TUsbPeripheralState DUsbClientController::DeviceStatus() const - { - return iDeviceState; - } - -TBool DUsbClientController::Ep0ReceivedNonStdRequest() - { - return iEp0ReceivedNonStdRequest; - } - -/** This function gets called by the PSL upon completion of a pending endpoint zero data transfer request. - - @param aRealEndpoint Either 0 for Ep0 OUT (= Read), or 1 for Ep0 IN (= Write). - @param aCount The number of bytes received or transmitted, respectively. - @param aError The error status of the completed transfer request. Can be KErrNone if no error, KErrCancel - if transfer was cancelled, or KErrPrematureEnd if a premature status end was encountered. - - @return KErrNone if no error during transfer completion processing, KErrGeneral if the request was a read & - a Setup packet was received & the recipient for that packet couldn't be found (invalid packet: Ep0 has been - stalled), KErrNotFound if the request was a read & the recipient for that packet (Setup or data) _was_ - found - however no read had been set up by that recipient (this case should be used by the PSL to disable - the Ep0 interrupt at that point and give the LDD time to set up a new Ep0 read; once the 'missing' read - was set up either Ep0ReceiveProceed or Ep0ReadSetupPktProceed will be called by the PIL). - - @publishedPartner @released -*/ -TInt DUsbClientController::Ep0RequestComplete(TInt aRealEndpoint, - TInt aCount, - TInt aError, - UsbShai::TControlPacketType aPktType) - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::Ep0RequestComplete(%d)", aRealEndpoint)); - - iLastError = KErrNone; - - iConTransferMgr->Ep0RequestComplete(iEp0_RxBuf,aCount,aError,aPktType); - - __KTRACE_OPT(KUSB, Kern::Printf(" iLastError(%d)", iLastError)); - - if(iEp0WritePending == EFalse) - { - iConTransferMgr->SetupEndpointZeroRead(); - } - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::Ep0RequestComplete")); - return iLastError; - } - -/** This function should be called by the PSL once the UDC (and thus the USB device) is in the Address state. - - @publishedPartner @released -*/ -void DUsbClientController::MoveToAddressState() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::MoveToAddressState()")); - - // This function may be called by the PSL from within an ISR -- so we have - // to take care what we do here (and also in all functions that get called - // from here). - - NextDeviceState(UsbShai::EUsbPeripheralStateAddress); - } - - -TBool DUsbClientController::CreateDescriptors(TUsbPeripheralDescriptorPool& aOutput) - { - TInt errCode = KErrNone; - - // Create all the string descriptors - TUsbcDeviceDescriptor* deviceDesc = TUsbcDeviceDescriptor::New( - 0, // aDeviceClass, will be changed later by upper app - 0, // aDeviceSubClass, will be changed later by upper app - 0, // aDeviceProtocol, will be changed later by upper app - iControllerProperties.iMaxEp0Size , // aMaxPacketSize0 - KUsbVendorId, // aVendorId - KUsbProductId , // aProductId - iControllerProperties.iDeviceRelease, // aDeviceRelease - KUsbNumberOfConfiguration);// aNumConfigurations - __ASSERT_DEBUG( (deviceDesc != NULL), Kern::Fault( "USB PSL Out of memory, deviceDesc", __LINE__ )); - - TUsbcConfigDescriptor* configDesc = TUsbcConfigDescriptor::New( - 1, // Only one configruation is supported current. - EFalse, // at here, we always mark it as bus powered. - (iControllerProperties.iControllerCaps & UsbShai::KDevCapRemoteWakeupSupport)?ETrue:EFalse, // remote wakeup - 100); // 100 is a default value, thise value will be changed by - - __ASSERT_DEBUG( (configDesc != NULL), Kern::Fault( "USB PSL Out of memory, configDesc", __LINE__ )); - - TUsbcLangIdDescriptor* stringDescLang = TUsbcLangIdDescriptor::New(KUsbLangId); - __ASSERT_DEBUG( (stringDescLang != NULL), Kern::Fault( "USB PSL Out of memory, stringDescLang", __LINE__ )); - - // Default manufacturer string - TPtrC8 aString; - aString.Set(reinterpret_cast(KStringManufacturer), sizeof(KStringManufacturer) - 2); - TUsbcStringDescriptor* stringDescManu = TUsbcStringDescriptor::New(aString); - __ASSERT_DEBUG( (stringDescManu != NULL), Kern::Fault( "USB PSL Out of memory, stringDescManu", __LINE__ )); - - // Default product name string - aString.Set(reinterpret_cast(KStringProduct), sizeof(KStringProduct) - 2); - TUsbcStringDescriptor* stringDescProd = TUsbcStringDescriptor::New(aString); - __ASSERT_DEBUG( (stringDescProd != NULL), Kern::Fault( "USB PSL Out of memory, stringDescProd", __LINE__ )); - - // Default configuration name string - aString.Set(reinterpret_cast(KStringConfig), sizeof(KStringConfig) - 2); - TUsbcStringDescriptor* stringDescConf = TUsbcStringDescriptor::New(aString); - __ASSERT_DEBUG( (stringDescConf != NULL), Kern::Fault( "USB PSL Out of memory, stringDescConf", __LINE__ )); - - // Default serial bumber string - aString.Set(reinterpret_cast(KStringSerial), sizeof(KStringSerial) - 2); - TUsbcStringDescriptor* stringSerial = TUsbcStringDescriptor::New(aString); - __ASSERT_DEBUG( (stringSerial != NULL), Kern::Fault( "USB PSL Out of memory, stringDescConf", __LINE__ )); - - TUsbcOtgDescriptor* otgDesc = NULL; - - // In an OTG-environment, we also need to create the OTG - // descriptor. The PSL supports both HNP and SRP and hence we - // report support for them. Upper layers will override the - // descriptors anyway. - if (iIsOtgPort) - { - TBool srpSupported = (iControllerProperties.iControllerCaps & UsbShai::KDevCapSrpSupport)?ETrue:EFalse; - TBool hnpSupported = (iControllerProperties.iControllerCaps & UsbShai::KDevCapHnpSupport)?ETrue:EFalse; - - otgDesc = TUsbcOtgDescriptor::New(srpSupported, - hnpSupported); - - __ASSERT_DEBUG( (otgDesc != NULL), Kern::Fault( "USB PSL Out of memory, otgDesc", __LINE__ )); - } - - if( (deviceDesc != NULL) && - (configDesc != NULL) && - (stringDescLang != NULL) && - (stringDescManu != NULL) && - (stringDescProd != NULL) && - (stringDescConf != NULL) && - ((!iIsOtgPort) || (iIsOtgPort && (otgDesc != NULL)))) - { - aOutput.iDeviceDesc = deviceDesc; - aOutput.iConfigDesc = configDesc; - aOutput.iLangId = stringDescLang; - aOutput.iManufacturer = stringDescManu; - aOutput.iProduct = stringDescProd; - aOutput.iConfig = stringDescConf; - aOutput.iSerialNum = stringSerial; - aOutput.iOtgDesc = otgDesc; - } - else - { - if( deviceDesc != NULL ) - { - delete deviceDesc; - } - - if( configDesc != NULL ) - { - delete configDesc; - } - - if( stringDescLang != NULL ) - { - delete stringDescLang; - } - - if( stringDescManu != NULL ) - { - delete stringDescManu; - } - - if( stringDescProd != NULL ) - { - delete stringDescProd; - } - - if( stringDescConf != NULL ) - { - delete stringDescConf; - } - - if( stringSerial != NULL ) - { - delete stringSerial; - } - - if( otgDesc != NULL ) - { - delete otgDesc; - } - - errCode = KErrNoMemory; - } - - // We don't support serial number - aOutput.iSerialNum = NULL; - - return errCode; - } - -// -// === USB Controller member function implementations - Internal utility functions (private) ======= -// - -TInt DUsbClientController::DeRegisterClientCallback(const DBase* aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterClientCallback()")); - __ASSERT_DEBUG((aClientId != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); - TSglQueIter iter(iClientCallbacks); - TUsbcClientCallback* p; - while ((p = iter++) != NULL) - if (p->Owner() == aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf(" removing ClientCallback @ 0x%x", p)); - iClientCallbacks.Remove(*p); - return KErrNone; - } - __KTRACE_OPT(KUSB, Kern::Printf(" Client not found")); - return KErrNotFound; - } - - -TBool DUsbClientController::CheckEpAvailability(TInt aEndpointsUsed, - const TUsbcEndpointInfoArray& aEndpointData, - TInt aIfcNumber) const - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CheckEpAvailability()")); - if (aEndpointsUsed > KMaxEndpointsPerClient) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: too many endpoints claimed (%d)", aEndpointsUsed)); - return EFalse; - } - TBool reserve[KUsbcEpArraySize]; // iDeviceTotalEndpoints can be equal to 32 - memset(reserve, EFalse, sizeof(reserve)); // reset the array - for (TInt i = 0; i < aEndpointsUsed; ++i) - { - __KTRACE_OPT(KUSB, Kern::Printf(" checking for (user) endpoint #%d availability...", i + 1)); - TInt j = 2; - while (j < iDeviceTotalEndpoints) - { - if ((iRealEndpoints[j].EndpointSuitable(&aEndpointData[i], aIfcNumber)) && - (reserve[j] == EFalse)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" ---> found suitable endpoint: RealEndpoint #%d", j)); - reserve[j] = ETrue; // found one: mark this ep as reserved - break; - } - __KTRACE_OPT(KUSB, Kern::Printf(" -> endpoint not suitable: RealEndpoint #%d", j)); - j++; - } - if (j == iDeviceTotalEndpoints) - { - return EFalse; - } - } - return ETrue; - } - - -TUsbcInterface* DUsbClientController::CreateInterface(const DBase* aClientId, TInt aIfc, TUint32 aFeatureWord) -// We know that 9.2.3 says: "Interfaces are numbered from zero to one less than the number of -// concurrent interfaces supported by the configuration." But since we permit the user to -// change interface numbers, we can neither assume nor enforce anything about them here. - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CreateInterface(x, aIfc=%d)", aIfc)); - TUsbcInterfaceSet* ifcset_ptr = NULL; - TInt ifcset = ClientId2InterfaceNumber(aClientId); - TBool new_ifc; - if (ifcset < 0) - { - // New interface(set), so we need to find a number for it. - new_ifc = ETrue; - const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); - if (num_ifcsets == 255) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Too many interfaces already exist: 255")); - return NULL; - } - // Find the smallest interface number that has not yet been used. - for (ifcset = 0; ifcset < 256; ++ifcset) - { - TBool n_used = EFalse; - for (TInt i = 0; i < num_ifcsets; ++i) - { - if ((iConfigs[0]->iInterfaceSets[i]->iInterfaceNumber) == ifcset) - { - __KTRACE_OPT(KUSB, Kern::Printf(" interface number %d already used", ifcset)); - n_used = ETrue; - break; - } - } - if (!n_used) - { - break; - } - } - if (ifcset == 256) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no available interface number found")); - return NULL; - } - // append the ifcset - __KTRACE_OPT(KUSB, Kern::Printf(" creating new InterfaceSet %d first", ifcset)); - if (aIfc != 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface setting number (1): %d", aIfc)); - return NULL; - } - if ((ifcset_ptr = new TUsbcInterfaceSet(aClientId, ifcset)) == NULL) - { - __KTRACE_OPT(KPANIC, - Kern::Printf(" Error: new TUsbcInterfaceSet(aClientId, ifcset_num) failed")); - return NULL; - } - iConfigs[0]->iInterfaceSets.Append(ifcset_ptr); - } - else /* if (ifcset_num >= 0) */ - { - // use an existent ifcset - new_ifc = EFalse; - __KTRACE_OPT(KUSB, Kern::Printf(" using existing InterfaceSet %d", ifcset)); - ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); - if (aIfc != ifcset_ptr->iInterfaces.Count()) - { - // 9.2.3: "Alternate settings range from zero to one less than the number of alternate - // settings for a specific interface." (Thus we can here only append a setting.) - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface setting number (2): %d", aIfc)); - return NULL; - } - // Check whether the existing interface belongs indeed to this client - if (ifcset_ptr->iClientId != aClientId) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: iClientId (%p) != aClientId (%p)", - ifcset_ptr->iClientId, aClientId)); - return NULL; - } - } - const TBool no_ep0_requests = aFeatureWord & KUsbcInterfaceInfo_NoEp0RequestsPlease; - TUsbcInterface* const ifc_ptr = new TUsbcInterface(ifcset_ptr, aIfc, no_ep0_requests); - if (!ifc_ptr) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: new TUsbcInterface(ifcset, aIfc) failed")); - if (new_ifc) - { - DeleteInterfaceSet(ifcset); - } - return NULL; - } - ifcset_ptr->iInterfaces.Append(ifc_ptr); - return ifc_ptr; - } - - -#define RESET_SETTINGRESERVE \ - for (TInt i = start_ep; i < iDeviceTotalEndpoints; i++) \ - { \ - if (iRealEndpoints[i].iSettingReserve) \ - iRealEndpoints[i].iSettingReserve = EFalse; \ - } \ - -TInt DUsbClientController::CreateEndpoints(TUsbcInterface* aIfc, TInt aEndpointsUsed, - const TUsbcEndpointInfoArray& aEndpointData, - TInt aRealEpNumbers[]) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CreateEndpoints()")); - const TInt ifc_num = aIfc->iInterfaceSet->iInterfaceNumber; - const TInt start_ep = 2; - for (TInt i = 0; i < aEndpointsUsed; ++i) - { - for (TInt j = start_ep; j < iDeviceTotalEndpoints; ++j) - { - if (iRealEndpoints[j].EndpointSuitable(&aEndpointData[i], ifc_num)) - { - // Logical endpoints are numbered 1..KMaxEndpointsPerClient (virtual 0 is real 0 and 1) - TUsbcLogicalEndpoint* const ep = new TUsbcLogicalEndpoint(this, i + 1, aEndpointData[i], - aIfc, &iRealEndpoints[j]); - if (!ep) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: new TUsbcLogicalEndpoint() failed")); - aIfc->iEndpoints.ResetAndDestroy(); - RESET_SETTINGRESERVE; - return KErrNoMemory; - } - aIfc->iEndpoints.Append(ep); - // Check on logical endpoint's sizes for compliance with special restrictions. - if (aIfc->iSettingCode == 0) - { - // For details see last paragraph of 5.7.3 "Interrupt Transfer Packet Size Constraints". - if ((ep->iInfo.iType == UsbShai::KUsbEpTypeInterrupt) && (ep->iEpSize_Hs > 64)) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: INT ep HS size = %d on default ifc setting", - ep->iEpSize_Hs)); - __KTRACE_OPT(KPANIC, Kern::Printf(" (should be <= 64)")); - } - // For details see last paragraph of 5.6.3 "Isochronous Transfer Packet Size Constraints". - else if ((ep->iInfo.iType == UsbShai::KUsbEpTypeIsochronous) && (ep->iInfo.iSize > 0)) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: ISO ep size = %d on default ifc setting", - ep->iInfo.iSize)); - __KTRACE_OPT(KPANIC, Kern::Printf(" (should be zero or ep non-existent)")); - } - } - // If the endpoint doesn't support DMA (now or never) the next operation - // will be a successful no-op. - /* - const TInt r = OpenDmaChannel(j); - if (r != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Opening of DMA channel failed")); - aIfc->iEndpoints.ResetAndDestroy(); - RESET_SETTINGRESERVE; - return r; - } - */ - __KTRACE_OPT(KUSB, Kern::Printf(" creating ep: mapping real ep %d -> logical ep %d", - j, i + 1)); - iRealEndpoints[j].iIfcNumber = &aIfc->iInterfaceSet->iInterfaceNumber; - iRealEndpoints[j].iSettingReserve = ETrue; - __KTRACE_OPT(KUSB, - Kern::Printf(" ep->iInfo: iType=0x%x iDir=0x%x iSize=%d iInterval=%d", - ep->iInfo.iType, ep->iInfo.iDir, ep->iInfo.iSize, - ep->iInfo.iInterval)); - __KTRACE_OPT(KUSB, - Kern::Printf(" ep->iInfo: iInterval_Hs=%d iTransactions=%d iExtra=%d", - ep->iInfo.iInterval_Hs, ep->iInfo.iTransactions, - ep->iInfo.iExtra)); - // Store real endpoint numbers: - // array[x] holds the number for logical ep x. - aRealEpNumbers[i + 1] = j; - break; - } - } - } - aRealEpNumbers[0] = 0; // ep0: 0. - __KTRACE_OPT(KUSB,{ - Kern::Printf(" Endpoint Mapping for Interface %d / Setting %d:", ifc_num, aIfc->iSettingCode); - Kern::Printf("Logical | Real"); - Kern::Printf("Endpoint | Endpoint"); - for (TInt ep = 0; ep <= aEndpointsUsed; ++ep) Kern::Printf(" %2d %3d",ep, aRealEpNumbers[ep]); - }); - RESET_SETTINGRESERVE; - return KErrNone; - } - - -TInt DUsbClientController::SetupIfcDescriptor(TUsbcInterface* aIfc, TUsbcClassInfo& aClass, DThread* aThread, - TDesC8* aString, const TUsbcEndpointInfoArray& aEndpointData) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetupIfcDescriptor()")); - - // Interface descriptor - TUsbcDescriptorBase* d = TUsbcInterfaceDescriptor::New(aIfc->iInterfaceSet->iInterfaceNumber, - aIfc->iSettingCode, - aIfc->iEndpoints.Count(), - aClass); - if (!d) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for ifc desc failed.")); - return KErrNoMemory; - } - iDescriptors.InsertDescriptor(d); - - // Interface string descriptor - if (aString) - { - // we don't know the length of the string, so we have to allocate memory dynamically - TUint strlen = Kern::ThreadGetDesLength(aThread, aString); - if (strlen > KUsbStringDescStringMaxSize) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: $ descriptor too long - string will be truncated")); - strlen = KUsbStringDescStringMaxSize; - } - HBuf8* const stringbuf = HBuf8::New(strlen); - if (!stringbuf) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for ifc $ desc string failed.")); - iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, - aIfc->iSettingCode); - return KErrNoMemory; - } - stringbuf->SetMax(); - // the aString points to data that lives in user memory, so we have to copy it: - TInt r = Kern::ThreadDesRead(aThread, aString, *stringbuf, 0); - if (r != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Thread read error")); - iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, - aIfc->iSettingCode); - delete stringbuf; - return r; - } - TUsbcStringDescriptor* const sd = TUsbcStringDescriptor::New(*stringbuf); - if (!sd) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for ifc $ desc failed.")); - iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, - aIfc->iSettingCode); - delete stringbuf; - return KErrNoMemory; - } - iDescriptors.SetIfcStringDescriptor(sd, aIfc->iInterfaceSet->iInterfaceNumber, aIfc->iSettingCode); - delete stringbuf; // the (EPOC) descriptor was copied by New() - } - - // Endpoint descriptors - for (TInt i = 0; i < aIfc->iEndpoints.Count(); ++i) - { - // The reason for using another function argument for Endpoint Info - // (and not possibly - similar to the Endpoint Address - - // "aIfc->iEndpoints[i]->iPEndpoint->iLEndpoint->iInfo") is that this time - // there are no logical endpoints associated with our real endpoints, - // i.e. iLEndpoint is NULL!. - if (aEndpointData[i].iExtra) - { - // if a non-standard endpoint descriptor is requested... - if (aEndpointData[i].iExtra != 2) - { - // ...then it must be a Audio Class endpoint descriptor. Else... - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: EP desc extension > 2 bytes (%d)", - aEndpointData[i].iExtra)); - iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, - aIfc->iSettingCode); - return KErrArgument; - } - d = TUsbcAudioEndpointDescriptor::New(aIfc->iEndpoints[i]->iPEndpoint->iEndpointAddr, - aEndpointData[i]); - } - else - { - d = TUsbcEndpointDescriptor::New(aIfc->iEndpoints[i]->iPEndpoint->iEndpointAddr, - aEndpointData[i]); - } - if (!d) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for ep desc #%d failed.", i)); - iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, - aIfc->iSettingCode); - return KErrNoMemory; - } - iDescriptors.InsertDescriptor(d); - } - - return KErrNone; - } - - -TInt DUsbClientController::ClientId2InterfaceNumber(const DBase* aClientId) const - { - const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); - for (TInt i = 0; i < num_ifcsets; ++i) - { - if (iConfigs[0]->iInterfaceSets[i]->iClientId == aClientId) - { - return iConfigs[0]->iInterfaceSets[i]->iInterfaceNumber; - } - } - return -1; - } - - -TUsbcInterfaceSet* DUsbClientController::ClientId2InterfacePointer(const DBase* aClientId) const - { - const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); - for (TInt i = 0; i < num_ifcsets; ++i) - { - if (iConfigs[0]->iInterfaceSets[i]->iClientId == aClientId) - { - return iConfigs[0]->iInterfaceSets[i]; - } - } - return NULL; - } - - -const DBase* DUsbClientController::InterfaceNumber2ClientId(TInt aIfcSet) const - { - if (!InterfaceExists(aIfcSet)) - { - return NULL; - } - return InterfaceNumber2InterfacePointer(aIfcSet)->iClientId; - } - - -TUsbcInterfaceSet* DUsbClientController::InterfaceNumber2InterfacePointer(TInt aIfcSet) const - { - const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); - for (TInt i = 0; i < num_ifcsets; ++i) - { - if ((iConfigs[0]->iInterfaceSets[i]->iInterfaceNumber) == aIfcSet) - { - return iConfigs[0]->iInterfaceSets[i]; - } - } - return NULL; - } - - -TInt DUsbClientController::ActivateHardwareController() - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::ActivateHardwareController()")); - - // iStackIsActive must be ETrue at this time - // the caller of this function shall checked that iStackIsActive is ETrue - __ASSERT_DEBUG(iStackIsActive, Kern::Fault(KUsbPILPanicCat, __LINE__)); - - if (iHardwareActivated) - { - __KTRACE_OPT(KUSB, Kern::Printf(" already active -> returning")); - return KErrNone; - } - // Initialise HW - TInt r = iController.StartPeripheralController(); - if (r != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: StartPeripheralController() failed")); - return KErrHardwareNotAvailable; - } - - iHardwareActivated = ETrue; - - // Configure & enable endpoint zero - const TUsbcLogicalEndpoint* const ep0_0 = iRealEndpoints[0].iLEndpoint; - const TUsbcLogicalEndpoint* const ep0_1 = iRealEndpoints[1].iLEndpoint; - if (iHighSpeed) - { - const_cast(ep0_0)->iInfo.iSize = ep0_0->iEpSize_Hs; - const_cast(ep0_1)->iInfo.iSize = ep0_1->iEpSize_Hs; - } - else - { - const_cast(ep0_0)->iInfo.iSize = ep0_0->iEpSize_Fs; - const_cast(ep0_1)->iInfo.iSize = ep0_1->iEpSize_Fs; - } - iController.ConfigureEndpoint(0, ep0_0->iInfo); - iController.ConfigureEndpoint(1, ep0_1->iInfo); - iEp0MaxPacketSize = ep0_0->iInfo.iSize; - - __KTRACE_OPT(KUSB, Kern::Printf(" Controller activated.")); - - // Controller is powered up, changes device state to powered - NextDeviceState(UsbShai::EUsbPeripheralStatePowered); - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::ActivateHardwareController()")); - return KErrNone;; - } - - -void DUsbClientController::DeActivateHardwareController() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeActivateHardwareController()")); - if (!iHardwareActivated) - { - __KTRACE_OPT(KUSB, Kern::Printf(" not active -> returning")); - return; - } - // Deconfigure & disable endpoint zero - iController.DeConfigureEndpoint(KEp0_Out); - iController.DeConfigureEndpoint(KEp0_In); - // Stop HW - iController.StopPeripheralController(); - iHardwareActivated = EFalse; - __KTRACE_OPT(KUSB, Kern::Printf(" Controller deactivated.")); - - // Always go to attached state, until statck is disabled - NextDeviceState(UsbShai::EUsbPeripheralStateAttached); - - return; - } - - -void DUsbClientController::DeleteInterfaceSet(TInt aIfcSet) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeleteInterfaceSet(%d)", aIfcSet)); - TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(aIfcSet); - if (!ifcset_ptr) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface number: %d", aIfcSet)); - return; - } - const TInt idx = iConfigs[0]->iInterfaceSets.Find(ifcset_ptr); - if (idx == KErrNotFound) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface not found in array")); - return; - } - //Add this mutex to protect the interface set data structure - if (NKern::CurrentContext() == EThread) - { - NKern::FMWait(&iMutex); - } - - iConfigs[0]->iInterfaceSets.Remove(idx); - if (NKern::CurrentContext() == EThread) - { - NKern::FMSignal(&iMutex); - } - delete ifcset_ptr; - } - - -void DUsbClientController::DeleteInterface(TInt aIfcSet, TInt aIfc) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeleteInterface(%d, %d)", aIfcSet, aIfc)); - TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(aIfcSet); - if (!ifcset_ptr) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface number: %d", aIfcSet)); - return; - } - if (ifcset_ptr->iInterfaces.Count() <= aIfc) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface setting: %d", aIfc)); - return; - } - //Add this mutex to protect the interface set data structure - if (NKern::CurrentContext() == EThread) - { - NKern::FMWait(&iMutex); - } - TUsbcInterface* const ifc_ptr = ifcset_ptr->iInterfaces[aIfc]; - // Always first remove, then delete (see ~TUsbcLogicalEndpoint() for the reason why) - ifcset_ptr->iInterfaces.Remove(aIfc); - - if (aIfc == ifcset_ptr->iCurrentInterface) - { - __KTRACE_OPT(KUSB, Kern::Printf(" > Warning: deleting current interface setting")); - ifcset_ptr->iCurrentInterface = 0; - } - if (NKern::CurrentContext() == EThread) - { - NKern::FMSignal(&iMutex); - } - delete ifc_ptr; - } - - -void DUsbClientController::CancelTransferRequests(TInt aRealEndpoint) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CancelTransferRequests(aRealEndpoint=%d)", - aRealEndpoint)); - const DBase* const clientId = PEndpoint2ClientId(aRealEndpoint); - if (EpIdx2Addr(aRealEndpoint) & KUsbEpAddress_In) - { - CancelWriteBuffer(clientId, aRealEndpoint); - } - else - { - CancelReadBuffer(clientId, aRealEndpoint); - } - } - - -void DUsbClientController::DeleteRequestCallback(const DBase* aClientId, TInt aEndpointNum, - UsbShai::TTransferDirection aTransferDir) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeleteRequestCallback()")); - // Ep0 OUT - if (aEndpointNum == 0) - { - const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); - TSglQueIter iter(iEp0ReadRequestCallbacks); - TUsbcRequestCallback* p; - while ((p = iter++) != NULL) - { - if (p->Owner() == aClientId) - { - __ASSERT_DEBUG((p->iRealEpNum == 0), Kern::Fault(KUsbPILPanicCat, __LINE__)); - __ASSERT_DEBUG((p->iTransferDir == UsbShai::EControllerRead), Kern::Fault(KUsbPILPanicCat, __LINE__)); - __KTRACE_OPT(KUSB, Kern::Printf(" removing RequestCallback @ 0x%x (ep0)", p)); - iEp0ReadRequestCallbacks.Remove(*p); - } - } - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - return; - } - // Other endpoints - TUsbcRequestCallback* const p = iRequestCallbacks[aEndpointNum]; - if (p) - { - __ASSERT_DEBUG((p->Owner() == aClientId), Kern::Fault(KUsbPILPanicCat, __LINE__)); - __ASSERT_DEBUG((p->iTransferDir == aTransferDir), Kern::Fault(KUsbPILPanicCat, __LINE__)); - __KTRACE_OPT(KUSB, Kern::Printf(" removing RequestCallback @ 0x%x", p)); - iRequestCallbacks[aEndpointNum] = NULL; - } - } - - -void DUsbClientController::DeleteRequestCallbacks(const DBase* aClientId) - { - // aClientId being NULL means: delete all requests for *all* clients. - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeleteRequestCallbacks()")); - // Ep0 OUT - const TInt irq = __SPIN_LOCK_IRQSAVE(iUsbLock); - TSglQueIter iter(iEp0ReadRequestCallbacks); - TUsbcRequestCallback* p; - while ((p = iter++) != NULL) - { - if (!aClientId || p->Owner() == aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf(" removing RequestCallback @ 0x%x (ep0)", p)); - iEp0ReadRequestCallbacks.Remove(*p); - } - } - __SPIN_UNLOCK_IRQRESTORE(iUsbLock, irq); - // Other endpoints - for (TInt i = 1; i < KUsbcEpArraySize; i++) - { - TUsbcRequestCallback* const p = iRequestCallbacks[i]; - if (p && (!aClientId || p->Owner() == aClientId)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" removing RequestCallback @ 0x%x", p)); - iRequestCallbacks[i] = NULL; - } - } - } - - -void DUsbClientController::StatusNotify(UsbShai::TUsbPeripheralState aState, const DBase* aClientId) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::StatusNotify()")); - - // This function may be called by the PSL (via chapter9.cpp) from within an - // ISR -- so we have to take care what we do here (and also in all - // functions that get called from here). - - TSglQueIter iter(iStatusCallbacks); - TUsbcStatusCallback* p; - while ((p = iter++) != NULL) - { - if (!aClientId || aClientId == p->Owner()) - { - __KTRACE_OPT(KUSB, Kern::Printf(" notifying LDD @ 0x%x about %d", p->Owner(), aState)); - p->SetState(aState); - p->DoCallback(); - } - } - } - - -void DUsbClientController::EpStatusNotify(TInt aRealEndpoint) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EpStatusNotify()")); - - // This function may be called by the PSL (via chapter9.cpp) from within an - // ISR -- so we have to take care what we do here (and also in all - // functions that get called from here). - - const DBase* const client_id = PEndpoint2ClientId(aRealEndpoint); - if (!client_id) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Client not found for real ep %d", aRealEndpoint)); - return; - } - // Check if there is a notification request queued for that client (if not, we can return here). - TSglQueIter iter(iEpStatusCallbacks); - TUsbcEndpointStatusCallback* p; - while ((p = iter++) != NULL) - { - if (p->Owner() == client_id) - { - break; - } - } - if (!p) - { - __KTRACE_OPT(KUSB, Kern::Printf(" No notification request for that client, returning")); - return; - } - const TInt ifcset = ClientId2InterfaceNumber(client_id); - if (ifcset < 0) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Ifcset not found for clientid %d", client_id)); - return; - } - const TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); - if (!ifcset_ptr) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Ifcset pointer not found for ifcset %d", ifcset)); - return; - } - const TUsbcInterface* const ifc_ptr = ifcset_ptr->CurrentInterface(); - if (!ifc_ptr) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Current ifc pointer not found for ifcset %d", ifcset)); - return; - } - TUint state = 0; - const TInt eps = ifc_ptr->iEndpoints.Count(); - for (TInt i = 0; i < eps; i++) - { - const TUsbcLogicalEndpoint* const ep_ptr = ifc_ptr->iEndpoints[i]; - __KTRACE_OPT(KUSB, Kern::Printf(" checking logical ep #%d for stall state...", - ep_ptr->iLEndpointNum)); - if (ep_ptr->iPEndpoint->iHalt) - { - __KTRACE_OPT(KUSB, Kern::Printf(" -- stalled")); - // set the bit n to 1, where n is the logical endpoint number minus one - state |= (1 << (ep_ptr->iLEndpointNum - 1)); - } - else - { - __KTRACE_OPT(KUSB, Kern::Printf(" -- not stalled")); - } - } - __KTRACE_OPT(KUSB, Kern::Printf(" passing ep state 0x%x on to LDD @ 0x%x", state, client_id)); - p->SetState(state); - p->DoCallback(); - } - - -void DUsbClientController::OtgFeaturesNotify() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::OtgFeaturesNotify()")); - - // This function may be called from the PSL (via PIL's chapter9.cpp) from - // within an ISR -- so we have to take care what we do here (and also in - // all functions that get called from here). - - TSglQueIter iter(iOtgCallbacks); - TUsbcOtgFeatureCallback* p; - while ((p = iter++) != NULL) - { - p->SetFeatures(iOtgFuncMap & 0x1C); - p->DoCallback(); - } - } - - -void DUsbClientController::RunClientCallbacks() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RunClientCallbacks()")); - TSglQueIter iter(iClientCallbacks); - TUsbcClientCallback* p; - while ((p = iter++) != NULL) - { - __KTRACE_OPT(KUSB, Kern::Printf("Callback 0x%x", p)); - p->DoCallback(); - } - } - - -void DUsbClientController::ProcessDataTransferDone(TUsbcRequestCallback& aRcb) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessDataTransferDone()")); - // This piece can only be called in thread context from ProcessEp0DataReceived() / - // ProcessEp0SetupReceived() via the call to ProcessEp0ReceiveDone() in - // SetupReadBuffer(), which is guarded by an interrupt lock. - TInt ep = aRcb.iRealEpNum; - if (ep == 0) - { - if (aRcb.iTransferDir == UsbShai::EControllerRead) - { - // Ep0 OUT is special - iEp0ReadRequestCallbacks.Remove(aRcb); - } - else // UsbShai::EControllerWrite - { - // Ep0 IN needs to be adjusted: it's '1' within the PIL. - ep = KEp0_Tx; - } - } - if (ep > 0) // not 'else'! - { - __ASSERT_DEBUG((iRequestCallbacks[ep] == &aRcb), Kern::Fault(KUsbPILPanicCat, __LINE__)); - __KTRACE_OPT(KUSB, Kern::Printf(" > removing RequestCallback[%d] @ 0x%x", ep, &aRcb)); - iRequestCallbacks[ep] = NULL; - } - aRcb.DoCallback(); - } - - -void DUsbClientController::NextDeviceState(UsbShai::TUsbPeripheralState aNextState) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::NextDeviceState()")); -#ifdef _DEBUG - const char* const states[] = {"Undefined", "Attached", "Powered", "Default", - "Address", "Configured", "Suspended"}; - if ((aNextState >= UsbShai::EUsbPeripheralStateUndefined) && - (aNextState <= UsbShai::EUsbPeripheralStateSuspended)) - { - __KTRACE_OPT(KUSB, Kern::Printf(" next device state: %s", states[aNextState])); - } - else - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown next device state: %d", aNextState)); - } - // Print a warning when an invalid state transition is detected - // 'Undefined' is not a state that is mentioned in the USB spec, but - // that's what we're in once the cable gets pulled (for instance). - switch (iDeviceState) - { - case UsbShai::EUsbPeripheralStateUndefined: - // valid: Undefined -> Attached - if (aNextState != UsbShai::EUsbPeripheralStateAttached) - break; - goto OK; - case UsbShai::EUsbPeripheralStateAttached: - // valid: Attached -> {Undefined, Powered} - if ((aNextState != UsbShai::EUsbPeripheralStateUndefined) && - (aNextState != UsbShai::EUsbPeripheralStatePowered)) - break; - goto OK; - case UsbShai::EUsbPeripheralStatePowered: - // valid: Powered -> {Undefined, Attached, Default, Suspended} - if ((aNextState != UsbShai::EUsbPeripheralStateUndefined) && - (aNextState != UsbShai::EUsbPeripheralStateAttached) && - (aNextState != UsbShai::EUsbPeripheralStateDefault) && - (aNextState != UsbShai::EUsbPeripheralStateSuspended)) - break; - goto OK; - case UsbShai::EUsbPeripheralStateDefault: - // valid: Default -> {Undefined, Powered, Default, Address, Suspended} - if ((aNextState != UsbShai::EUsbPeripheralStateUndefined) && - (aNextState != UsbShai::EUsbPeripheralStatePowered) && - (aNextState != UsbShai::EUsbPeripheralStateDefault) && - (aNextState != UsbShai::EUsbPeripheralStateAddress) && - (aNextState != UsbShai::EUsbPeripheralStateSuspended)) - break; - goto OK; - case UsbShai::EUsbPeripheralStateAddress: - // valid: Address -> {Undefined, Powered, Default, Configured, Suspended} - if ((aNextState != UsbShai::EUsbPeripheralStateUndefined) && - (aNextState != UsbShai::EUsbPeripheralStatePowered) && - (aNextState != UsbShai::EUsbPeripheralStateDefault) && - (aNextState != UsbShai::EUsbPeripheralStateConfigured) && - (aNextState != UsbShai::EUsbPeripheralStateSuspended)) - break; - goto OK; - case UsbShai::EUsbPeripheralStateConfigured: - // valid: Configured -> {Undefined, Powered, Default, Address, Suspended} - if ((aNextState != UsbShai::EUsbPeripheralStateUndefined) && - (aNextState != UsbShai::EUsbPeripheralStatePowered) && - (aNextState != UsbShai::EUsbPeripheralStateDefault) && - (aNextState != UsbShai::EUsbPeripheralStateAddress) && - (aNextState != UsbShai::EUsbPeripheralStateSuspended)) - break; - goto OK; - case UsbShai::EUsbPeripheralStateSuspended: - // valid: Suspended -> {Undefined, Powered, Default, Address, Configured} - if ((aNextState != UsbShai::EUsbPeripheralStateUndefined) && - (aNextState != UsbShai::EUsbPeripheralStatePowered) && - (aNextState != UsbShai::EUsbPeripheralStateDefault) && - (aNextState != UsbShai::EUsbPeripheralStateAddress) && - (aNextState != UsbShai::EUsbPeripheralStateConfigured)) - break; - goto OK; - default: - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown current device state: %d", iDeviceState)); - goto OK; - } - // KUSB only (instead of KPANIC) so as not to worry people too much where - // a particular h/w regularly enforces invalid (but harmless) transitions - __KTRACE_OPT(KUSB, Kern::Printf(" Warning: Invalid next state from %s", states[iDeviceState])); -OK: -#endif // _DEBUG - - iDeviceState = aNextState; - StatusNotify(iDeviceState); - } - - -TInt DUsbClientController::ProcessSuspendEvent() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSuspendEvent()")); - // A suspend interrupt has been received and needs attention. - iDeviceStateB4Suspend = iDeviceState; - - // We have to move to the Suspend state immediately (in case it's a genuine Suspend) - // because 7.1.7.6 says: "The device must actually be suspended, [...] after no more - // than 10ms of bus inactivity [...]." Assuming we got the interrupt 3ms after the - // Suspend condition arose, we have now 7ms left. - NextDeviceState(UsbShai::EUsbPeripheralStateSuspended); - iController.Suspend(); - - return KErrNone; - } - -TInt DUsbClientController::ProcessResumeEvent() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessResumeEvent()")); - if (iDeviceState == UsbShai::EUsbPeripheralStateSuspended) - { - NextDeviceState(iDeviceStateB4Suspend); - } - iController.Resume(); - return KErrNone; - } - - -TInt DUsbClientController::ProcessResetEvent(TBool aPslUpcall) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessResetEvent()")); - - if (aPslUpcall) - { - // Call back into PSL if we're coming from there. - // Also, do it always, even when PIL processing will be deferred. - iController.Reset(); - } - - // In an OTG-environment, some OTG controllers have implemented - // the OTG state machine in HW and connect to the bus - // automatically already before the SW has indicated - // readiness. Peripheral PSL operating on top of such controller - // may report a reset event already before the upper layers are - // ready. In this case we defer the reset processing to after the - // upper layers have indicated their readiness. - if (iUsbResetDeferred) - { - __KTRACE_OPT(KUSB, Kern::Printf(" User-side (still) not ready -> returning")); - return KErrNone; - } - else if (!iClientSupportReady) - { - // Wait with the PIL Reset processing until user-side is ready - __KTRACE_OPT(KUSB, Kern::Printf(" User-side not ready -> deferring")); - iUsbResetDeferred = ETrue; - return KErrNone; - } - - if (iDeviceState == UsbShai::EUsbPeripheralStateAttached) - { - NextDeviceState(UsbShai::EUsbPeripheralStatePowered); - } - // Notify the world. (This will just queue a DFC, so users won't actually be - // notified before we return. But we change the device state already here so - // ChangeConfiguration will see the correct one.) - NextDeviceState(UsbShai::EUsbPeripheralStateDefault); - // Tear down the current configuration (never called from thread) - ChangeConfiguration(0); - // Reset essential vars - ResetEp0DataOutVars(); - //iEp0_RxExtraData = EFalse; - iEp0WritePending = EFalse; - iEp0ClientDataTransmitting = EFalse; - - iLastError = KErrNone; - iSetupPacketPending = EFalse; - //iEp0_RxExtraError = 0; - iConTransferMgr->Reset(); - - // Reset OTG features, leave attributes as is - iOtgFuncMap &= KUsbOtgAttr_SrpSupp | KUsbOtgAttr_HnpSupp; - if (iOtgSupport) - { - OtgFeaturesNotify(); - } - - // Check whether there's a speed change - const TBool was_hs = iHighSpeed; - iHighSpeed = CurrentlyUsingHighSpeed(); - if (!was_hs && iHighSpeed) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Moving to High-speed")); - EnterHighSpeed(); - } - else if (was_hs && !iHighSpeed) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Moving to Full-speed")); - EnterFullSpeed(); - } - - // Setup initial Ep0 read (SetupEndpointZeroRead never called from thread) - if (iConTransferMgr->SetupEndpointZeroRead() != KErrNone) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: while setting up Ep0 read")); - return KErrGeneral; - } - - return KErrNone; - } - - -TInt DUsbClientController::ProcessVbusRisenEvent() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessVbusRisenEvent()")); - if (iIsOtgPort) - { - // In an OTG environment, this notification is not expected - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: EUsbEventVbusRisen shouldn't be sent by an OTG Client PSL")); - return KErrArgument; - } - else - { - // In a non-OTG environment, seeing VBUS rising causes the - // peripheral stack to be enabled - EnablePeripheralStack(); - return KErrNone; - } - } - - -TInt DUsbClientController::ProcessVbusFallenEvent() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessVbusFallenEvent()")); - if (iIsOtgPort) - { - // In an OTG environment, this notification is not expected - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: EUsbEventVbusFallen shouldn't be sent by an OTG Client PSL")); - return KErrArgument; - } - else - { - // In a non-OTG environment, seeing VBUS falling causes the - // peripheral stack to be disabled - DisablePeripheralStack(); - return KErrNone; - } - } - - -void DUsbClientController::EnterFullSpeed() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EnterFullSpeed()")); - iDescriptors.UpdateDescriptorsFs(); - } - - -void DUsbClientController::EnterHighSpeed() - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EnterHighSpeed()")); - iDescriptors.UpdateDescriptorsHs(); - } - - -// -// DFC (static), we are runing in a DFC context. -// -void DUsbClientController::ReconnectTimerCallback(TAny *aPtr) - { - __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ReconnectTimerCallback()")); - if (!aPtr) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: !aPtr")); - return; - } - - DUsbClientController* const ptr = static_cast(aPtr); - - ptr->UsbConnect(); - - } - -// -// static Dfc function -// -void DUsbClientController::PowerUpDfc(TAny* aPtr) - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::PowerUpDfc")); - if (!aPtr) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: !aPtr")); - return; - } - - DUsbClientController* const ptr = static_cast(aPtr); - - __PM_ASSERT(ptr->iStandby); - - ptr->iStandby = EFalse; - - // We have nothing to do when powerup - ptr->iPowerHandler->PowerUpDone(); - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::PowerUpDfc")); - return ; - } - -// -// static Dfc function -// -void DUsbClientController::PowerDownDfc(TAny* aPtr) - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::PowerDownDfc")); - if (!aPtr) - { - __KTRACE_OPT(KPANIC, Kern::Printf(" Error: !aPtr")); - return; - } - - DUsbClientController* const ptr = static_cast(aPtr); - __PM_ASSERT(!ptr->iStandby); - - ptr->iStandby = ETrue; - - // Disable stack(stop controller inside) - ptr->DisablePeripheralStack(); - - ptr->iPowerHandler->PowerDownDone(); - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::PowerDownDfc")); - return ; - } - -// -// Static Dfc function -// -void DUsbClientController::DeviceEventNotifyDfc(TAny* aPtr) - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::DeviceEventNotifyDfc")); - DUsbClientController* const ptr = static_cast(aPtr); - - UsbShai::TUsbPeripheralEvent event = ptr->iDevEventQueue.FifoGet(); - - if( event == -1) - { - // No event queued - __KTRACE_OPT(KUSB, Kern::Printf(" Warning, No event found, exit !!!")); - return; - } - - ptr->ProcessDeviceEventNotification(event); - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::DeviceEventNotifyDfc")); - } - -// -// Static Dfc function -// -void DUsbClientController::ThreadContextFinderDfc(TAny* aPtr) - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::ThreadContextFinderDfc")); - - DUsbClientController* const ptr = static_cast(aPtr); - - ptr->iCommonDfcQThread = NKern::CurrentThread(); - __KTRACE_OPT(KUSB, Kern::Printf(" iCommonDfcQThread = %d",ptr->iCommonDfcQThread)); - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::ThreadContextFinderDfc")); - } -// -// -// -void DUsbClientController::ProcessDeviceEventNotification(UsbShai::TUsbPeripheralEvent aEvent) - { - __KTRACE_OPT(KUSB, Kern::Printf("> DUsbClientController::ProcessDeviceEventNotification %d",aEvent)); - // If an OTG Observer has registered, forward the event - // notification to it as well - if (iOtgObserver != NULL) - { - __KTRACE_OPT(KUSB, Kern::Printf(" Forwarding to OTG Observer")); - iOtgObserver->NotifyPeripheralEvent(aEvent); - } - - // This function may be called by the PSL from within an ISR -- so we have - // to take care what we do here (and also in all functions that get called - // from here). - - switch (aEvent) - { - case UsbShai::EUsbEventSuspend: - ProcessSuspendEvent(); - break; - case UsbShai::EUsbEventResume: - ProcessResumeEvent(); - break; - case UsbShai::EUsbEventReset: - ProcessResetEvent(); - break; - case UsbShai::EUsbEventVbusRisen: - ProcessVbusRisenEvent(); - break; - case UsbShai::EUsbEventVbusFallen: - ProcessVbusFallenEvent(); - break; - - default: - break; - } - - __KTRACE_OPT(KUSB, Kern::Printf("< DUsbClientController::ProcessDeviceEventNotification")); - } - -// Functions from UsbShai::MChargerDetectorObserverIf -void DUsbClientController::NotifyPortType(UsbShai::TPortType aPortType) - { - // FIXME: Not yet implemented! - } - -void DUsbClientController::Buffer2Setup(const TAny* aBuf, TUsbcSetup& aSetup) const - { - // TUint8 index - aSetup.iRequestType = static_cast(aBuf)[0]; - aSetup.iRequest = static_cast(aBuf)[1]; - // TUint16 index from here! - aSetup.iValue = SWAP_BYTES_16((static_cast(aBuf))[1]); - aSetup.iIndex = SWAP_BYTES_16((static_cast(aBuf))[2]); - aSetup.iLength = SWAP_BYTES_16((static_cast(aBuf))[3]); - } - -TUsbPeriDeviceEventQueue::TUsbPeriDeviceEventQueue() - { - iDeviceQueueHead = 0; - iDeviceQueueTail = 0; - } - -// FifoAdd will be called from Isr or IDfc context -// be careful when processing -void TUsbPeriDeviceEventQueue::FifoAdd(UsbShai::TUsbPeripheralEvent aDeviceEvent) - { - __KTRACE_OPT(KUSB, Kern::Printf("> TUsbPeriDeviceEventQueue::FifoAdd %d , %d",iDeviceQueueHead,iDeviceQueueTail)); - iDeviceEventQueue[iDeviceQueueTail] = aDeviceEvent; - - iDeviceQueueTail ++; - iDeviceQueueTail %= KUsbDeviceEventQueueDepth; - if(iDeviceQueueTail == iDeviceQueueHead) - { - __KTRACE_OPT(KUSB, Kern::Printf("TUsbPeriDeviceEventQueue::FifoAdd overflow, oldest event missed")); - iDeviceQueueHead ++; - iDeviceQueueHead %= KUsbDeviceEventQueueDepth; - } - __KTRACE_OPT(KUSB, Kern::Printf("< TUsbPeriDeviceEventQueue::FifoAdd %d , %d",iDeviceQueueHead,iDeviceQueueTail)); - } - -// FifoAdd will be called from thread context -UsbShai::TUsbPeripheralEvent TUsbPeriDeviceEventQueue::FifoGet() - { - __KTRACE_OPT(KUSB, Kern::Printf("> TUsbPeriDeviceEventQueue::FifoGet %d , %d",iDeviceQueueHead,iDeviceQueueTail)); - UsbShai::TUsbPeripheralEvent ret = (UsbShai::TUsbPeripheralEvent)-1; - - if(iDeviceQueueHead != iDeviceQueueTail) - { - ret = iDeviceEventQueue[iDeviceQueueHead]; - iDeviceQueueHead++; - iDeviceQueueHead %= KUsbDeviceEventQueueDepth; - } - __KTRACE_OPT(KUSB, Kern::Printf("< TUsbPeriDeviceEventQueue::FifoGet %d , %d",iDeviceQueueHead,iDeviceQueueTail)); - return ret; - } - -/** Sets some data members of this request for a read request. - - @param aBufferStart The start of the data buffer to be filled. - @param aBufferAddr The physical address of the buffer (used for DMA). - @param aPacketIndex A pointer to the packet index values array. - @param aPacketSize A pointer to the packet size values array. - @param aLength The number of bytes to be received. -*/ -EXPORT_C void TUsbcRequestCallback::SetRxBufferInfo(TUint8* aBufferStart, TUintPtr aBufferAddr, - TUint32* aPacketIndex, - TUint32* aPacketSize, - TInt aLength) - { - iTransferDir = UsbShai::EControllerRead; - iBufferStart = aBufferStart; - iBufferAddr = aBufferAddr; - iPacketIndex = aPacketIndex; - iPacketSize = aPacketSize; - iLength = aLength; - } - - -/** Sets some data members of this request for a write request. - - @param aBufferStart The start of the buffer that contains the data to be sent. - @param aBufferAddr The physical address of the buffer (used for DMA). - @param aLength The number of bytes to be transmitted. -*/ -EXPORT_C void TUsbcRequestCallback::SetTxBufferInfo(TUint8* aBufferStart, TUintPtr aBufferAddr, TInt aLength) - { - iTransferDir = UsbShai::EControllerWrite; - iBufferStart = aBufferStart; - iBufferAddr = aBufferAddr; - iLength = aLength; - } - -EXPORT_C UsbShai::TUsbPeripheralRequest::TUsbPeripheralRequest(TInt aRealEpNum): - iRealEpNum(aRealEpNum), - iBufferStart(NULL), - iBufferAddr(0), - iLength(0), - iTxBytes(0), - iRxPackets(0), - iPacketIndex(NULL), // actually TUint16 (*)[] - iPacketSize(NULL), // actually TUint16 (*)[] - iTransferDir(EControllerNone), - iZlpReqd(EFalse), - iError(KErrNone) - { - } - -// Peripheral PSL use this interface to register itself to PIL layer, in our case, -// DUsbClientController instance -// -// param aPeripheralControllerIf point to an implementation of -// UsbShai::MPeripheralControllerIf which represent a peripheral controller hardware. -EXPORT_C void UsbShai::UsbPeripheralPil::RegisterPeripheralController( UsbShai::MPeripheralControllerIf& aPeripheralControllerIf, - const UsbShai::TPeripheralControllerProperties& aProperties) - { - __KTRACE_OPT(KUSB, Kern::Printf("> UsbPeripheralPil::RegisterPeripheralController enter.")); - - DUsbClientController* usbcc = DUsbClientController::Create(aPeripheralControllerIf, - aProperties, - /*aIsOtgPort=*/EFalse); - __ASSERT_DEBUG( (usbcc != NULL), - Kern::Fault( "DUsbClientController extension entry point: USB PSL Out of memory", __LINE__ ) ); - } - -// The way for charger detector(PSL) to make it known to us. -EXPORT_C void UsbShai::UsbChargerDetectionPil::RegisterChargerDetector(UsbShai::MChargerDetectorIf& aChargerDetector, - UsbShai::TChargerDetectorProperties& aProperties) - { - // Only on charger detector is allowed per system. - if( gChargerDetector != NULL) - { - return ; - } - - gChargerDetector = &aChargerDetector; - - if(gChargerObsever != NULL) - { - // Register to charger detector to listen to any charger type change - // events. - gChargerDetector->SetChargerDetectorObserver(*gChargerObsever); - } - } - -// -EOF-