sl@0: // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32/drivers/usbcc/misc.cpp sl@0: // Platform independent layer (PIL) of the USB Device controller driver: sl@0: // Implementations of misc. classes defined in usbc.h. sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file misc.cpp sl@0: @internalTechnology sl@0: */ sl@0: sl@0: #include sl@0: sl@0: sl@0: /** Helper function for logical endpoints and endpoint descriptors: sl@0: Split single Ep size into separate FS/HS sizes. sl@0: This function modifies its arguments. sl@0: */ sl@0: TInt TUsbcEndpointInfo::AdjustEpSizes(TInt& aEpSize_Fs, TInt& aEpSize_Hs) const sl@0: { sl@0: if (iType == KUsbEpTypeBulk) sl@0: { sl@0: // FS: [8|16|32|64] HS: 512 sl@0: if (iSize < 64) sl@0: { sl@0: aEpSize_Fs = iSize; sl@0: } sl@0: else sl@0: { sl@0: aEpSize_Fs = 64; sl@0: } sl@0: aEpSize_Hs = 512; sl@0: } sl@0: else if (iType == KUsbEpTypeInterrupt) sl@0: { sl@0: // FS: [0..64] HS: [0..1024] sl@0: if (iSize < 64) sl@0: { sl@0: aEpSize_Fs = iSize; sl@0: } sl@0: else sl@0: { sl@0: aEpSize_Fs = 64; sl@0: } sl@0: aEpSize_Hs = iSize; sl@0: } sl@0: else if (iType == KUsbEpTypeIsochronous) sl@0: { sl@0: // FS: [0..1023] HS: [0..1024] sl@0: if (iSize < 1023) sl@0: { sl@0: aEpSize_Fs = iSize; sl@0: } sl@0: else sl@0: { sl@0: aEpSize_Fs = 1023; sl@0: } sl@0: aEpSize_Hs = iSize; sl@0: } sl@0: else if (iType == KUsbEpTypeControl) sl@0: { sl@0: // FS: [8|16|32|64] HS: 64 sl@0: if (iSize < 64) sl@0: { sl@0: aEpSize_Fs = iSize; sl@0: } sl@0: else sl@0: { sl@0: aEpSize_Fs = 64; sl@0: } sl@0: aEpSize_Hs = 64; sl@0: } sl@0: else sl@0: { sl@0: aEpSize_Fs = aEpSize_Hs = 0; sl@0: return KErrGeneral; sl@0: } sl@0: sl@0: // For the reason of the following checks see Table 9-14. "Allowed wMaxPacketSize sl@0: // Values for Different Numbers of Transactions per Microframe". sl@0: if ((iType == KUsbEpTypeInterrupt) || (iType == KUsbEpTypeIsochronous)) sl@0: { sl@0: if (iTransactions == 1) sl@0: { sl@0: if (aEpSize_Hs < 513) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Ep size too small: %d < 513. Correcting...", sl@0: aEpSize_Hs)); sl@0: aEpSize_Hs = 513; sl@0: } sl@0: } sl@0: else if (iTransactions == 2) sl@0: { sl@0: if (aEpSize_Hs < 683) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Ep size too small: %d < 683. Correcting...", sl@0: aEpSize_Hs)); sl@0: aEpSize_Hs = 683; sl@0: } sl@0: } sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** Helper function for logical endpoints and endpoint descriptors: sl@0: If not set, assign a valid and meaningful value to iInterval_Hs, deriving from iInterval. sl@0: This function modifies the objects's data member(s). sl@0: */ sl@0: TInt TUsbcEndpointInfo::AdjustPollInterval() sl@0: { sl@0: if (iInterval_Hs != -1) sl@0: { sl@0: // Already done. sl@0: return KErrNone; sl@0: } sl@0: if ((iType == KUsbEpTypeBulk) || (iType == KUsbEpTypeControl)) sl@0: { sl@0: // Valid range: 0..255 (maximum NAK rate). sl@0: // (The host controller will probably ignore this value though - sl@0: // see the last sentence of section 9.6.6 for details.) sl@0: iInterval_Hs = 255; sl@0: } sl@0: else if (iType == KUsbEpTypeInterrupt) sl@0: { sl@0: // HS interval = 2^(iInterval_Hs-1) with a valid iInterval_Hs range of 1..16. sl@0: // The following table shows the mapping of HS values to actual intervals (and sl@0: // thus FS values) for the range of possible FS values (1..255). sl@0: // There is not always a 1:1 mapping possible, but we want at least to make sure sl@0: // that the HS polling interval is never longer than the FS one (except for 255). sl@0: // sl@0: // 1 = 1 sl@0: // 2 = 2 sl@0: // 3 = 4 sl@0: // 4 = 8 sl@0: // 5 = 16 sl@0: // 6 = 32 sl@0: // 7 = 64 sl@0: // 8 = 128 sl@0: // 9 = 256 sl@0: if (iInterval == 255) sl@0: iInterval_Hs = 9; sl@0: else if (iInterval >= 128) sl@0: iInterval_Hs = 8; sl@0: else if (iInterval >= 64) sl@0: iInterval_Hs = 7; sl@0: else if (iInterval >= 32) sl@0: iInterval_Hs = 6; sl@0: else if (iInterval >= 16) sl@0: iInterval_Hs = 5; sl@0: else if (iInterval >= 8) sl@0: iInterval_Hs = 4; sl@0: else if (iInterval >= 4) sl@0: iInterval_Hs = 3; sl@0: else if (iInterval >= 2) sl@0: iInterval_Hs = 2; sl@0: else if (iInterval == 1) sl@0: iInterval_Hs = 1; sl@0: else sl@0: { sl@0: // iInterval wasn't set properly by the user sl@0: iInterval_Hs = 1; sl@0: return KErrGeneral; sl@0: } sl@0: } sl@0: else if (iType == KUsbEpTypeIsochronous) sl@0: { sl@0: // Interpretation is the same for FS and HS. sl@0: iInterval_Hs = iInterval; sl@0: } sl@0: else sl@0: { sl@0: // '1' is a valid value for all endpoint types... sl@0: iInterval_Hs = 1; sl@0: return KErrGeneral; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TUsbcPhysicalEndpoint::TUsbcPhysicalEndpoint() sl@0: : iEndpointAddr(0), iIfcNumber(NULL), iLEndpoint(NULL), iSettingReserve(EFalse), iHalt(EFalse) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::TUsbcPhysicalEndpoint")); sl@0: } sl@0: sl@0: sl@0: TInt TUsbcPhysicalEndpoint::TypeAvailable(TUint aType) const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::TypeAvailable")); sl@0: switch (aType) sl@0: { sl@0: case KUsbEpTypeControl: sl@0: return (iCaps.iTypesAndDir & KUsbEpTypeControl); sl@0: case KUsbEpTypeIsochronous: sl@0: return (iCaps.iTypesAndDir & KUsbEpTypeIsochronous); sl@0: case KUsbEpTypeBulk: sl@0: return (iCaps.iTypesAndDir & KUsbEpTypeBulk); sl@0: case KUsbEpTypeInterrupt: sl@0: return (iCaps.iTypesAndDir & KUsbEpTypeInterrupt); sl@0: default: sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid EP type: %d", aType)); sl@0: return 0; sl@0: } sl@0: } sl@0: sl@0: sl@0: TInt TUsbcPhysicalEndpoint::DirAvailable(TUint aDir) const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::DirAvailable")); sl@0: switch (aDir) sl@0: { sl@0: case KUsbEpDirIn: sl@0: return (iCaps.iTypesAndDir & KUsbEpDirIn); sl@0: case KUsbEpDirOut: sl@0: return (iCaps.iTypesAndDir & KUsbEpDirOut); sl@0: default: sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid EP direction: %d", aDir)); sl@0: return 0; sl@0: } sl@0: } sl@0: sl@0: sl@0: TInt TUsbcPhysicalEndpoint::EndpointSuitable(const TUsbcEndpointInfo* aEpInfo, TInt aIfcNumber) const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::EndpointSuitable")); sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" looking for EP: type=0x%x dir=0x%x size=%d (ifc_num=%d)", sl@0: aEpInfo->iType, aEpInfo->iDir, aEpInfo->iSize, aIfcNumber)); sl@0: if (iSettingReserve) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" -> setting conflict")); sl@0: return 0; sl@0: } sl@0: // (aIfcNumber == -1) means the ep is for a new default interface setting sl@0: else if (iIfcNumber && (*iIfcNumber != aIfcNumber)) sl@0: { sl@0: // If this endpoint has already been claimed (iIfcNumber != NULL), sl@0: // but by a different interface(-set) than the currently looking one sl@0: // (*iIfcNumber != aIfcNumber), then it's not available. sl@0: // This works because we can assign the same physical endpoint sl@0: // to different alternate settings of the *same* interface, and sl@0: // because we check for available endpoints for every alternate setting sl@0: // as a whole. sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" -> ifc conflict")); sl@0: return 0; sl@0: } sl@0: else if (!TypeAvailable(aEpInfo->iType)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" -> type conflict")); sl@0: return 0; sl@0: } sl@0: else if (!DirAvailable(aEpInfo->iDir)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" -> direction conflict")); sl@0: return 0; sl@0: } sl@0: else if (!(iCaps.iSizes & PacketSize2Mask(aEpInfo->iSize)) && !(iCaps.iSizes & KUsbEpSizeCont)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" -> size conflict")); sl@0: return 0; sl@0: } sl@0: else sl@0: return 1; sl@0: } sl@0: sl@0: sl@0: TUsbcPhysicalEndpoint::~TUsbcPhysicalEndpoint() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcPhysicalEndpoint::~TUsbcPhysicalEndpoint()")); sl@0: iLEndpoint = NULL; sl@0: } sl@0: sl@0: sl@0: TUsbcLogicalEndpoint::TUsbcLogicalEndpoint(DUsbClientController* aController, TUint aEndpointNum, sl@0: const TUsbcEndpointInfo& aEpInfo, TUsbcInterface* aInterface, sl@0: TUsbcPhysicalEndpoint* aPEndpoint) sl@0: : iController(aController), iLEndpointNum(aEndpointNum), iInfo(aEpInfo), iInterface(aInterface), sl@0: iPEndpoint(aPEndpoint) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcLogicalEndpoint::TUsbcLogicalEndpoint()")); sl@0: // Adjust FS/HS endpoint sizes sl@0: if (iInfo.AdjustEpSizes(iEpSize_Fs, iEpSize_Hs) != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown endpoint type: %d", iInfo.iType)); sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Now set: iEpSize_Fs=%d iEpSize_Hs=%d (iInfo.iSize=%d)", sl@0: iEpSize_Fs, iEpSize_Hs, iInfo.iSize)); sl@0: // Adjust HS polling interval sl@0: if (iInfo.AdjustPollInterval() != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown ep type (%d) or invalid interval value (%d)", sl@0: iInfo.iType, iInfo.iInterval)); sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Now set: iInfo.iInterval=%d iInfo.iInterval_Hs=%d", sl@0: iInfo.iInterval, iInfo.iInterval_Hs)); sl@0: // Additional transactions requested on a non High Bandwidth ep? sl@0: if ((iInfo.iTransactions > 0) && !aPEndpoint->iCaps.iHighBandwidth) sl@0: { sl@0: __KTRACE_OPT(KPANIC, sl@0: Kern::Printf(" Warning: Additional transactions requested but not a High Bandwidth ep")); sl@0: } sl@0: } sl@0: sl@0: sl@0: TUsbcLogicalEndpoint::~TUsbcLogicalEndpoint() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcLogicalEndpoint::~TUsbcLogicalEndpoint: #%d", iLEndpointNum)); sl@0: // If the real endpoint this endpoint points to is also used by sl@0: // any other logical endpoint in any other setting of this interface sl@0: // then we leave the real endpoint marked as used. Otherwise we mark sl@0: // it as available (set its ifc number pointer to NULL). sl@0: const TInt n = iInterface->iInterfaceSet->iInterfaces.Count(); sl@0: for (TInt i = 0; i < n; ++i) sl@0: { sl@0: const TUsbcInterface* const ifc = iInterface->iInterfaceSet->iInterfaces[i]; sl@0: const TInt m = ifc->iEndpoints.Count(); sl@0: for (TInt j = 0; j < m; ++j) sl@0: { sl@0: const TUsbcLogicalEndpoint* const ep = ifc->iEndpoints[j]; sl@0: if ((ep->iPEndpoint == iPEndpoint) && (ep != this)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Physical endpoint still in use -> we leave it as is")); sl@0: return; sl@0: } sl@0: } sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Closing DMA channel")); sl@0: const TInt idx = iController->EpAddr2Idx(iPEndpoint->iEndpointAddr); sl@0: // If the endpoint doesn't support DMA (now or ever) the next operation will be a no-op. sl@0: iController->CloseDmaChannel(idx); sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Setting physical ep 0x%02x ifc number to NULL (was %d)", sl@0: iPEndpoint->iEndpointAddr, *iPEndpoint->iIfcNumber)); sl@0: iPEndpoint->iIfcNumber = NULL; sl@0: } sl@0: sl@0: sl@0: TUsbcInterface::TUsbcInterface(TUsbcInterfaceSet* aIfcSet, TUint8 aSetting, TBool aNoEp0Requests) sl@0: : iEndpoints(2), iInterfaceSet(aIfcSet), iSettingCode(aSetting), iNoEp0Requests(aNoEp0Requests) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterface::TUsbcInterface()")); sl@0: } sl@0: sl@0: sl@0: TUsbcInterface::~TUsbcInterface() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterface::~TUsbcInterface()")); sl@0: iEndpoints.ResetAndDestroy(); sl@0: } sl@0: sl@0: sl@0: TUsbcInterfaceSet::TUsbcInterfaceSet(const DBase* aClientId, TUint8 aIfcNum) sl@0: : iInterfaces(2), iClientId(aClientId), iInterfaceNumber(aIfcNum), iCurrentInterface(0) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterfaceSet::TUsbcInterfaceSet()")); sl@0: } sl@0: sl@0: sl@0: TUsbcInterfaceSet::~TUsbcInterfaceSet() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcInterfaceSet::~TUsbcInterfaceSet()")); sl@0: iInterfaces.ResetAndDestroy(); sl@0: } sl@0: sl@0: sl@0: TUsbcConfiguration::TUsbcConfiguration(TUint8 aConfigVal) sl@0: : iInterfaceSets(1), iConfigValue(aConfigVal) // iInterfaceSets(1): granularity sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcConfiguration::TUsbcConfiguration()")); sl@0: } sl@0: sl@0: sl@0: TUsbcConfiguration::~TUsbcConfiguration() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcConfiguration::~TUsbcConfiguration()")); sl@0: iInterfaceSets.ResetAndDestroy(); sl@0: } sl@0: sl@0: sl@0: _LIT(KDriverName, "Usbcc"); sl@0: sl@0: DUsbcPowerHandler::DUsbcPowerHandler(DUsbClientController* aController) sl@0: : DPowerHandler(KDriverName), iController(aController) sl@0: {} sl@0: sl@0: sl@0: void DUsbcPowerHandler::PowerUp() sl@0: { sl@0: if (iController) sl@0: iController->iPowerUpDfc.Enque(); sl@0: } sl@0: sl@0: sl@0: void DUsbcPowerHandler::PowerDown(TPowerState) sl@0: { sl@0: if (iController) sl@0: iController->iPowerDownDfc.Enque(); sl@0: } sl@0: sl@0: sl@0: // -eof-