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/ps_usbc.cpp sl@0: // Platform independent layer (PIL) of the USB Device controller driver (PDD). sl@0: // Interface to the USB LDD. sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file ps_usbc.cpp sl@0: @internalTechnology sl@0: */ sl@0: sl@0: #include sl@0: sl@0: sl@0: /** sl@0: TUsbcInterfaceSet and TUsbcInterface sl@0: ==================================== sl@0: sl@0: TUsbcInterfaceSet represents a 'USB Interface' and TUsbcInterface sl@0: represents an 'Alternate Setting of a USB Interface'. sl@0: sl@0: Since every LDD governs exactly one interface, the above distinction is sl@0: made only within the USB implementation. At the LDD API, there is/are sl@0: simply one or more settings for this single interface, numbered from '0' sl@0: (the default) to 'n', and specified by the parameter 'TInt aInterfaceNum'. sl@0: sl@0: Within the PDD implementation, for a TUsbcInterfaceSet number the parameter sl@0: 'TInt aIfcSet' is used (local variable ifcset); for a TUsbcInterface number sl@0: the parameter 'TInt aIfc' is used (local variable ifc). sl@0: sl@0: sl@0: iConfigs[0] and CurrentConfig() sl@0: =============================== sl@0: sl@0: One problem with this file is that it always uses iConfigs[0] and not sl@0: CurrentConfig(). This is mainly because the API to the LDD doesn't know sl@0: about the concept of multiple configurations, and thus always assumes one sl@0: single configuration (which is also always active: a further problem). sl@0: sl@0: In the file chapter9.cpp this issue doesn't exist, since there we always sl@0: have to obey the USB protocol, and in this way will use the configuration sl@0: which is selected by the host (which will then again currently always be sl@0: iConfigs[0].) sl@0: sl@0: sl@0: iEp0ClientId and iEp0DataReceiving sl@0: ================================== sl@0: sl@0: The purpose of these two members of class DUsbClientController is the sl@0: following. sl@0: sl@0: They are used only during Ep0 control transactions which have an OUT (Rx) sl@0: data stage. The special problem with these transactions is twofold. For one sl@0: thing we have to know that what we are receiving is data and not a Setup sl@0: packet. Furthermore we cannot deduce from the received data itself to whom sl@0: it is addressed (that's because of the shared nature of Ep0). sl@0: sl@0: So in order to recognize data packets we use iEp0DataReceiving. This sl@0: variable is set to TRUE either 1) upon processing a standard request which sl@0: has a DATA_OUT phase (only SET_DESCRIPTOR), or 2) if we have identified a sl@0: class-specific request which has a DATA_OUT phase and we have also found sl@0: the recipient for that request. sl@0: sl@0: In order to be able to tell whether received Ep0 data is to be processed by sl@0: the PIL or a LDD, we use iEp0ClientId. iEp0ClientId is usually NULL, which sl@0: means it is our data. However it is set to the client ID of an LDD in case sl@0: 2) above. That way we can subsequently hand over received data to the sl@0: correct client LDD. sl@0: sl@0: iEp0DataReceived tracks the amount of data already received - it is used to sl@0: determine the end of the DATA_OUT phase, irrespective of the owner of the sl@0: data. The total amount that is to be received can be obtained via sl@0: iSetup.iLength. (iSetup holds in that case the Setup packet of the current sl@0: Control transfer.) sl@0: sl@0: iEp0ClientDataTransmitting is only set to TRUE if a client sets up an Ep0 sl@0: write. After that transmission has completed we use this value to decide sl@0: whether we have to report the completion to a client or not. (If this sl@0: variable is FALSE, we did set up the write and thus no client notification sl@0: is necessary.) sl@0: sl@0: */ sl@0: sl@0: // sl@0: // === Global and Local Variables ================================================================== sl@0: // sl@0: sl@0: GLDEF_D DUsbClientController* DUsbClientController::UsbClientController[] = {NULL, NULL}; sl@0: sl@0: static const TInt KUsbReconnectDelay = 500; // milliseconds sl@0: static const TInt KUsbCableStatusDelay = 500; // milliseconds sl@0: sl@0: sl@0: // sl@0: // === USB Controller member function implementations - LDD API (public) =========================== sl@0: // sl@0: sl@0: sl@0: /** The class destructor. sl@0: sl@0: This rarely gets called, except, for example when something goes sl@0: wrong during construction. sl@0: sl@0: It's not exported because it is virtual. sl@0: */ sl@0: DUsbClientController::~DUsbClientController() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::~DUsbClientController()")); sl@0: if (iPowerHandler) sl@0: { sl@0: iPowerHandler->Remove(); sl@0: delete iPowerHandler; sl@0: } sl@0: // ResetAndDestroy() will call for every array element the destructor of the pointed-to object, sl@0: // before deleting the element itself, and closing the array. sl@0: iConfigs.ResetAndDestroy(); sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::~DUsbClientController(): Done.")); sl@0: } sl@0: sl@0: sl@0: /** To be called by the OTG/Host stack in an OTG setup to disable USB device sl@0: functionality. sl@0: sl@0: The OTG stack calls this function when VBus is no longer valid, when the sl@0: B-device swaps out of peripheral mode, or when moving out of the sl@0: A_PERIPHERAL state. sl@0: sl@0: The Client stack will disable the D+ pull-up immediately when the function sl@0: is called. sl@0: sl@0: During DisableClientStack() the Client stack will notify its registered sl@0: applications on the user-side (including the USB Manager) about a USB sl@0: device state change event, a transition to the "Undefined" state. sl@0: */ sl@0: EXPORT_C void DUsbClientController::DisableClientStack() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DisableClientStack()")); sl@0: if (!iStackIsActive) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Already disabled - returning")); sl@0: return; sl@0: } sl@0: iOtgClientConnect = EFalse; sl@0: TInt r = EvaluateOtgConnectFlags(); // will disconnect UDC sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: EvaluateOtgConnectFlags() failed: %d", r)); sl@0: } sl@0: sl@0: // Reset OTG features, leave attributes as is (just as in USB Reset case) sl@0: // (OTG spec 1.3 sections 6.5.x all say "... on a bus reset or at the end sl@0: // of a session." VBus drop is the end of a session.) sl@0: iOtgFuncMap &= KUsbOtgAttr_SrpSupp | KUsbOtgAttr_HnpSupp; sl@0: OtgFeaturesNotify(); sl@0: // Tear down the current configuration (if any) sl@0: ChangeConfiguration(0); sl@0: sl@0: if (iDeviceState != EUsbcDeviceStateUndefined) sl@0: { sl@0: // Not being in state UNDEFINED implies that the cable is inserted. sl@0: if (iHardwareActivated) sl@0: { sl@0: NextDeviceState(EUsbcDeviceStatePowered); sl@0: } sl@0: // (If the hardware is NOT activated at this point, we can only be in sl@0: // state EUsbcDeviceStateAttached, so we don't have to move to it.) sl@0: } sl@0: DeActivateHardwareController(); // turn off UDC altogether sl@0: iStackIsActive = EFalse; sl@0: // Complete all pending requests, returning KErrDisconnected sl@0: RunClientCallbacks(); sl@0: // Notify registered clients on the user side about a USB device state sl@0: // change event and a transition to the "Undefined" state. sl@0: NextDeviceState(EUsbcDeviceStateUndefined); sl@0: } sl@0: sl@0: sl@0: /** To be called by the OTG/Host stack in an OTG setup to enable USB device sl@0: functionality. sl@0: sl@0: Once called, the function will return quickly, but it will by then not sl@0: necessarily have enabled the D+ pull-up*. The Client stack can enable the D+ sl@0: pull-up (via the transceiver) from that moment on and as long as the OTG sl@0: stack doesn't call DisableClientStack(). sl@0: sl@0: *) It will enable the D+ pull-up immediately if the user-side USB support sl@0: has already been loaded. This should always be the case when the OTG stack sl@0: is calling this function during the transition to the A_PERIPHERAL state, sl@0: i.e. when acting as an A-device. sl@0: */ sl@0: EXPORT_C void DUsbClientController::EnableClientStack() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EnableClientStack()")); sl@0: if (iStackIsActive) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Already enabled - returning")); sl@0: return; sl@0: } sl@0: iStackIsActive = ETrue; sl@0: // If the UDC is still off, we switch it on here. sl@0: TInt r = ActivateHardwareController(); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ActivateHardwareController() failed: %d", r)); sl@0: } sl@0: iOtgClientConnect = ETrue; sl@0: r = EvaluateOtgConnectFlags(); // may connect UDC sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: EvaluateOtgConnectFlags() failed: %d", r)); sl@0: } sl@0: } sl@0: sl@0: sl@0: /** Called by LDD to see if controller is usable. sl@0: sl@0: @return ETrue if controller is in normal state, EFalse if it is disabled. sl@0: */ sl@0: EXPORT_C TBool DUsbClientController::IsActive() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::IsActive()")); sl@0: return iStackIsActive; sl@0: } sl@0: sl@0: sl@0: /** Called by LDD to register client callbacks. sl@0: sl@0: @return KErrNone if successful, KErrAlreadyExists callback exists. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::RegisterClientCallback(TUsbcClientCallback& aCallback) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterClientCallback()")); sl@0: if (iClientCallbacks.Elements() == KUsbcMaxListLength) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", sl@0: KUsbcMaxListLength)); sl@0: return KErrGeneral; sl@0: } sl@0: TSglQueIter iter(iClientCallbacks); sl@0: TUsbcClientCallback* p; sl@0: while ((p = iter++) != NULL) sl@0: if (p == &aCallback) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Error: ClientCallback @ 0x%x already registered", &aCallback)); sl@0: return KErrAlreadyExists; sl@0: } sl@0: iClientCallbacks.AddLast(aCallback); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** Returns a pointer to the USB client controller object. sl@0: sl@0: This function is static. sl@0: sl@0: @param aUdc The number of the UDC (0..n) for which the pointer is to be returned. sl@0: sl@0: @return A pointer to the USB client controller object. sl@0: */ sl@0: EXPORT_C DUsbClientController* DUsbClientController::UsbcControllerPointer(TInt aUdc) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::UsbcControllerPointer()")); sl@0: if (aUdc < 0 || aUdc > 1) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aUdc out of range (%d)", aUdc)); sl@0: return NULL; sl@0: } sl@0: return UsbClientController[aUdc]; sl@0: } sl@0: sl@0: sl@0: /** Fills the buffer passed in as an argument with endpoint capability information. sl@0: sl@0: @see DUsbClientController::DeviceCaps() sl@0: @see TUsbcEndpointData sl@0: @see TUsbDeviceCaps sl@0: sl@0: @param aClientId A pointer to the LDD making the enquiry. sl@0: @param aCapsBuf A reference to a descriptor buffer, which, on return, contains an array of sl@0: TUsbcEndpointData elements; there are TUsbDeviceCaps::iTotalEndpoints elements in the array; sl@0: call DeviceCaps() to get the number of elements required. sl@0: */ sl@0: EXPORT_C void DUsbClientController::EndpointCaps(const DBase* aClientId, TDes8& aCapsBuf) const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EndpointCaps()")); sl@0: // Here we do not simply call DUsbClientController::DeviceEndpointCaps(), sl@0: // because that function fills an array which comprises of _all_ endpoints, sl@0: // whereas this function omits ep0 and all unusable endpoints. sl@0: // Apart from that, we have to fill an array of TUsbcEndpointData, not TUsbcEndpointCaps. sl@0: TUsbcEndpointData data[KUsbcMaxEndpoints]; sl@0: const TInt ifcset_num = ClientId2InterfaceNumber(aClientId); sl@0: for (TInt i = 2, j = 0; i < iDeviceTotalEndpoints; ++i) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::Caps: RealEndpoint #%d", i)); sl@0: if (iRealEndpoints[i].iCaps.iTypesAndDir != KUsbEpNotAvailable) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::Caps: --> UsableEndpoint #%d", j)); sl@0: data[j].iCaps = iRealEndpoints[i].iCaps; sl@0: if (ifcset_num < 0) sl@0: { sl@0: // If this LDD doesn't own an interface, but the Ep points to one, sl@0: // then that must be the interface of a different LDD. Hence the Ep sl@0: // is not available for this LDD. sl@0: data[j].iInUse = (iRealEndpoints[i].iIfcNumber != NULL); sl@0: } sl@0: else sl@0: { sl@0: // If this LDD does already own an interface, and the Ep also points to one, sl@0: // then the Ep is not available for this LDD only if that interface is owned sl@0: // by a different LDD (i.e. if the interface number is different). sl@0: // Reason: Even though the endpoint might already be part of an interface setting, sl@0: // it is still available for a different alternate setting of the same interface. sl@0: data[j].iInUse = ((iRealEndpoints[i].iIfcNumber != NULL) && sl@0: (*(iRealEndpoints[i].iIfcNumber) != ifcset_num)); sl@0: } sl@0: j++; sl@0: } sl@0: } sl@0: // aCapsBuf resides in userland sl@0: TPtrC8 des((TUint8*)data, sizeof(data)); sl@0: const TInt r = Kern::ThreadDesWrite((reinterpret_cast(aClientId))->Client(), sl@0: &aCapsBuf, des, 0, KChunkShiftBy0, NULL); sl@0: if (r != KErrNone) sl@0: { sl@0: Kern::ThreadKill((reinterpret_cast(aClientId))->Client(), sl@0: EExitPanic, r, KUsbPILKillCat); sl@0: } sl@0: } sl@0: sl@0: sl@0: /** Fills the buffer passed in as an argument with device capability information. sl@0: sl@0: @see TUsbDeviceCaps sl@0: @see TUsbDeviceCapsV01 sl@0: sl@0: @param aClientId A pointer to the LDD making the enquiry. sl@0: @param aCapsBuf A reference to a descriptor buffer which, on return, contains sl@0: a TUsbDeviceCaps structure. sl@0: */ sl@0: EXPORT_C void DUsbClientController::DeviceCaps(const DBase* aClientId, TDes8& aCapsBuf) const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeviceCaps()")); sl@0: TUsbDeviceCaps caps; sl@0: caps().iTotalEndpoints = iDeviceUsableEndpoints; // not DeviceTotalEndpoints()! sl@0: caps().iConnect = SoftConnectCaps(); sl@0: caps().iSelfPowered = iSelfPowered; sl@0: caps().iRemoteWakeup = iRemoteWakeup; sl@0: caps().iHighSpeed = DeviceHighSpeedCaps(); sl@0: caps().iFeatureWord1 = CableDetectWithoutPowerCaps() ? sl@0: caps().iFeatureWord1 | KUsbDevCapsFeatureWord1_CableDetectWithoutPower : sl@0: caps().iFeatureWord1 & ~KUsbDevCapsFeatureWord1_CableDetectWithoutPower; sl@0: caps().iFeatureWord1 = DeviceResourceAllocV2Caps() ? sl@0: caps().iFeatureWord1 | KUsbDevCapsFeatureWord1_EndpointResourceAllocV2 : sl@0: caps().iFeatureWord1 & ~KUsbDevCapsFeatureWord1_EndpointResourceAllocV2; sl@0: caps().iReserved = 0; sl@0: sl@0: // aCapsBuf resides in userland sl@0: const TInt r = Kern::ThreadDesWrite((reinterpret_cast(aClientId))->Client(), sl@0: &aCapsBuf, caps, 0, KChunkShiftBy0, NULL); sl@0: if (r != KErrNone) sl@0: { sl@0: Kern::ThreadKill((reinterpret_cast(aClientId))->Client(), sl@0: EExitPanic, r, KUsbPILKillCat); sl@0: } sl@0: } sl@0: sl@0: sl@0: TUsbcEndpointInfoArray::TUsbcEndpointInfoArray(const TUsbcEndpointInfo* aData, TInt aDataSize) sl@0: { sl@0: iType = EUsbcEndpointInfo; sl@0: iData = (TUint8*) aData; sl@0: if (aDataSize > 0) sl@0: iDataSize = aDataSize; sl@0: else sl@0: iDataSize = sizeof(TUsbcEndpointInfo); sl@0: } sl@0: sl@0: sl@0: inline TUsbcEndpointInfo& TUsbcEndpointInfoArray::operator[](TInt aIndex) const sl@0: { sl@0: return *(TUsbcEndpointInfo*) &iData[aIndex * iDataSize]; sl@0: } sl@0: sl@0: sl@0: EXPORT_C TInt DUsbClientController::SetInterface(const DBase* aClientId, DThread* aThread, sl@0: TInt aInterfaceNum, TUsbcClassInfo& aClass, sl@0: TDesC8* aString, TInt aTotalEndpointsUsed, sl@0: const TUsbcEndpointInfo aEndpointData[], sl@0: TInt (*aRealEpNumbers)[6], TUint32 aFeatureWord) sl@0: { sl@0: TUsbcEndpointInfoArray endpointData = TUsbcEndpointInfoArray(aEndpointData); sl@0: return SetInterface(aClientId, aThread, aInterfaceNum, aClass, aString, aTotalEndpointsUsed, sl@0: endpointData, (TInt*) aRealEpNumbers, aFeatureWord); sl@0: } sl@0: sl@0: sl@0: /** Creates a new USB interface (one setting), complete with endpoints, descriptors, etc., sl@0: and chains it into the internal device configuration tree. sl@0: sl@0: @param aClientId A pointer to the LDD owning the new interface. sl@0: @param aThread A pointer to the thread the owning LDD is running in. sl@0: @param aInterfaceNum The interface setting number of the new interface setting. This must be 0 sl@0: if it is the first setting of the interface that gets created, or 1 more than the last setting sl@0: that was created for this interface. sl@0: @param aClass Contains information about the device class this interface might belong to. sl@0: @param aString A pointer to a string that is used for the string descriptor of this interface. sl@0: @param aTotalEndpointsUsed The number of endpoints used by this interface (and also the number of sl@0: elements of the following array). sl@0: @param aEndpointData An array with aTotalEndpointsUsed elements, containing information about the sl@0: endpoints of this interface. sl@0: sl@0: @return KErrNotSupported if Control endpoints are requested by the LDD but aren't supported by the PIL, sl@0: KErrInUse if at least one requested endpoint is - temporarily or permanently - not available for use, sl@0: KErrNoMemory if (endpoint, interface, string) descriptor allocation fails, KErrGeneral if something else sl@0: goes wrong during endpoint or interface or descriptor creation, KErrNone if interface successfully set up. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetInterface(const DBase* aClientId, DThread* aThread, sl@0: TInt aInterfaceNum, TUsbcClassInfo& aClass, sl@0: TDesC8* aString, TInt aTotalEndpointsUsed, sl@0: const TUsbcEndpointInfoArray aEndpointData, sl@0: TInt aRealEpNumbers[], TUint32 aFeatureWord) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetInterface()")); sl@0: if (aInterfaceNum != 0) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" alternate interface setting request: #%d", aInterfaceNum)); sl@0: } sl@0: #ifndef USB_SUPPORTS_CONTROLENDPOINTS sl@0: for (TInt i = 0; i < aTotalEndpointsUsed; ++i) sl@0: { sl@0: if (aEndpointData[i].iType == KUsbEpTypeControl) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: control endpoints not supported")); sl@0: return KErrNotSupported; sl@0: } sl@0: } sl@0: #endif sl@0: // Check for endpoint availability & check those endpoint's capabilities sl@0: const TInt ifcset_num = ClientId2InterfaceNumber(aClientId); sl@0: // The passed-in ifcset_num may be -1 now, but that's intended. sl@0: if (!CheckEpAvailability(aTotalEndpointsUsed, aEndpointData, ifcset_num)) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: endpoints not (all) available")); sl@0: return KErrInUse; sl@0: } sl@0: // Create & setup new interface sl@0: TUsbcInterface* ifc = CreateInterface(aClientId, aInterfaceNum, aFeatureWord); sl@0: if (ifc == NULL) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ifc == NULL")); sl@0: return KErrGeneral; sl@0: } sl@0: // Create logical endpoints sl@0: TInt r = CreateEndpoints(ifc, aTotalEndpointsUsed, aEndpointData, aRealEpNumbers); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: CreateEndpoints() != KErrNone")); sl@0: DeleteInterface(ifc->iInterfaceSet->iInterfaceNumber, aInterfaceNum); sl@0: return r; sl@0: } sl@0: // Create & setup interface, string, and endpoint descriptors sl@0: r = SetupIfcDescriptor(ifc, aClass, aThread, aString, aEndpointData); sl@0: if (r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** Releases an existing USB interface (one setting), complete with endpoints, descriptors, etc., sl@0: and removes it from the internal device configuration tree. sl@0: sl@0: @param aClientId A pointer to the LDD owning the interface. sl@0: @param aInterfaceNum The setting number of the interface setting to be deleted. This must be sl@0: the highest numbered (or 'last') setting for this interface. sl@0: sl@0: @return KErrNotFound if interface (not setting) for some reason cannot be found, KErrArgument if an sl@0: invalid interface setting number is specified (not existing or existing but too small), KErrNone if sl@0: interface successfully released or if this client doesn't own any interface. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::ReleaseInterface(const DBase* aClientId, TInt aInterfaceNum) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ReleaseInterface(..., %d)", aInterfaceNum)); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" interface not found")); // no error sl@0: return KErrNone; sl@0: } sl@0: TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); sl@0: if (!ifcset_ptr) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Error: interface number %d doesn't exist", ifcset)); sl@0: return KErrNotFound; sl@0: } sl@0: const TInt setting_count = ifcset_ptr->iInterfaces.Count(); sl@0: if ((setting_count - 1) != aInterfaceNum) sl@0: { sl@0: __KTRACE_OPT(KUSB, sl@0: Kern::Printf(" > Error: interface settings must be released in descending order:\n\r" sl@0: " %d setting(s) exist, #%d was requested to be released.\n\r" sl@0: " (#%d has to be released first)", sl@0: setting_count, aInterfaceNum, setting_count - 1)); sl@0: return KErrArgument; sl@0: } sl@0: // Tear down current setting (invalidate configured state) sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" > tearing down InterfaceSet %d", ifcset)); sl@0: // Cancel all transfers on the current setting of this interface and deconfigure all its endpoints. sl@0: InterfaceSetTeardown(ifcset_ptr); sl@0: // 'Setting 0' means: delete all existing settings. sl@0: if (aInterfaceNum == 0) sl@0: { sl@0: TInt m = ifcset_ptr->iInterfaces.Count(); sl@0: while (m > 0) sl@0: { sl@0: m--; sl@0: // Ground the physical endpoints' logical_endpoint_pointers sl@0: const TInt n = ifcset_ptr->iInterfaces[m]->iEndpoints.Count(); sl@0: for (TInt i = 0; i < n; ++i) sl@0: { sl@0: TUsbcPhysicalEndpoint* ptr = const_cast sl@0: (ifcset_ptr->iInterfaces[m]->iEndpoints[i]->iPEndpoint); sl@0: ptr->iLEndpoint = NULL; sl@0: } sl@0: // Delete the setting itself + its ifc & ep descriptors sl@0: DeleteInterface(ifcset, m); sl@0: iDescriptors.DeleteIfcDescriptor(ifcset, m); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // Ground the physical endpoints' logical_endpoint_pointers sl@0: const TInt n = ifcset_ptr->iInterfaces[aInterfaceNum]->iEndpoints.Count(); sl@0: for (TInt i = 0; i < n; ++i) sl@0: { sl@0: TUsbcPhysicalEndpoint* ptr = const_cast sl@0: (ifcset_ptr->iInterfaces[aInterfaceNum]->iEndpoints[i]->iPEndpoint); sl@0: ptr->iLEndpoint = NULL; sl@0: } sl@0: // Delete the setting itself + its ifc & ep descriptors sl@0: DeleteInterface(ifcset, aInterfaceNum); sl@0: iDescriptors.DeleteIfcDescriptor(ifcset, aInterfaceNum); sl@0: } sl@0: // Delete the whole interface if all settings are gone sl@0: if (ifcset_ptr->iInterfaces.Count() == 0) sl@0: { sl@0: DeleteInterfaceSet(ifcset); sl@0: } sl@0: // We now no longer have a valid current configuration sl@0: iCurrentConfig = 0; sl@0: if (iDeviceState == EUsbcDeviceStateConfigured) sl@0: { sl@0: NextDeviceState(EUsbcDeviceStateAddress); sl@0: } sl@0: // If it was the last interface(set)... sl@0: if (iConfigs[0]->iInterfaceSets.Count() == 0) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" No ifc left -> turning off UDC")); sl@0: // First disconnect the device from the bus sl@0: UsbDisconnect(); sl@0: DeActivateHardwareController(); sl@0: // (this also disables endpoint zero; we cannot have a USB device w/o interface, see 9.6.3) sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** Enforces a USB re-enumeration by disconnecting the UDC from the bus (if it is currently connected) and sl@0: re-connecting it. sl@0: sl@0: This only works if the PSL supports it, i.e. if SoftConnectCaps() returns ETrue. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::ReEnumerate() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ReEnumerate()")); sl@0: // If, in an OTG setup, the client stack is disabled, there's no point in sl@0: // trying to reenumerate the device. In fact, we then don't even want to sl@0: // turn on the UDC via ActivateHardwareController(). sl@0: if (!iStackIsActive) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Client stack disabled -> returning here")); sl@0: return KErrNotReady; sl@0: } sl@0: // We probably don't check here whether SoftConnectCaps() is ETrue, and sl@0: // return if not, because we might still want to execute sl@0: // ActivateHardwareController(). UsbConnect() and UsbDisconnect() should be sl@0: // no-ops if not supported by the PSL. sl@0: if (iConfigs[0]->iInterfaceSets.Count() == 0) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" > No interface registered -> no need to re-enumerate")); sl@0: return KErrNone;; sl@0: } sl@0: if (!iHardwareActivated) sl@0: { sl@0: // If the UDC is still off, we switch it on here. sl@0: const TInt r = ActivateHardwareController(); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ActivateHardwareController() failed: %d", r)); sl@0: return r; sl@0: } sl@0: // Finally connect the device to the bus sl@0: UsbConnect(); sl@0: } sl@0: else sl@0: { sl@0: UsbDisconnect(); sl@0: // Now we have to wait a certain amount of time, in order to give the host the opportunity sl@0: // to come to terms with the new situation. sl@0: // (The ETrue parameter makes the callback get called in DFC instead of in ISR context.) sl@0: iReconnectTimer.OneShot(KUsbReconnectDelay, ETrue); sl@0: } sl@0: return KErrNone;; sl@0: } sl@0: sl@0: sl@0: /** Powers up the UDC if one or more interfaces exist. sl@0: sl@0: @return KErrNone if UDC successfully powered up, KErrNotReady if no sl@0: interfaces have been registered yet, KErrHardwareNotAvailable if UDC sl@0: couldn't be activated. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::PowerUpUdc() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::PowerUpUdc()")); sl@0: // If, in an OTG setup, the client stack is disabled, we mustn't turn on sl@0: // the UDC via ActivateHardwareController() as that would already configure sl@0: // Ep0. sl@0: if (!iStackIsActive) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Client stack disabled -> returning here")); sl@0: return KErrNotReady; sl@0: } sl@0: if (iConfigs[0]->iInterfaceSets.Count() == 0) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" > No interface registered -> won't power up UDC")); sl@0: return KErrNotReady; sl@0: } sl@0: // If the UDC is still off, we switch it on here. sl@0: const TInt r = ActivateHardwareController(); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ActivateHardwareController() failed: %d", r)); sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** Connects the UDC to the bus. sl@0: sl@0: This only works if the PSL supports it, i.e. if SoftConnectCaps() returns ETrue. sl@0: sl@0: @return KErrNone if UDC successfully connected, KErrGeneral if there was an error. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::UsbConnect() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::UsbConnect()")); sl@0: #ifdef USB_OTG_CLIENT sl@0: iClientSupportReady = ETrue; sl@0: const TInt r = EvaluateOtgConnectFlags(); sl@0: const TInt irq = NKern::DisableAllInterrupts(); sl@0: if (iUsbResetDeferred) // implies (iOtgHnpHandledByHw == ETrue) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Resetting USB Reset 'defer' flag")); sl@0: iUsbResetDeferred = EFalse; sl@0: (void) ProcessResetEvent(EFalse); sl@0: } sl@0: NKern::RestoreInterrupts(irq); sl@0: #else sl@0: const TInt r = UdcConnect(); sl@0: #endif // USB_OTG_CLIENT sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** Disconnects the UDC from the bus. sl@0: sl@0: This only works if the PSL supports it, i.e. if SoftConnectCaps() returns ETrue. sl@0: sl@0: @return KErrNone if UDC successfully disconnected, KErrGeneral if there was an error. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::UsbDisconnect() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::UsbDisconnect()")); sl@0: #ifdef USB_OTG_CLIENT sl@0: iClientSupportReady = EFalse; sl@0: const TInt r = EvaluateOtgConnectFlags(); sl@0: #else sl@0: const TInt r = UdcDisconnect(); sl@0: #endif // USB_OTG_CLIENT sl@0: // There won't be any notification by the PSL about this, sl@0: // so we have to notify the LDD/user ourselves: sl@0: if ((r == KErrNone) && (iDeviceState != EUsbcDeviceStateUndefined)) sl@0: { sl@0: // Not being in state UNDEFINED implies that the cable is inserted. sl@0: if (iHardwareActivated) sl@0: { sl@0: NextDeviceState(EUsbcDeviceStatePowered); sl@0: } sl@0: // (If the hardware is NOT activated at this point, we can only be in sl@0: // state EUsbcDeviceStateAttached, so we don't have to move to it.) sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** Registers a notification callback for changes of the USB device state. sl@0: sl@0: In the event of a device state change, the callback's state member gets updated (using SetState) with a sl@0: new TUsbcDeviceState value, and then the callback is executed (DoCallback). 'USB device state' here refers sl@0: to the Visible Device States as defined in chapter 9 of the USB specification. sl@0: sl@0: @param aCallback A reference to a properly filled in status callback structure. sl@0: sl@0: @return KErrNone if callback successfully registered, KErrGeneral if this callback is already registered sl@0: (it won't be registered twice). sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::RegisterForStatusChange(TUsbcStatusCallback& aCallback) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterForStatusChange()")); sl@0: if (iStatusCallbacks.Elements() == KUsbcMaxListLength) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", sl@0: KUsbcMaxListLength)); sl@0: return KErrGeneral; sl@0: } sl@0: if (IsInTheStatusList(aCallback)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Error: StatusCallback @ 0x%x already registered", &aCallback)); sl@0: return KErrGeneral; sl@0: } sl@0: const TInt irq = NKern::DisableAllInterrupts(); sl@0: iStatusCallbacks.AddLast(aCallback); sl@0: NKern::RestoreInterrupts(irq); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** De-registers (removes from the list of pending requests) a notification callback for the USB device sl@0: status. sl@0: sl@0: @param aClientId A pointer to the LDD owning the status change callback. sl@0: sl@0: @return KErrNone if callback successfully unregistered, KErrNotFound if the callback couldn't be found. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::DeRegisterForStatusChange(const DBase* aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterForStatusChange()")); sl@0: __ASSERT_DEBUG((aClientId != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); sl@0: const TInt irq = NKern::DisableAllInterrupts(); sl@0: TSglQueIter iter(iStatusCallbacks); sl@0: TUsbcStatusCallback* p; sl@0: while ((p = iter++) != NULL) sl@0: { sl@0: if (p->Owner() == aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" removing StatusCallback @ 0x%x", p)); sl@0: iStatusCallbacks.Remove(*p); sl@0: NKern::RestoreInterrupts(irq); sl@0: return KErrNone; sl@0: } sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" client not found")); sl@0: NKern::RestoreInterrupts(irq); sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: sl@0: /** Registers a notification callback for changes of the state of endpoints. sl@0: sl@0: In the event of a state change of an endpoint that is spart of an interface which is owned by the LDD sl@0: specified in the callback structure, the callback's state member gets updated (using SetState) with a new sl@0: value, and the callback is executed (DoCallback). 'Endpoint state' here refers to the state of the sl@0: ENDPOINT_HALT feature of an endpoint as described in chapter 9 of the USB specification. The contents of sl@0: the state variable reflects the state of the halt features for all endpoints of the current interface sl@0: setting: bit 0 represents endpoint 1, bit 1 endpoint 2, etc. A set bit means 'endpoint halted', a cleared sl@0: bit 'endpoint not halted'. sl@0: sl@0: @param aCallback A reference to a properly filled in endpoint status callback structure. sl@0: sl@0: @return KErrNone if callback successfully registered, KErrGeneral if this callback is already registered sl@0: (it won't be registered twice). sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::RegisterForEndpointStatusChange(TUsbcEndpointStatusCallback& aCallback) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterForEndpointStatusChange()")); sl@0: if (iEpStatusCallbacks.Elements() == KUsbcMaxListLength) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", sl@0: KUsbcMaxListLength)); sl@0: return KErrGeneral; sl@0: } sl@0: if (IsInTheEpStatusList(aCallback)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Error: EpStatusCallback @ 0x%x already registered", &aCallback)); sl@0: return KErrGeneral; sl@0: } sl@0: const TInt irq = NKern::DisableAllInterrupts(); sl@0: iEpStatusCallbacks.AddLast(aCallback); sl@0: NKern::RestoreInterrupts(irq); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** De-registers (removes from the list of pending requests) a notification callback for changes of the state sl@0: of endpoints. sl@0: sl@0: @param aClientId A pointer to the LDD owning the endpoint status change callback. sl@0: sl@0: @return KErrNone if callback successfully unregistered, KErrNotFound if the callback couldn't be found. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::DeRegisterForEndpointStatusChange(const DBase* aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterForEndpointStatusChange()")); sl@0: __ASSERT_DEBUG((aClientId != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); sl@0: const TInt irq = NKern::DisableAllInterrupts(); sl@0: TSglQueIter iter(iEpStatusCallbacks); sl@0: TUsbcEndpointStatusCallback* p; sl@0: while ((p = iter++) != NULL) sl@0: { sl@0: if (p->Owner() == aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" removing EpStatusCallback @ 0x%x", p)); sl@0: iEpStatusCallbacks.Remove(*p); sl@0: NKern::RestoreInterrupts(irq); sl@0: return KErrNone; sl@0: } sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" client not found")); sl@0: NKern::RestoreInterrupts(irq); sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: sl@0: /** Returns the number of the currently active alternate interface setting for this interface. sl@0: sl@0: @param aClientId A pointer to the LDD owning the interface. sl@0: @param aInterfaceNum Here the interface gets written to. sl@0: sl@0: @return KErrNotFound if an interface for this client couldn't be found, KErrNone if setting value was sl@0: successfully written. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetInterfaceNumber(const DBase* aClientId, TInt& aInterfaceNum) const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetInterfaceNumber()")); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error (ifc < 0)")); sl@0: return KErrNotFound; sl@0: } sl@0: const TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); sl@0: if (!ifcset_ptr) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface number %d doesn't exist", ifcset)); sl@0: return KErrNotFound; sl@0: } sl@0: aInterfaceNum = ifcset_ptr->iCurrentInterface; sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** This is normally called once by an LDD's destructor, either after a Close() on the user side, sl@0: or during general cleanup. sl@0: sl@0: It might also be called by the LDD when some internal unrecoverable error occurs. sl@0: sl@0: This function sl@0: - de-registers a possibly pending device state change notification request, sl@0: - de-registers a possibly pending endpoint state change notification request, sl@0: - releases all interfaces + settings owned by this LDD, sl@0: - cancels all remaining (if any) read/write requests. sl@0: sl@0: @param aClientId A pointer to the LDD to be unregistered. sl@0: sl@0: @return KErrNone. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::DeRegisterClient(const DBase* aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterClient(0x%x)", aClientId)); sl@0: // Cancel all device state notification requests sl@0: DeRegisterForStatusChange(aClientId); sl@0: // Cancel all endpoint state notification requests sl@0: DeRegisterForEndpointStatusChange(aClientId); sl@0: DeRegisterForOtgFeatureChange(aClientId); sl@0: DeRegisterClientCallback(aClientId); sl@0: // Delete the interface including all its alternate settings which might exist. sl@0: // (If we release the default setting (0), all alternate settings are deleted as well.) sl@0: const TInt r = ReleaseInterface(aClientId, 0); sl@0: // Cancel all remaining (if any) read/write requests sl@0: DeleteRequestCallbacks(aClientId); sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterClient: Done.")); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** Returns the currently used Ep0 max packet size. sl@0: sl@0: @return The currently used Ep0 max packet size. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::Ep0PacketSize() const sl@0: { sl@0: const TUsbcLogicalEndpoint* const ep = iRealEndpoints[0].iLEndpoint; sl@0: if (iHighSpeed) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Ep0 size = %d (HS)", ep->iEpSize_Hs)); sl@0: return ep->iEpSize_Hs; sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Ep0 size = %d (FS)", ep->iEpSize_Fs)); sl@0: return ep->iEpSize_Fs; sl@0: } sl@0: } sl@0: sl@0: sl@0: /** Stalls Ep0. sl@0: sl@0: @param aClientId A pointer to the LDD wishing to stall Ep0 (this is for PIL internal purposes only). sl@0: sl@0: @return KErrNone if endpoint zero successfully stalled, KErrGeneral otherwise. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::Ep0Stall(const DBase* aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::Ep0Stall()")); sl@0: if (aClientId == iEp0ClientId) sl@0: { sl@0: ResetEp0DataOutVars(); sl@0: } sl@0: const TInt err = StallEndpoint(KEp0_Out); sl@0: if (err < 0) sl@0: { sl@0: return err; sl@0: } sl@0: else sl@0: return StallEndpoint(KEp0_In); sl@0: } sl@0: sl@0: sl@0: /** Sends a zero-byte status packet on Ep0. sl@0: sl@0: @param aClientId A pointer to the LDD wishing to send the status packet (not used at present). sl@0: */ sl@0: EXPORT_C void DUsbClientController::SendEp0StatusPacket(const DBase* /* aClientId */) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SendEp0StatusPacket()")); sl@0: SendEp0ZeroByteStatusPacket(); sl@0: } sl@0: sl@0: sl@0: /** Returns the current USB device state. sl@0: sl@0: 'USB device state' here refers to the Visible Device States as defined in chapter 9 of the USB sl@0: specification. sl@0: sl@0: @return The current USB device state, or EUsbcDeviceStateUndefined if the UDC doesn't allow device state sl@0: tracking (PSL's DeviceStateChangeCaps() returns EFalse). sl@0: */ sl@0: EXPORT_C TUsbcDeviceState DUsbClientController::GetDeviceStatus() const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetDeviceStatus()")); sl@0: return iDeviceState; sl@0: } sl@0: sl@0: sl@0: /** Returns the state of an endpoint. sl@0: sl@0: 'Endpoint state' here refers to the state of the ENDPOINT_HALT feature of sl@0: an endpoint as described in chapter 9 of the USB specification. sl@0: sl@0: @param aClientId A pointer to the LDD owning the interface which contains the endpoint to be queried. sl@0: @param aEndpointNum The number of the endpoint to be queried. sl@0: sl@0: @return The current endpoint state, or EEndpointStateUnknown if the endpoint couldn't be found. sl@0: */ sl@0: EXPORT_C TEndpointState DUsbClientController::GetEndpointStatus(const DBase* aClientId, TInt aEndpointNum) const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetEndpointStatus()")); sl@0: return EndpointStallStatus(aEndpointNum) ? sl@0: EEndpointStateStalled : sl@0: EEndpointStateNotStalled; sl@0: } sl@0: sl@0: sl@0: /** Sets up a data read request for an endpoint. sl@0: sl@0: @param aCallback A reference to a properly filled in data transfer request callback structure. sl@0: sl@0: @return KErrNone if callback successfully registered or if this callback is already registered sl@0: (but it won't be registered twice), KErrNotFound if the endpoint couldn't be found, KErrArgument if sl@0: endpoint number invalid (PSL), KErrGeneral if something else goes wrong. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetupReadBuffer(TUsbcRequestCallback& aCallback) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetupReadBuffer()")); sl@0: const TInt ep = aCallback.iRealEpNum; sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" logical ep: #%d", aCallback.iEndpointNum)); sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" real ep: #%d", ep)); sl@0: TInt err = KErrGeneral; sl@0: if (ep != 0) sl@0: { sl@0: if (iRequestCallbacks[ep]) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: RequestCallback already registered for that ep")); sl@0: if (iRequestCallbacks[ep] == &aCallback) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" (this same RequestCallback @ 0x%x)", &aCallback)); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" (a different RequestCallback @ 0x%x)", &aCallback)); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: // This may seem awkward: sl@0: // First we add a callback, and then, in case of an error, we remove it again. sl@0: // However this is necessary because the transfer request might complete (through sl@0: // an ISR) _before_ the SetupEndpointRead function returns. Since we don't know the sl@0: // outcome, we have to provide the callback before making the setup call. sl@0: // sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" adding RequestCallback[%d] @ 0x%x", ep, &aCallback)); sl@0: iRequestCallbacks[ep] = &aCallback; sl@0: if ((err = SetupEndpointRead(ep, aCallback)) != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" removing RequestCallback @ 0x%x (due to error)", sl@0: &aCallback)); sl@0: iRequestCallbacks[ep] = NULL; sl@0: } sl@0: } sl@0: else // (ep == 0) sl@0: { sl@0: if (iEp0ReadRequestCallbacks.Elements() == KUsbcMaxListLength) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", sl@0: KUsbcMaxListLength)); sl@0: return KErrGeneral; sl@0: } sl@0: if (IsInTheRequestList(aCallback)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" RequestCallback @ 0x%x already registered", &aCallback)); sl@0: return KErrNone; sl@0: } sl@0: // Ep0 reads don't need to be prepared - there's always one pending sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" adding RequestCallback @ 0x%x (ep0)", &aCallback)); sl@0: TInt irq = NKern::DisableAllInterrupts(); sl@0: iEp0ReadRequestCallbacks.AddLast(aCallback); sl@0: NKern::RestoreInterrupts(irq); sl@0: err = KErrNone; sl@0: if (iEp0_RxExtraData) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" iEp0_RxExtraData: trying again...")); sl@0: const TBool rx_data = iEp0DataReceiving; sl@0: const TInt irq = NKern::DisableAllInterrupts(); sl@0: err = ProcessEp0ReceiveDone(iEp0_RxExtraCount); sl@0: NKern::RestoreInterrupts(irq); sl@0: if (err == KErrNone) sl@0: { sl@0: iEp0_RxExtraData = EFalse; sl@0: // Queue a new Ep0 read (because xxxProceed only re-enables the interrupt) sl@0: SetupEndpointZeroRead(); sl@0: if (rx_data) sl@0: { sl@0: Ep0ReceiveProceed(); sl@0: } sl@0: else sl@0: { sl@0: Ep0ReadSetupPktProceed(); sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" :-)")); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: :-(")); sl@0: err = KErrGeneral; sl@0: } sl@0: return err; sl@0: } sl@0: } sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** Sets up a data write request for an endpoint. sl@0: sl@0: @param aCallback A reference to a properly filled in data transfer request callback structure. sl@0: sl@0: @return KErrNone if callback successfully registered or if this callback is already registered sl@0: (but it won't be registered twice), KErrNotFound if the endpoint couldn't be found, KErrArgument if sl@0: endpoint number invalid (PSL), KErrGeneral if something else goes wrong. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetupWriteBuffer(TUsbcRequestCallback& aCallback) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetupWriteBuffer()")); sl@0: TInt ep = aCallback.iRealEpNum; sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" logical ep: #%d", aCallback.iEndpointNum)); sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" real ep: #%d", ep)); sl@0: if (iRequestCallbacks[ep]) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: RequestCallback already registered for that ep")); sl@0: if (iRequestCallbacks[ep] == &aCallback) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" (this same RequestCallback @ 0x%x)", &aCallback)); sl@0: return KErrNone; sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" (a different RequestCallback @ 0x%x - poss. error)", sl@0: &aCallback)); sl@0: return KErrGeneral; sl@0: } sl@0: } sl@0: if (ep == 0) sl@0: { sl@0: if (iEp0_TxNonStdCount) sl@0: { sl@0: if (iEp0_TxNonStdCount > aCallback.iLength) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Ep0 is sending less data than requested")); sl@0: if ((aCallback.iLength % iEp0MaxPacketSize == 0) && !aCallback.iZlpReqd) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Zlp should probably be requested")); sl@0: } sl@0: } sl@0: else if (iEp0_TxNonStdCount < aCallback.iLength) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Ep0 is sending more data than requested")); sl@0: } sl@0: iEp0_TxNonStdCount = 0; sl@0: } sl@0: // Ep0 IN needs to be adjusted: the LDD uses 0 for both Ep0 directions. sl@0: ep = KEp0_Tx; sl@0: } sl@0: // This may seem awkward: sl@0: // First we add a callback, and then, in case of an error, we remove it again. sl@0: // However this is necessary because the transfer request might complete (through sl@0: // an ISR) _before_ the SetupEndpointWrite function returns. Since we don't know the sl@0: // outcome, we have to provide the callback before making the setup call. sl@0: // sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" adding RequestCallback[%d] @ 0x%x", ep, &aCallback)); sl@0: iRequestCallbacks[ep] = &aCallback; sl@0: if (ep == KEp0_Tx) sl@0: { sl@0: iEp0ClientDataTransmitting = ETrue; // this must be set before calling SetupEndpointZeroWrite sl@0: if (SetupEndpointZeroWrite(aCallback.iBufferStart, aCallback.iLength, aCallback.iZlpReqd) != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" removing RequestCallback @ 0x%x (due to error)", &aCallback)); sl@0: iRequestCallbacks[ep] = NULL; sl@0: iEp0ClientDataTransmitting = EFalse; sl@0: } sl@0: } sl@0: else if (SetupEndpointWrite(ep, aCallback) != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" removing RequestCallback @ 0x%x (due to error)", &aCallback)); sl@0: iRequestCallbacks[ep] = NULL; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** Cancels a data read request for an endpoint. sl@0: sl@0: The request callback will be removed from the queue and the sl@0: callback function won't be executed. sl@0: sl@0: @param aClientId A pointer to the LDD owning the interface which contains the endpoint. sl@0: @param aRealEndpoint The number of the endpoint for which the transfer request is to be cancelled. sl@0: */ sl@0: EXPORT_C void DUsbClientController::CancelReadBuffer(const DBase* aClientId, TInt aRealEndpoint) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CancelReadBuffer(%d)", aRealEndpoint)); sl@0: if (aRealEndpoint < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ep # < 0: %d", aRealEndpoint)); sl@0: return; sl@0: } sl@0: // Note that we here don't cancel Ep0 read requests at the PSL level! sl@0: if (aRealEndpoint > 0) sl@0: { sl@0: CancelEndpointRead(aRealEndpoint); sl@0: } sl@0: DeleteRequestCallback(aClientId, aRealEndpoint, EControllerRead); sl@0: } sl@0: sl@0: sl@0: /** Cancels a data write request for an endpoint. sl@0: sl@0: It cannot be guaranteed that the data is not sent nonetheless, as some UDCs don't permit a flushing of a sl@0: TX FIFO once it has been filled. The request callback will be removed from the queue in any case and the sl@0: callback function won't be executed. sl@0: sl@0: @param aClientId A pointer to the LDD owning the interface which contains the endpoint. sl@0: @param aRealEndpoint The number of the endpoint for which the transfer request is to be cancelled. sl@0: */ sl@0: EXPORT_C void DUsbClientController::CancelWriteBuffer(const DBase* aClientId, TInt aRealEndpoint) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CancelWriteBuffer(%d)", aRealEndpoint)); sl@0: if (aRealEndpoint < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: ep # < 0: %d", aRealEndpoint)); sl@0: return; sl@0: } sl@0: if (aRealEndpoint == 0) sl@0: { sl@0: // Ep0 IN needs to be adjusted: the LDD uses 0 for both Ep0 directions. sl@0: aRealEndpoint = KEp0_Tx; sl@0: } sl@0: CancelEndpointWrite(aRealEndpoint); sl@0: if (aRealEndpoint == KEp0_Tx) sl@0: { sl@0: // Since Ep0 is shared among clients, we don't have to care about the client id. sl@0: iEp0WritePending = EFalse; sl@0: } sl@0: DeleteRequestCallback(aClientId, aRealEndpoint, EControllerWrite); sl@0: } sl@0: sl@0: sl@0: /** Halts (stalls) an endpoint (but not Ep0). sl@0: sl@0: @param aClientId A pointer to the LDD owning the interface which contains the endpoint to be stalled. sl@0: @param aEndpointNum The number of the endpoint. sl@0: sl@0: @return KErrNotFound if endpoint couldn't be found (includes Ep0), KErrNone if endpoint successfully sl@0: stalled, KErrGeneral otherwise. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::HaltEndpoint(const DBase* aClientId, TInt aEndpointNum) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::HaltEndpoint(%d)", aEndpointNum)); sl@0: const TInt r = StallEndpoint(aEndpointNum); sl@0: if (r == KErrNone) sl@0: { sl@0: iRealEndpoints[aEndpointNum].iHalt = ETrue; sl@0: } sl@0: else if (r == KErrArgument) sl@0: { sl@0: return KErrNotFound; sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** Clears the halt condition of an endpoint (but not Ep0). sl@0: sl@0: @param aClientId A pointer to the LDD owning the interface which contains the endpoint to be un-stalled. sl@0: @param aEndpointNum The number of the endpoint. sl@0: sl@0: @return KErrNotFound if endpoint couldn't be found (includes Ep0), KErrNone if endpoint successfully sl@0: stalled, KErrGeneral otherwise. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::ClearHaltEndpoint(const DBase* aClientId, TInt aEndpointNum) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ClearHaltEndpoint(%d)", aEndpointNum)); sl@0: const TInt r = ClearStallEndpoint(aEndpointNum); sl@0: if (r == KErrNone) sl@0: { sl@0: iRealEndpoints[aEndpointNum].iHalt = EFalse; sl@0: } sl@0: else if (r == KErrArgument) sl@0: { sl@0: return KErrNotFound; sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** This function requests 'device control' for an LDD. sl@0: sl@0: Class or vendor specific Ep0 requests addressed to the USB device as a whole (Recipient field in sl@0: bmRequestType byte of a Setup packet set to zero) are delivered to the LDD that owns device control. For sl@0: obvious reasons only one USB LDD can have device control at any given time. sl@0: sl@0: @param aClientId A pointer to the LDD requesting device control. sl@0: sl@0: @return KErrNone if device control successfully claimed or if this LDD already owns it, KErrGeneral if sl@0: device control already owned by a different client. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetDeviceControl(const DBase* aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetDeviceControl()")); sl@0: if (iEp0DeviceControl) sl@0: { sl@0: if (iEp0DeviceControl == aClientId) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Device Control already owned by this client")); sl@0: return KErrNone; sl@0: } sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device Control already claimed by a different client")); sl@0: return KErrGeneral; sl@0: } sl@0: iEp0DeviceControl = aClientId; sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** This function releases device control for an LDD. sl@0: sl@0: @see DUsbClientController::SetDeviceControl() sl@0: sl@0: @param aClientId A pointer to the LDD releasing device control. sl@0: sl@0: @return KErrNone if device control successfully released, KErrGeneral if device control owned by a sl@0: different client or by no client at all. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::ReleaseDeviceControl(const DBase* aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ReleaseDeviceControl()")); sl@0: if (iEp0DeviceControl) sl@0: { sl@0: if (iEp0DeviceControl == aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Releasing Device Control")); sl@0: iEp0DeviceControl = NULL; sl@0: return KErrNone; sl@0: } sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device Control owned by a different client")); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device Control not owned by any client")); sl@0: } sl@0: return KErrGeneral; sl@0: } sl@0: sl@0: sl@0: /** Returns all available (configurable) max packet sizes for Ep0. sl@0: sl@0: The information is coded as bitwise OR'ed values of KUsbEpSizeXXX constants (the bitmap format used for sl@0: TUsbcEndpointCaps.iSupportedSizes). sl@0: sl@0: @return All available (configurable) max packet sizes for Ep0. sl@0: */ sl@0: EXPORT_C TUint DUsbClientController::EndpointZeroMaxPacketSizes() const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EndpointZeroMaxPacketSizes()")); sl@0: return iRealEndpoints[0].iCaps.iSizes; sl@0: } sl@0: sl@0: sl@0: /** Sets (configures) the max packet size for Ep0. sl@0: sl@0: For available sizes as returned by DUsbClientController::EndpointZeroMaxPacketSizes() sl@0: sl@0: Note that for HS operation the Ep0 size cannot be chosen, but is fixed at 64 bytes. sl@0: sl@0: @return KErrNotSupported if invalid size specified, KErrNone if new max packet size successfully set or sl@0: requested size was already set. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetEndpointZeroMaxPacketSize(TInt aMaxPacketSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetEndpointZeroMaxPacketSize(%d)", sl@0: aMaxPacketSize)); sl@0: sl@0: if (DeviceHighSpeedCaps()) sl@0: { sl@0: // We're not going to mess with this on a HS device. sl@0: return KErrNone; sl@0: } sl@0: sl@0: if (!(iRealEndpoints[0].iCaps.iSizes & PacketSize2Mask(aMaxPacketSize))) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid size")); sl@0: return KErrNotSupported; sl@0: } sl@0: if (iRealEndpoints[0].iLEndpoint->iEpSize_Fs == aMaxPacketSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" this packet size already set -> returning")); sl@0: return KErrNone; sl@0: } sl@0: const TUsbcLogicalEndpoint* const ep0_0 = iRealEndpoints[0].iLEndpoint; sl@0: const TUsbcLogicalEndpoint* const ep0_1 = iRealEndpoints[1].iLEndpoint; sl@0: const_cast(ep0_0)->iEpSize_Fs = aMaxPacketSize; sl@0: const_cast(ep0_1)->iEpSize_Fs = aMaxPacketSize; sl@0: sl@0: // @@@ We should probably modify the device descriptor here as well... sl@0: sl@0: if (iHardwareActivated) sl@0: { sl@0: // De-configure endpoint zero sl@0: DeConfigureEndpoint(KEp0_Out); sl@0: DeConfigureEndpoint(KEp0_In); sl@0: // Re-configure endpoint zero sl@0: const_cast(ep0_0)->iInfo.iSize = ep0_0->iEpSize_Fs; sl@0: const_cast(ep0_1)->iInfo.iSize = ep0_1->iEpSize_Fs; sl@0: ConfigureEndpoint(0, ep0_0->iInfo); sl@0: ConfigureEndpoint(1, ep0_1->iInfo); sl@0: iEp0MaxPacketSize = ep0_0->iInfo.iSize; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** Returns the current USB Device descriptor. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor is running in. sl@0: @param aDeviceDescriptor A reference to a buffer into which the requested descriptor should be written sl@0: (most likely located user-side). sl@0: sl@0: @return The return value of the thread write operation, Kern::ThreadWrite(), when writing to the target sl@0: buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetDeviceDescriptor(DThread* aThread, TDes8& aDeviceDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetDeviceDescriptor()")); sl@0: return iDescriptors.GetDeviceDescriptorTC(aThread, aDeviceDescriptor); sl@0: } sl@0: sl@0: sl@0: /** Sets a new USB Device descriptor. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. sl@0: @param aDeviceDescriptor A reference to a buffer which contains the descriptor to be set (most likely sl@0: located user-side). sl@0: sl@0: @return The return value of the thread read operation, Kern::ThreadRead(), when reading from the source sl@0: buffer in case of a failure, KErrNone if the new descriptor was successfully set. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetDeviceDescriptor(DThread* aThread, const TDes8& aDeviceDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetDeviceDescriptor()")); sl@0: return iDescriptors.SetDeviceDescriptorTC(aThread, aDeviceDescriptor); sl@0: } sl@0: sl@0: sl@0: /** Returns the current USB Device descriptor size. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. sl@0: @param aSize A reference to a buffer into which the requested descriptor size should be written sl@0: (most likely located user-side). sl@0: sl@0: @return The return value of the thread write operation, Kern::ThreadWrite(), when writing to the target sl@0: buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetDeviceDescriptorSize(DThread* aThread, TDes8& aSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetDeviceDescriptorSize()")); sl@0: // We do not really enquire here.... sl@0: const TPtrC8 size(reinterpret_cast(&KUsbDescSize_Device), sizeof(KUsbDescSize_Device)); sl@0: return Kern::ThreadDesWrite(aThread, &aSize, size, 0); sl@0: } sl@0: sl@0: sl@0: /** Returns the current USB configuration descriptor. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor is running in. sl@0: @param aConfigurationDescriptor A reference to a buffer into which the requested descriptor should be sl@0: written (most likely located user-side). sl@0: sl@0: @return The return value of the thread write operation, Kern::ThreadWrite(), when writing to the target sl@0: buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetConfigurationDescriptor(DThread* aThread, TDes8& aConfigurationDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetConfigurationDescriptor()")); sl@0: return iDescriptors.GetConfigurationDescriptorTC(aThread, aConfigurationDescriptor); sl@0: } sl@0: sl@0: sl@0: /** Sets a new USB configuration descriptor. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. sl@0: @param aConfigurationDescriptor A reference to a buffer which contains the descriptor to be set (most sl@0: likely located user-side). sl@0: sl@0: @return The return value of the thread read operation, Kern::ThreadRead() when reading from the source sl@0: buffer in case of a failure, KErrNone if the new descriptor was successfully set. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetConfigurationDescriptor(DThread* aThread, sl@0: const TDes8& aConfigurationDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetConfigurationDescriptor()")); sl@0: return iDescriptors.SetConfigurationDescriptorTC(aThread, aConfigurationDescriptor); sl@0: } sl@0: sl@0: sl@0: /** Returns the current USB configuration descriptor size. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. sl@0: @param aSize A reference to a buffer into which the requested descriptor size should be written sl@0: (most likely located user-side). sl@0: sl@0: @return The return value of the thread write operation, Kern::ThreadWrite(), when writing to the target sl@0: buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetConfigurationDescriptorSize(DThread* aThread, TDes8& aSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetConfigurationDescriptorSize()")); sl@0: // We do not really enquire here.... sl@0: const TPtrC8 size(reinterpret_cast(&KUsbDescSize_Config), sizeof(KUsbDescSize_Config)); sl@0: return Kern::ThreadDesWrite(aThread, &aSize, size, 0); sl@0: } sl@0: sl@0: sl@0: /** Returns the current USB OTG descriptor. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. sl@0: @param aOtgDesc A reference to a buffer into which the requested descriptor should be sl@0: written (most likely located user-side). sl@0: sl@0: @return KErrNotSupported or the return value of the thread write operation, Kern::ThreadDesWrite(), sl@0: when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetOtgDescriptor(DThread* aThread, TDes8& aOtgDesc) const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetOtgDescriptor()")); sl@0: if (!iOtgSupport) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: return iDescriptors.GetOtgDescriptorTC(aThread, aOtgDesc); sl@0: } sl@0: sl@0: sl@0: /** Sets a new OTG descriptor. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. sl@0: @param aOtgDesc A reference to a buffer which contains new OTG descriptor. sl@0: sl@0: @return KErrNotSupported or the return value of the thread read operation, Kern::ThreadDesRead(). sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetOtgDescriptor(DThread* aThread, const TDesC8& aOtgDesc) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetOtgDescriptor()")); sl@0: if (!iOtgSupport) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: TBuf8 otg; sl@0: const TInt r = Kern::ThreadDesRead(aThread, &aOtgDesc, otg, 0); sl@0: if (r != KErrNone) sl@0: { sl@0: return r; sl@0: } sl@0: // Check descriptor validity sl@0: if (otg[0] != KUsbDescSize_Otg || otg[1] != KUsbDescType_Otg || otg[2] > 3) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid OTG descriptor")); sl@0: return KErrGeneral; sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" iOtgFuncMap before: 0x%x", iOtgFuncMap)); sl@0: // Update value in controller as well sl@0: const TUint8 hnp = otg[2] & KUsbOtgAttr_HnpSupp; sl@0: const TUint8 srp = otg[2] & KUsbOtgAttr_SrpSupp; sl@0: if (hnp && !srp) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: Invalid OTG attribute combination (HNP && !SRP")); sl@0: } sl@0: if (hnp && !(iOtgFuncMap & KUsbOtgAttr_HnpSupp)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Setting attribute KUsbOtgAttr_HnpSupp")); sl@0: iOtgFuncMap |= KUsbOtgAttr_HnpSupp; sl@0: } sl@0: else if (!hnp && (iOtgFuncMap & KUsbOtgAttr_HnpSupp)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Removing attribute KUsbOtgAttr_HnpSupp")); sl@0: iOtgFuncMap &= ~KUsbOtgAttr_HnpSupp; sl@0: } sl@0: if (srp && !(iOtgFuncMap & KUsbOtgAttr_SrpSupp)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Setting attribute KUsbOtgAttr_SrpSupp")); sl@0: iOtgFuncMap |= KUsbOtgAttr_SrpSupp; sl@0: } sl@0: else if (!srp && (iOtgFuncMap & KUsbOtgAttr_SrpSupp)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Removing attribute KUsbOtgAttr_SrpSupp")); sl@0: iOtgFuncMap &= ~KUsbOtgAttr_SrpSupp; sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" iOtgFuncMap after: 0x%x", iOtgFuncMap)); sl@0: return iDescriptors.SetOtgDescriptor(otg); sl@0: } sl@0: sl@0: sl@0: /** Returns current OTG features of USB device. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. sl@0: @param aFeatures A reference to a buffer into which the requested OTG features should be written. sl@0: sl@0: @return KErrNotSupported or the return value of the thread write operation, Kern::ThreadDesWrite(). sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetOtgFeatures(DThread* aThread, TDes8& aFeatures) const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetOtgFeatures()")); sl@0: if (!iOtgSupport) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: TBuf8<1> features(1); sl@0: features[0] = iOtgFuncMap & 0x1C; sl@0: return Kern::ThreadDesWrite(aThread, &aFeatures, features, 0); sl@0: } sl@0: sl@0: sl@0: /** Returns current OTG features of USB device. This function is intended to be sl@0: called only from kernel side. sl@0: sl@0: @param aFeatures The reference to which the current features should be set at. sl@0: @return KErrNone if successful, KErrNotSupported if OTG is unavailable. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetCurrentOtgFeatures(TUint8& aFeatures) const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetCurrentOtgFeatures()")); sl@0: if (!iOtgSupport) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: aFeatures = iOtgFuncMap & 0x1C; sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** Registers client request for OTG feature change. Client is notified when any OTG sl@0: feature is changed. sl@0: sl@0: @see KUsbOtgAttr_B_HnpEnable, KUsbOtgAttr_A_HnpSupport, KUsbOtgAttr_A_AltHnpSupport sl@0: sl@0: @param aCallback Callback function. Gets called when OTG features change sl@0: sl@0: @return KErrNone if successful, KErrAlreadyExists if aCallback is already in the queue. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::RegisterForOtgFeatureChange(TUsbcOtgFeatureCallback& aCallback) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterForOtgFeatureChange()")); sl@0: if (iOtgCallbacks.Elements() == KUsbcMaxListLength) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Maximum list length reached: %d", sl@0: KUsbcMaxListLength)); sl@0: return KErrGeneral; sl@0: } sl@0: if (IsInTheOtgFeatureList(aCallback)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Error: OtgFeatureCallback @ 0x%x already registered", &aCallback)); sl@0: return KErrAlreadyExists; sl@0: } sl@0: const TInt irq = NKern::DisableAllInterrupts(); sl@0: iOtgCallbacks.AddLast(aCallback); sl@0: NKern::RestoreInterrupts(irq); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** De-registers (removes from the list of pending requests) a notification callback for sl@0: OTG feature change. sl@0: sl@0: @param aClientId A pointer to the LDD owning the endpoint status change callback. sl@0: sl@0: @return KErrNone if callback successfully unregistered, KErrNotFound if the callback couldn't be found. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::DeRegisterForOtgFeatureChange(const DBase* aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterForOtgFeatureChange()")); sl@0: __ASSERT_DEBUG((aClientId != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); sl@0: const TInt irq = NKern::DisableAllInterrupts(); sl@0: TSglQueIter iter(iOtgCallbacks); sl@0: TUsbcOtgFeatureCallback* p; sl@0: while ((p = iter++) != NULL) sl@0: { sl@0: if (!aClientId || p->Owner() == aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" removing OtgFeatureCallback @ 0x%x", p)); sl@0: iOtgCallbacks.Remove(*p); sl@0: NKern::RestoreInterrupts(irq); sl@0: return KErrNone; sl@0: } sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" client not found")); sl@0: NKern::RestoreInterrupts(irq); sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: sl@0: /** Returns a specific standard USB interface descriptor. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor is running in. sl@0: @param aClientId A pointer to the LDD requesting the descriptor. sl@0: @param aSettingNum The setting number of the interface for which the descriptor is requested. sl@0: @param aInterfaceDescriptor A reference to a buffer into which the requested descriptor should be written sl@0: (most likely located user-side). sl@0: sl@0: @return KErrNotFound if the specified interface couldn't be found, otherwise the return value of the thread sl@0: write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetInterfaceDescriptor(DThread* aThread, const DBase* aClientId, sl@0: TInt aSettingNum, TDes8& aInterfaceDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetInterfaceDescriptor(x, 0x%08x, %d, y)", sl@0: aClientId, aSettingNum)); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); sl@0: return KErrNotFound; sl@0: } sl@0: return iDescriptors.GetInterfaceDescriptorTC(aThread, aInterfaceDescriptor, ifcset, aSettingNum); sl@0: } sl@0: sl@0: sl@0: /** Sets a new standard USB interface descriptor. sl@0: sl@0: This function can also be used, by the user, and under certain conditions, to change an interface's number sl@0: (reported as bInterfaceNumber in the descriptor). The conditions are: 1) We cannot accept a number that is sl@0: already used by another interface, 2) We allow the interface number to be changed only when it's still the sl@0: only setting, and 3) We allow the interface number to be changed only for the default setting (0). (All sl@0: alternate settings created for that interface thereafter will inherit the new, changed number.) sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. sl@0: @param aClientId A pointer to the LDD requesting the setting of the descriptor. sl@0: @param aSettingNum The setting number of the interface for which the descriptor is to be set. sl@0: @param aInterfaceDescriptor A reference to a buffer which contains the descriptor to be set (most sl@0: likely located user-side). sl@0: sl@0: @return KErrNotFound if the specified interface couldn't be found, the return value of the thread read sl@0: operation, Kern::ThreadRead(), when reading from the source buffer in case of a failure, KErrArgument if the sl@0: interface number is to be changed (via bInterfaceNumber in the descriptor) and either the requested sl@0: interface number is already used by another interface or the interface has more than one setting. KErrNone sl@0: if the new descriptor was successfully set. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetInterfaceDescriptor(DThread* aThread, const DBase* aClientId, sl@0: TInt aSettingNum, const TDes8& aInterfaceDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetInterfaceDescriptor(x, 0x%08x, %d, y)", sl@0: aClientId, aSettingNum)); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); sl@0: return KErrNotFound; sl@0: } sl@0: TBuf8 new_ifc; sl@0: TInt r = Kern::ThreadDesRead(aThread, &aInterfaceDescriptor, new_ifc, 0); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Copying interface descriptor buffer failed (%d)", r)); sl@0: return r; sl@0: } sl@0: const TInt ifcset_new = new_ifc[2]; sl@0: const TBool ifc_num_changes = (ifcset != ifcset_new); sl@0: TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); sl@0: if (!ifcset_ptr) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface number %d doesn't exist", ifcset)); sl@0: return KErrNotFound; sl@0: } sl@0: if (ifc_num_changes) sl@0: { sl@0: // If the user wants to change the interface number, we need to do some sanity checks: sl@0: if (InterfaceExists(ifcset_new)) sl@0: { sl@0: // Obviously we cannot accept a number that is already used by another interface. sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface number %d already in use", ifcset_new)); sl@0: return KErrArgument; sl@0: } sl@0: if (ifcset_ptr->iInterfaces.Count() > 1) sl@0: { sl@0: // We allow the interface number to be changed only when it's the only setting. sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface has more than one alternate setting")); sl@0: return KErrArgument; sl@0: } sl@0: if (aSettingNum != 0) sl@0: { sl@0: // We allow the interface number to be changed only when it's the default setting. sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface number can only be changed for setting 0")); sl@0: return KErrArgument; sl@0: } sl@0: } sl@0: if ((r = iDescriptors.SetInterfaceDescriptor(new_ifc, ifcset, aSettingNum)) != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: iDescriptors.SetInterfaceDescriptorfailed")); sl@0: return r; sl@0: } sl@0: if (ifc_num_changes) sl@0: { sl@0: // Alright then, let's do it... sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" about to change interface number from %d to %d", sl@0: ifcset, ifcset_new)); sl@0: ifcset_ptr->iInterfaceNumber = ifcset_new; sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** Returns the size of a specific standard USB interface descriptor. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. sl@0: @param aClientId A pointer to the LDD requesting the descriptor size. sl@0: @param aSettingNum The setting number of the interface for which the descriptor size is requested. sl@0: @param aSize A reference to a buffer into which the requested descriptor size should be written (most sl@0: likely located user-side). sl@0: sl@0: @return KErrNotFound if the specified interface couldn't be found, otherwise the return value of the thread sl@0: write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetInterfaceDescriptorSize(DThread* aThread, const DBase* aClientId, sl@0: TInt /*aSettingNum*/, TDes8& aSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetInterfaceDescriptorSize()")); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); sl@0: return KErrNotFound; sl@0: } sl@0: // Actually, we do not really enquire here.... sl@0: const TPtrC8 size(reinterpret_cast(&KUsbDescSize_Interface), sizeof(KUsbDescSize_Interface)); sl@0: Kern::ThreadDesWrite(aThread, &aSize, size, 0); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** Returns a specific standard USB endpoint descriptor. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor is running in. sl@0: @param aClientId A pointer to the LDD requesting the descriptor. sl@0: @param aSettingNum The setting number of the interface that contains the endpoint for which the sl@0: descriptor is requested. sl@0: @param aEndpointNum The endpoint for which the descriptor is requested. sl@0: @param aEndpointDescriptor A reference to a buffer into which the requested descriptor should be written sl@0: (most likely located user-side). sl@0: sl@0: @return KErrNotFound if the specified interface or endpoint couldn't be found, otherwise the return value sl@0: of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetEndpointDescriptor(DThread* aThread, const DBase* aClientId, sl@0: TInt aSettingNum, TInt aEndpointNum, sl@0: TDes8& aEndpointDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetEndpointDescriptor(x, 0x%08x, %d, %d, y)", sl@0: aClientId, aSettingNum, aEndpointNum)); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); sl@0: return KErrNotFound; sl@0: } sl@0: return iDescriptors.GetEndpointDescriptorTC(aThread, aEndpointDescriptor, ifcset, sl@0: aSettingNum, EpIdx2Addr(aEndpointNum)); sl@0: } sl@0: sl@0: sl@0: /** Sets a new standard USB endpoint descriptor. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. sl@0: @param aClientId A pointer to the LDD requesting the setting of the descriptor. sl@0: @param aSettingNum The setting number of the interface that contains the endpoint for which the sl@0: descriptor is to be set. sl@0: @param aEndpointNum The endpoint for which the descriptor is to be set. sl@0: @param aEndpointDescriptor A reference to a buffer which contains the descriptor to be set (most sl@0: likely located user-side). sl@0: sl@0: @return KErrNotFound if the specified interface or endpoint couldn't be found, the return value of the sl@0: thread read operation, Kern::ThreadRead(), when reading from the source buffer in case of a read failure, sl@0: KErrNone if the new descriptor was successfully set. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetEndpointDescriptor(DThread* aThread, const DBase* aClientId, sl@0: TInt aSettingNum, TInt aEndpointNum, sl@0: const TDes8& aEndpointDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetEndpointDescriptor(x, 0x%08x, %d, %d, y)", sl@0: aClientId, aSettingNum, aEndpointNum)); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); sl@0: return KErrNotFound; sl@0: } sl@0: return iDescriptors.SetEndpointDescriptorTC(aThread, aEndpointDescriptor, ifcset, sl@0: aSettingNum, EpIdx2Addr(aEndpointNum)); sl@0: } sl@0: sl@0: sl@0: /** Returns the size of a specific standard USB endpoint descriptor. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor size is running in. sl@0: @param aClientId A pointer to the LDD requesting the descriptor size. sl@0: @param aSettingNum The setting number of the interface that contains the endpoint for which the sl@0: descriptor size is requested. sl@0: @param aEndpointNum The endpoint for which the descriptor size is requested. sl@0: @param aEndpointDescriptor A reference to a buffer into which the requested descriptor size should be sl@0: written (most likely located user-side). sl@0: sl@0: @return KErrNotFound if the specified interface or endpoint couldn't be found, otherwise the return value sl@0: of the thread write operation, kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetEndpointDescriptorSize(DThread* aThread, const DBase* aClientId, sl@0: TInt aSettingNum, TInt aEndpointNum, sl@0: TDes8& aSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetEndpointDescriptorSize(x, 0x%08x, %d, %d, y)", sl@0: aClientId, aSettingNum, aEndpointNum)); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); sl@0: return KErrNotFound; sl@0: } sl@0: TInt s; sl@0: TInt r = iDescriptors.GetEndpointDescriptorSize(ifcset, aSettingNum, sl@0: EpIdx2Addr(aEndpointNum), s); sl@0: if (r == KErrNone) sl@0: { sl@0: TPtrC8 size(reinterpret_cast(&s), sizeof(s)); sl@0: r = Kern::ThreadDesWrite(aThread, &aSize, size, 0); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: endpoint descriptor not found")); sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** Returns the current Device_Qualifier descriptor. On a USB device which doesn't support high-speed sl@0: operation this function will return an error. Note that the contents of the descriptor depend on sl@0: the current device speed (full-speed or high-speed). sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor is running in. sl@0: @param aDeviceQualifierDescriptor A reference to a buffer into which the requested descriptor sl@0: should be written (most likely located user-side). sl@0: sl@0: @return KErrNotSupported if this descriptor is not supported, otherwise the return value of the thread sl@0: write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetDeviceQualifierDescriptor(DThread* aThread, sl@0: TDes8& aDeviceQualifierDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetDeviceQualifierDescriptor()")); sl@0: return iDescriptors.GetDeviceQualifierDescriptorTC(aThread, aDeviceQualifierDescriptor); sl@0: } sl@0: sl@0: sl@0: /** Sets a new Device_Qualifier descriptor. On a USB device which doesn't support high-speed sl@0: operation this function will return an error. Note that the contents of the descriptor should take sl@0: into account the current device speed (full-speed or high-speed) as it is dependent on it. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. sl@0: @param aDeviceQualifierDescriptor A reference to a buffer which contains the descriptor to be set (most sl@0: likely located user-side). sl@0: sl@0: @return KErrNotSupported if this descriptor is not supported, otherwise the return value of the thread sl@0: read operation, Kern::ThreadRead(), when reading from the source buffer in case of a failure, KErrNone if sl@0: the new descriptor was successfully set. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetDeviceQualifierDescriptor(DThread* aThread, sl@0: const TDes8& aDeviceQualifierDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetDeviceQualifierDescriptor()")); sl@0: return iDescriptors.SetDeviceQualifierDescriptorTC(aThread, aDeviceQualifierDescriptor); sl@0: } sl@0: sl@0: sl@0: /** Returns the current Other_Speed_Configuration descriptor. On a USB device which doesn't support high-speed sl@0: operation this function will return an error. Note that the contents of the descriptor depend on the sl@0: current device speed (full-speed or high-speed). sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor is running in. sl@0: @param aConfigurationDescriptor A reference to a buffer into which the requested descriptor sl@0: should be written (most likely located user-side). sl@0: sl@0: @return KErrNotSupported if this descriptor is not supported, otherwise the return value of the thread sl@0: write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetOtherSpeedConfigurationDescriptor(DThread* aThread, sl@0: TDes8& aConfigurationDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetOtherSpeedConfigurationDescriptor()")); sl@0: return iDescriptors.GetOtherSpeedConfigurationDescriptorTC(aThread, aConfigurationDescriptor); sl@0: } sl@0: sl@0: sl@0: /** Sets a new Other_Speed_Configuration descriptor. On a USB device which doesn't support high-speed sl@0: operation this function will return an error. Note that the contents of the descriptor should take sl@0: into account the current device speed (full-speed or high-speed) as it is dependent on it. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the descriptor is running in. sl@0: @param aConfigurationDescriptor A reference to a buffer which contains the descriptor to be set (most sl@0: likely located user-side). sl@0: sl@0: @return KErrNotSupported if this descriptor is not supported, otherwise the return value of the thread sl@0: read operation, Kern::ThreadRead(), when reading from the source buffer in case of a failure, KErrNone if sl@0: the new descriptor was successfully set. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetOtherSpeedConfigurationDescriptor(DThread* aThread, sl@0: const TDes8& aConfigurationDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetOtherSpeedConfigurationDescriptor()")); sl@0: return iDescriptors.SetOtherSpeedConfigurationDescriptorTC(aThread, aConfigurationDescriptor); sl@0: } sl@0: sl@0: sl@0: /** Returns a block of all available non-standard (class-specific) interface descriptors for a specific sl@0: interface. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor block is running in. sl@0: @param aClientId A pointer to the LDD requesting the descriptor block. sl@0: @param aSettingNum The setting number of the interface for which the descriptor block is requested. sl@0: @param aInterfaceDescriptor A reference to a buffer into which the requested descriptor(s) should be sl@0: written (most likely located user-side). sl@0: sl@0: @return KErrNotFound if the specified interface couldn't be found, otherwise the return value of the thread sl@0: write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetCSInterfaceDescriptorBlock(DThread* aThread, const DBase* aClientId, sl@0: TInt aSettingNum, sl@0: TDes8& aInterfaceDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetCSInterfaceDescriptorBlock(x, 0x%08x, %d, y)", sl@0: aClientId, aSettingNum)); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); sl@0: return KErrNotFound; sl@0: } sl@0: return iDescriptors.GetCSInterfaceDescriptorTC(aThread, aInterfaceDescriptor, ifcset, aSettingNum); sl@0: } sl@0: sl@0: sl@0: /** Sets a block of (i.e. one or more) non-standard (class-specific) interface descriptors for a specific sl@0: interface. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the descriptor block is running sl@0: in. sl@0: @param aClientId A pointer to the LDD requesting the setting of the descriptor block. sl@0: @param aSettingNum The setting number of the interface for which the setting of the descriptor block is sl@0: requested. sl@0: @param aInterfaceDescriptor A reference to a buffer which contains the descriptor block to be set (most sl@0: likely located user-side). sl@0: @param aSize The size of the descriptor block to be set. sl@0: sl@0: @return KErrNotFound if the specified interface couldn't be found, KErrArgument if aSize is less than 2, sl@0: KErrNoMemory if enough memory for the new descriptor(s) couldn't be allocated, otherwise the return value sl@0: of the thread read operation, Kern::ThreadRead(), when reading from the source buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetCSInterfaceDescriptorBlock(DThread* aThread, const DBase* aClientId, sl@0: TInt aSettingNum, sl@0: const TDes8& aInterfaceDescriptor, TInt aSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, sl@0: Kern::Printf("DUsbClientController::SetCSInterfaceDescriptorBlock(x, 0x%08x, %d, y, %d)", sl@0: aClientId, aSettingNum, aSize)); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); sl@0: return KErrNotFound; sl@0: } sl@0: if (aSize < 2) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aSize < 2 (%d)", aSize)); sl@0: return KErrArgument; sl@0: } sl@0: return iDescriptors.SetCSInterfaceDescriptorTC(aThread, aInterfaceDescriptor, ifcset, aSettingNum, aSize); sl@0: } sl@0: sl@0: sl@0: /** Returns the total size all non-standard (class-specific) interface descriptors for a specific interface. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor block size is running in. sl@0: @param aClientId A pointer to the LDD requesting the descriptor block size. sl@0: @param aSettingNum The setting number of the interface for which the descriptor block size is sl@0: requested. sl@0: @param aSize A reference to a buffer into which the requested descriptor block size should be written (most sl@0: likely located user-side). sl@0: sl@0: @return KErrNotFound if the specified interface couldn't be found, otherwise the return value of the thread sl@0: write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetCSInterfaceDescriptorBlockSize(DThread* aThread, const DBase* aClientId, sl@0: TInt aSettingNum, TDes8& aSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, sl@0: Kern::Printf("DUsbClientController::GetCSInterfaceDescriptorBlockSize(x, 0x%08x, %d, y)", sl@0: aClientId, aSettingNum)); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); sl@0: return KErrNotFound; sl@0: } sl@0: TInt s; sl@0: const TInt r = iDescriptors.GetCSInterfaceDescriptorSize(ifcset, aSettingNum, s); sl@0: if (r == KErrNone) sl@0: { sl@0: const TPtrC8 size(reinterpret_cast(&s), sizeof(s)); sl@0: Kern::ThreadDesWrite(aThread, &aSize, size, 0); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: cs interface descriptor not found")); sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** Returns a block of all available non-standard (class-specific) endpoint descriptors for a specific endpoint. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor block is running in. sl@0: @param aClientId A pointer to the LDD requesting the descriptor block. sl@0: @param aSettingNum The setting number of the interface that contains the endpoint for which the sl@0: descriptor block is requested. sl@0: @param aEndpointNum The endpoint for which the descriptor block is requested. sl@0: @param aEndpointDescriptor A reference to a buffer into which the requested descriptor(s) should be written sl@0: (most likely located user-side). sl@0: sl@0: @return KErrNotFound if the specified interface or endpoint couldn't be found, otherwise the return value sl@0: of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetCSEndpointDescriptorBlock(DThread* aThread, const DBase* aClientId, sl@0: TInt aSettingNum, TInt aEndpointNum, sl@0: TDes8& aEndpointDescriptor) sl@0: { sl@0: __KTRACE_OPT(KUSB, sl@0: Kern::Printf("DUsbClientController::GetCSEndpointDescriptorBlock(x, 0x%08x, %d, %d, y)", sl@0: aClientId, aSettingNum, aEndpointNum)); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); sl@0: return KErrNotFound; sl@0: } sl@0: return iDescriptors.GetCSEndpointDescriptorTC(aThread, aEndpointDescriptor, ifcset, sl@0: aSettingNum, EpIdx2Addr(aEndpointNum)); sl@0: } sl@0: sl@0: sl@0: /** Sets a block of (i.e. one or more) non-standard (class-specific) endpoint descriptors for a specific sl@0: endpoint. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the descriptor block is running sl@0: in. sl@0: @param aClientId A pointer to the LDD requesting the setting of the descriptor block. sl@0: @param aSettingNum The setting number of the interface that contains the endpoint for which the sl@0: descriptor block is to be set. sl@0: @param aEndpointNum The endpoint for which the descriptor block is to be set. sl@0: @param aEndpointDescriptor A reference to a buffer which contains the descriptor block to be set (most sl@0: likely located user-side). sl@0: @param aSize The size of the descriptor block to be set. sl@0: sl@0: @return KErrNotFound if the specified interface or endpoint couldn't be found, KErrArgument if aSize is sl@0: less than 2, KErrNoMemory if enough memory for the new descriptor(s) couldn't be allocated, otherwise the sl@0: return value of the thread read operation, Kern::ThreadRead(), when reading from the source buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetCSEndpointDescriptorBlock(DThread* aThread, const DBase* aClientId, sl@0: TInt aSettingNum, TInt aEndpointNum, sl@0: const TDes8& aEndpointDescriptor, TInt aSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, sl@0: Kern::Printf("DUsbClientController::SetCSEndpointDescriptorBlock(x, 0x%08x, %d, %d, y)", sl@0: aClientId, aSettingNum, aEndpointNum)); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); sl@0: return KErrNotFound; sl@0: } sl@0: if (aSize < 2) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aSize < 2 (%d)", aSize)); sl@0: return KErrArgument; sl@0: } sl@0: return iDescriptors.SetCSEndpointDescriptorTC(aThread, aEndpointDescriptor, ifcset, sl@0: aSettingNum, EpIdx2Addr(aEndpointNum), aSize); sl@0: } sl@0: sl@0: sl@0: /** Returns the total size all non-standard (class-specific) endpoint descriptors for a specific endpoint. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the descriptor block size is running in. sl@0: @param aClientId A pointer to the LDD requesting the descriptor block size. sl@0: @param aSettingNum The setting number of the interface for which the descriptor block size is sl@0: requested. sl@0: @param aEndpointNum The endpoint for which the descriptor block size is requested. sl@0: @param aSize A reference to a buffer into which the requested descriptor block size should be written (most sl@0: likely located user-side). sl@0: sl@0: @return KErrNotFound if the specified interface or endpoint couldn't be found, otherwise the return value sl@0: of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetCSEndpointDescriptorBlockSize(DThread* aThread, const DBase* aClientId, sl@0: TInt aSettingNum, TInt aEndpointNum, sl@0: TDes8& aSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, sl@0: Kern::Printf("DUsbClientController::GetCSEndpointDescriptorBlockSize(x, 0x%08x, %d, %d, y)", sl@0: aClientId, aSettingNum, aEndpointNum)); sl@0: const TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface not found from client ID")); sl@0: return KErrNotFound; sl@0: } sl@0: TInt s; sl@0: const TInt r = iDescriptors.GetCSEndpointDescriptorSize(ifcset, aSettingNum, sl@0: EpIdx2Addr(aEndpointNum), s); sl@0: if (r == KErrNone) sl@0: { sl@0: const TPtrC8 size(reinterpret_cast(&s), sizeof(s)); sl@0: Kern::ThreadDesWrite(aThread, &aSize, size, 0); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: cs endpoint descriptor not found")); sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** Returns the currently set string descriptor language ID (LANGID) code. sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the LANGID is running in. sl@0: @param aLangId A reference to a buffer into which the requested code should be written (most likely sl@0: located user-side). sl@0: sl@0: @return The return value of the thread write operation, Kern::ThreadDesWrite(), sl@0: when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetStringDescriptorLangId(DThread* aThread, TDes8& aLangId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetStringDescriptorLangId()")); sl@0: return iDescriptors.GetStringDescriptorLangIdTC(aThread, aLangId); sl@0: } sl@0: sl@0: sl@0: /** Sets the string descriptor language ID (LANGID) code. sl@0: sl@0: @param aLangId The langauge ID code to be written. sl@0: sl@0: @return KErrNone. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetStringDescriptorLangId(TUint16 aLangId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetStringDescriptorLangId()")); sl@0: return iDescriptors.SetStringDescriptorLangId(aLangId); sl@0: } sl@0: sl@0: sl@0: /** Returns the currently set Manufacturer string (which is referenced by the iManufacturer field in the device sl@0: descriptor). sl@0: sl@0: (Thus, the function should actually be called either 'GetManufacturerString' sl@0: or 'GetManufacturerStringDescriptorString'.) sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the string is running in. sl@0: @param aString A reference to a buffer into which the requested string should be written (most likely sl@0: located user-side). sl@0: sl@0: @return KErrNotFound if the string descriptor couldn't be found (PIL internal error), otherwise the return sl@0: value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetManufacturerStringDescriptor(DThread* aThread, TDes8& aString) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetManufacturerStringDescriptor()")); sl@0: return iDescriptors.GetManufacturerStringDescriptorTC(aThread, aString); sl@0: } sl@0: sl@0: sl@0: /** Sets a new Manufacturer string in the Manufacturer string descriptor (which is referenced by the sl@0: iManufacturer field in the device descriptor). sl@0: sl@0: (Thus, the function should actually be called either sl@0: 'SetManufacturerString' or 'SetManufacturerStringDescriptorString'.) sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. sl@0: @param aString A reference to a buffer which contains the string to be set (most likely located sl@0: user-side). sl@0: sl@0: @return KErrNoMemory if not enough memory for the new descriptor or the string could be allocated, the sl@0: return value of the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong, sl@0: KErrNone if new string descriptor successfully set. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetManufacturerStringDescriptor(DThread* aThread, const TDes8& aString) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetManufacturerStringDescriptor()")); sl@0: return iDescriptors.SetManufacturerStringDescriptorTC(aThread, aString); sl@0: } sl@0: sl@0: sl@0: /** Removes (deletes) the Manufacturer string descriptor (which is referenced by the sl@0: iManufacturer field in the device descriptor). sl@0: sl@0: @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::RemoveManufacturerStringDescriptor() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveManufacturerStringDescriptor()")); sl@0: return iDescriptors.RemoveManufacturerStringDescriptor(); sl@0: } sl@0: sl@0: sl@0: /** Returns the currently set Product string (which is referenced by the iProduct field in the device sl@0: descriptor). sl@0: sl@0: (Thus, the function should actually be called either 'GetProductString' or sl@0: 'GetProductStringDescriptorString'.) sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the string is running in. sl@0: @param aString A reference to a buffer into which the requested string should be written (most likely sl@0: located user-side). sl@0: sl@0: @return KErrNotFound if the string descriptor couldn't be found (PIL internal error), otherwise the return sl@0: value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetProductStringDescriptor(DThread* aThread, TDes8& aString) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetProductStringDescriptor()")); sl@0: return iDescriptors.GetProductStringDescriptorTC(aThread, aString); sl@0: } sl@0: sl@0: sl@0: /** Sets a new Product string in the Product string descriptor (which is referenced by the iProduct field in sl@0: the device descriptor). sl@0: sl@0: (Thus, the function should actually be called either 'SetProductString' or sl@0: 'SetProductStringDescriptorString'.) sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. sl@0: @param aString A reference to a buffer which contains the string to be set (most likely located sl@0: user-side). sl@0: sl@0: @return KErrNoMemory if not enough memory for the new descriptor or the string could be allocated, the sl@0: return value of the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong, sl@0: KErrNone if new string descriptor successfully set. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetProductStringDescriptor(DThread* aThread, const TDes8& aString) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetProductStringDescriptor()")); sl@0: return iDescriptors.SetProductStringDescriptorTC(aThread, aString); sl@0: } sl@0: sl@0: sl@0: /** Removes (deletes) the Product string descriptor (which is referenced by the sl@0: iProduct field in the device descriptor). sl@0: sl@0: @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::RemoveProductStringDescriptor() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveProductStringDescriptor()")); sl@0: return iDescriptors.RemoveProductStringDescriptor(); sl@0: } sl@0: sl@0: sl@0: /** Returns the currently set SerialNumber string (which is referenced by the iSerialNumber field in the device sl@0: descriptor). sl@0: sl@0: (Thus, the function should actually be called either 'GetSerialNumberString' or sl@0: 'GetSerialNumberStringDescriptorString'.) sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the string is running in. sl@0: @param aString A reference to a buffer into which the requested string should be written (most likely sl@0: located user-side). sl@0: sl@0: @return KErrNotFound if the string descriptor couldn't be found (PIL internal error), otherwise the return sl@0: value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetSerialNumberStringDescriptor(DThread* aThread, TDes8& aString) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetSerialNumberStringDescriptor()")); sl@0: return iDescriptors.GetSerialNumberStringDescriptorTC(aThread, aString); sl@0: } sl@0: sl@0: sl@0: /** Sets a new SerialNumber string in the SerialNumber string descriptor (which is referenced by the sl@0: iSerialNumber field in the device descriptor). sl@0: sl@0: (Thus, the function should actually be called either sl@0: 'SetSerialNumberString' or 'SetSerialNumberStringDescriptorString'.) sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. sl@0: @param aString A reference to a buffer which contains the string to be set (most likely located sl@0: user-side). sl@0: sl@0: @return KErrNoMemory if not enough memory for the new descriptor or the string could be allocated, the sl@0: return value of the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong, sl@0: KErrNone if new string descriptor successfully set. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetSerialNumberStringDescriptor(DThread* aThread, const TDes8& aString) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetSerialNumberStringDescriptor()")); sl@0: return iDescriptors.SetSerialNumberStringDescriptorTC(aThread, aString); sl@0: } sl@0: sl@0: sl@0: /** Removes (deletes) the Serial Number string descriptor (which is referenced by the sl@0: iSerialNumber field in the device descriptor). sl@0: sl@0: @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::RemoveSerialNumberStringDescriptor() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveSerialNumberStringDescriptor()")); sl@0: return iDescriptors.RemoveSerialNumberStringDescriptor(); sl@0: } sl@0: sl@0: sl@0: /** Returns the currently set Configuration string (which is referenced by the iConfiguration field in the sl@0: configuration descriptor). sl@0: sl@0: (Thus, the function should actually be called either 'GetConfigurationString' or sl@0: 'GetConfigurationStringDescriptorString'.) sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the string is running in. sl@0: @param aString A reference to a buffer into which the requested string should be written (most likely sl@0: located user-side). sl@0: sl@0: @return KErrNotFound if the string descriptor couldn't be found (PIL internal error), otherwise the return sl@0: value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetConfigurationStringDescriptor(DThread* aThread, TDes8& aString) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetConfigurationStringDescriptor()")); sl@0: return iDescriptors.GetConfigurationStringDescriptorTC(aThread, aString); sl@0: } sl@0: sl@0: sl@0: /** Sets a new Configuration string in the Configuration string descriptor (which is referenced by the sl@0: iConfiguration field in the configuration descriptor). sl@0: sl@0: (Thus, the function should actually be called either sl@0: 'SetConfigurationString' or 'SetConfigurationStringDescriptorString'.) sl@0: sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. sl@0: @param aString A reference to a buffer which contains the string to be set (most likely located sl@0: user-side). sl@0: sl@0: @return KErrNoMemory if not enough memory for the new descriptor or the string could be allocated, the sl@0: return value of the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong, sl@0: KErrNone if new string descriptor successfully set. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetConfigurationStringDescriptor(DThread* aThread, const TDes8& aString) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetConfigurationStringDescriptor()")); sl@0: return iDescriptors.SetConfigurationStringDescriptorTC(aThread, aString); sl@0: } sl@0: sl@0: sl@0: /** Removes (deletes) the Configuration string descriptor (which is referenced by the sl@0: iConfiguration field in the configuration descriptor). sl@0: sl@0: @return KErrNone if successful, KErrNotFound if the string descriptor couldn't be found. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::RemoveConfigurationStringDescriptor() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveConfigurationStringDescriptor()")); sl@0: return iDescriptors.RemoveConfigurationStringDescriptor(); sl@0: } sl@0: sl@0: sl@0: /** Copies the string descriptor at the specified index in the string descriptor array into sl@0: the aString argument. sl@0: sl@0: @param aIndex The position of the string descriptor in the string descriptor array. sl@0: @param aThread A pointer to the thread the LDD requesting the string is running in. sl@0: @param aString A reference to a buffer into which the requested string should be written (most likely sl@0: located user-side). sl@0: sl@0: @return KErrNone if successful, KErrNotFound if no string descriptor exists at the specified index, or the sl@0: return value of the thread write operation, Kern::ThreadWrite(), when writing to the target buffer. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::GetStringDescriptor(DThread* aThread, TUint8 aIndex, TDes8& aString) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::GetStringDescriptor(%d)", aIndex)); sl@0: return iDescriptors.GetStringDescriptorTC(aThread, aIndex, aString); sl@0: } sl@0: sl@0: sl@0: /** Sets the aString argument to be a string descriptor at the specified index in the string sl@0: descriptor array. If a string descriptor already exists at that position then it will be replaced. sl@0: sl@0: @param aIndex The position of the string descriptor in the string descriptor array. sl@0: @param aThread A pointer to the thread the LDD requesting the setting of the string is running in. sl@0: @param aString A reference to a buffer which contains the string to be set (most likely located sl@0: user-side). sl@0: sl@0: @return KErrNone if successful, KErrArgument if aIndex is invalid, KErrNoMemory if no memory is available sl@0: to store the new string (an existing descriptor at that index will be preserved), or the return value of sl@0: the thread read operation, Kern::ThreadRead(), if reading from the source buffer goes wrong. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::SetStringDescriptor(DThread* aThread, TUint8 aIndex, const TDes8& aString) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetStringDescriptor(%d)", aIndex)); sl@0: return iDescriptors.SetStringDescriptorTC(aThread, aIndex, aString); sl@0: } sl@0: sl@0: sl@0: /** Removes (deletes) the string descriptor at the specified index in the string descriptor array. sl@0: sl@0: @param aIndex The position of the string descriptor in the string descriptor array. sl@0: sl@0: @return KErrNone if successful, KErrNotFound if no string descriptor exists at the specified index. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::RemoveStringDescriptor(TUint8 aIndex) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RemoveStringDescriptor(%d)", aIndex)); sl@0: return iDescriptors.RemoveStringDescriptor(aIndex); sl@0: } sl@0: sl@0: sl@0: /** Allocates an endpoint resource. sl@0: sl@0: If the resource gets successfully allocated, it will be used from when the current bus transfer sl@0: has been completed. sl@0: sl@0: @param aClientId A pointer to the LDD requesting the endpoint resource. sl@0: @param aEndpointNum The number of the endpoint. sl@0: @param aResource The endpoint resource to be allocated. sl@0: sl@0: @return KErrNone if the resource has been successfully allocated, KErrNotSupported if the endpoint sl@0: does not support the resource requested, and KErrInUse if the resource is already consumed and sl@0: cannot be allocated. KErrArgument if the endpoint number is invalid. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::AllocateEndpointResource(const DBase* /*aClientId*/, TInt aEndpointNum, sl@0: TUsbcEndpointResource aResource) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::AllocateEndpointResource()")); sl@0: return AllocateEndpointResource(aEndpointNum, aResource); sl@0: } sl@0: sl@0: sl@0: /** Deallocates (frees) an endpoint resource. sl@0: sl@0: The resource will be removed from when the current bus transfer has been completed. sl@0: sl@0: @param aClientId A pointer to the LDD requesting the freeing of the endpoint resource. sl@0: @param aEndpointNum The number of the endpoint. sl@0: @param aResource The endpoint resource to be deallocated. sl@0: sl@0: @return KErrNone if the resource has been successfully deallocated, KErrNotSupported if the endpoint sl@0: does not support the resource requested. KErrArgument if the endpoint number is invalid. sl@0: */ sl@0: EXPORT_C TInt DUsbClientController::DeAllocateEndpointResource(const DBase* /*aClientId*/, TInt aEndpointNum, sl@0: TUsbcEndpointResource aResource) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeAllocateEndpointResource()")); sl@0: return DeAllocateEndpointResource(aEndpointNum, aResource); sl@0: } sl@0: sl@0: sl@0: /** Queries the use of and endpoint resource. sl@0: sl@0: If the resource gets successfully allocated, it will be used from when the current bus transfer sl@0: has been completed. sl@0: sl@0: @param aClientId A pointer to the LDD querying the endpoint resource. sl@0: @param aEndpointNum The number of the endpoint. sl@0: @param aResource The endpoint resource to be queried. sl@0: sl@0: @return ETrue if the specified resource is in use at the endpoint, EFalse if not or if there was any error sl@0: during the execution of the function. sl@0: */ sl@0: EXPORT_C TBool DUsbClientController::QueryEndpointResource(const DBase* /*aClientId*/, TInt aEndpointNum, sl@0: TUsbcEndpointResource aResource) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::QueryEndpointResource()")); sl@0: return QueryEndpointResource(aEndpointNum, aResource); sl@0: } sl@0: sl@0: sl@0: EXPORT_C TInt DUsbClientController::EndpointPacketSize(const DBase* aClientId, TInt aEndpointNum) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EndpointPacketSize(0x%08x, %d)", sl@0: aClientId, aEndpointNum)); sl@0: sl@0: const TUsbcInterfaceSet* const ifcset_ptr = ClientId2InterfacePointer(aClientId); sl@0: if (!ifcset_ptr) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface or clientid not found")); sl@0: return -1; sl@0: } sl@0: const TUsbcInterface* const ifc_ptr = ifcset_ptr->iInterfaces[ifcset_ptr->iCurrentInterface]; sl@0: const RPointerArray& ep_array = ifc_ptr->iEndpoints; sl@0: const TInt n = ep_array.Count(); sl@0: for (TInt i = 0; i < n; i++) sl@0: { sl@0: const TUsbcLogicalEndpoint* const ep = ep_array[i]; sl@0: if (EpAddr2Idx(ep->iPEndpoint->iEndpointAddr) == static_cast(aEndpointNum)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Endpoint packet sizes: FS = %d HS = %d", sl@0: ep->iEpSize_Fs, ep->iEpSize_Hs)); sl@0: const TInt size = iHighSpeed ? ep->iEpSize_Hs : ep->iEpSize_Fs; sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Returning %d", size)); sl@0: return size; sl@0: } sl@0: } sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: endpoint not found")); sl@0: return -1; sl@0: } sl@0: sl@0: sl@0: // sl@0: // === USB Controller member function implementations - LDD API (public) =========================== sl@0: // sl@0: sl@0: EXPORT_C TBool DUsbClientController::CurrentlyUsingHighSpeed() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CurrentlyUsingHighSpeed()")); sl@0: return EFalse; sl@0: } sl@0: sl@0: sl@0: // sl@0: // === USB Controller member function implementations - PSL API (public) =========================== sl@0: // sl@0: sl@0: /** Gets called by the PSL to register a newly created derived class controller object. sl@0: sl@0: @param aUdc The number of the new UDC. It should be 0 for the first (or only) UDC in the system, 1 for the sl@0: second one, and so forth. KUsbcMaxUdcs determines how many UDCs are supported. sl@0: sl@0: @return A pointer to the controller if successfully registered, NULL if aUdc out of (static) range. sl@0: sl@0: @publishedPartner @released sl@0: */ sl@0: DUsbClientController* DUsbClientController::RegisterUdc(TInt aUdc) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RegisterUdc()")); sl@0: if (aUdc < 0 || aUdc > (KUsbcMaxUdcs - 1)) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aUdc out of range (%d)", aUdc)); sl@0: return NULL; sl@0: } sl@0: return UsbClientController[aUdc] = this; sl@0: } sl@0: sl@0: sl@0: // sl@0: // === USB Controller member function implementations - PSL API (protected) ======================== sl@0: // sl@0: sl@0: /** Initialises an instance of this class, which is the base class of the derived class (= PSL, which is sl@0: supposed to call this function). sl@0: sl@0: It does the following things: sl@0: sl@0: - disconnects the UDC from the bus, sl@0: - initialises the USB descriptor pool, uses data from the PSL (see function argument list) sl@0: - creates and initialises the basic USB device configuration sl@0: - initialises the array of physical endpoints sl@0: - initialises Ep0 structures (but doesn't configure & enable Ep0 yet) sl@0: - creates and installs the USB power handler sl@0: sl@0: @param aDeviceDesc A pointer to a valid standard USB device descriptor or NULL. The values initially sl@0: required in the descriptor follow from its constructor. The descriptor is not copied over, but rather this sl@0: pointer is queued directly into the descriptor pool. Must be writable memory. sl@0: sl@0: @param aConfigDesc A pointer to a valid standard USB configuration descriptor or NULL. The values sl@0: initially required in the descriptor follow from its constructor. The descriptor is not copied over, but sl@0: rather this pointer is queued directly into the descriptor pool. Must be writable memory. sl@0: sl@0: @param aLangId A pointer to a valid USB language ID (string) descriptor. The values initially required in sl@0: the descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is sl@0: queued directly into the descriptor pool. Must be writable memory. Other than the remaining four string sl@0: descriptors, this one is not optional. The reason is that the USB spec mandates a LangId descriptor as sl@0: soon as a single string descriptor gets returned by the device. So, even though the device might omit the sl@0: Manufacturer, Product, SerialNumber, and Configuration string descriptors, it is at this point not known sl@0: whether there will be any Interface string descriptors. Since any USB API user can create an interface sl@0: with an Interface string descriptor, we have to insist here on the provision of a LangId string sl@0: descriptor. (The PIL decides at run-time whether or not to return the LangId string descriptor to the sl@0: host, depending on whether there exist any string descriptors at that time.) sl@0: sl@0: @param aManufacturer A pointer to a valid USB string descriptor or NULL. The values initially required in sl@0: the descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is sl@0: queued directly into the descriptor pool. Must be writable memory. This descriptor will be referenced by sl@0: the iManufacturer field in the device descriptor. sl@0: sl@0: @param aProduct A pointer to a valid USB string descriptor or NULL. The values initially required in the sl@0: descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is sl@0: queued directly into the descriptor pool. Must be writable memory. This descriptor will be referenced by sl@0: the iProduct field in the device descriptor. sl@0: sl@0: @param aSerialNum A pointer to a valid USB string descriptor or NULL. The values initially required in the sl@0: descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is sl@0: queued directly into the descriptor pool. Must be writable memory. This descriptor will be referenced by sl@0: the iSerialNumber field in the device descriptor. sl@0: sl@0: @param aConfig A pointer to a valid USB string descriptor or NULL. The values initially required in the sl@0: descriptor follow from its constructor. The descriptor is not copied over, but rather this pointer is sl@0: queued directly into the descriptor pool. Must be writable memory. This descriptor will be referenced by sl@0: the iConfiguration field in the configuration descriptor. sl@0: sl@0: @param aOtgDesc A pointer to a valid USB OTG descriptor (if OTG is supported by this device and is to be sl@0: supported by the driver) or NULL. The values initially required in the descriptor follow from its sl@0: constructor. The descriptor is not copied over, but rather this pointer is queued directly into the sl@0: descriptor pool. Must be writable memory. sl@0: sl@0: @return EFalse, if USB descriptor pool initialisation fails, or if configuration creation fails, or if the sl@0: PSL reports more endpoints than the constant KUsbcMaxEndpoints permits, or if the Ep0 logical endpoint sl@0: creation fails, or if the creation of the power handler fails; ETrue, if base class object successfully sl@0: initialised. sl@0: sl@0: @publishedPartner @released sl@0: */ sl@0: TBool DUsbClientController::InitialiseBaseClass(TUsbcDeviceDescriptor* aDeviceDesc, sl@0: TUsbcConfigDescriptor* aConfigDesc, sl@0: TUsbcLangIdDescriptor* aLangId, sl@0: TUsbcStringDescriptor* aManufacturer, sl@0: TUsbcStringDescriptor* aProduct, sl@0: TUsbcStringDescriptor* aSerialNum, sl@0: TUsbcStringDescriptor* aConfig, sl@0: TUsbcOtgDescriptor* aOtgDesc) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::InitialiseBaseClass()")); sl@0: // We don't want the host to see us (at least not yet): sl@0: UsbDisconnect(); sl@0: sl@0: // Initialise USB descriptor pool sl@0: if (iDescriptors.Init(aDeviceDesc, aConfigDesc, aLangId, aManufacturer, aProduct, sl@0: aSerialNum, aConfig, aOtgDesc) != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Error: Descriptor initialization failed")); sl@0: return EFalse; sl@0: } sl@0: sl@0: if (aOtgDesc) sl@0: { sl@0: iOtgSupport = ETrue; sl@0: iOtgFuncMap = aOtgDesc->DescriptorData()[2]; sl@0: // We're only interested in the following capability if this is sl@0: // actually an OTG device. sl@0: iOtgHnpHandledByHw = DeviceHnpHandledByHardwareCaps(); sl@0: } sl@0: sl@0: // Some member variables sl@0: iSelfPowered = aConfigDesc->Byte(7) & (1 << 6); // Byte 7: bmAttributes sl@0: iRemoteWakeup = aConfigDesc->Byte(7) & (1 << 5); sl@0: iRmWakeupStatus_Enabled = EFalse; // default sl@0: sl@0: if (DeviceHighSpeedCaps()) sl@0: { sl@0: if (iDescriptors.InitHs() != KErrNone) sl@0: { sl@0: return EFalse; sl@0: } sl@0: } sl@0: sl@0: // Create and initialise our first (and only) configuration sl@0: TUsbcConfiguration* config = new TUsbcConfiguration(1); sl@0: if (!config) sl@0: { sl@0: return EFalse; sl@0: } sl@0: iConfigs.Append(config); sl@0: sl@0: // Some variable initializations (needed here because of the goto's) sl@0: const TUsbcEndpointCaps* caps = NULL; sl@0: TUsbcEndpointInfo info(KUsbEpTypeControl, KUsbEpDirOut, 0); sl@0: TUsbcLogicalEndpoint* ep = NULL; sl@0: sl@0: // Initialise the array of physical endpoints sl@0: iDeviceTotalEndpoints = DeviceTotalEndpoints(); sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" DeviceTotalEndpoints: %d", iDeviceTotalEndpoints)); sl@0: // KUsbcMaxEndpoints doesn't include ep 0 sl@0: if ((iDeviceTotalEndpoints > (KUsbcMaxEndpoints + 2)) || sl@0: ((iDeviceTotalEndpoints * sizeof(TUsbcPhysicalEndpoint)) > sizeof(iRealEndpoints))) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: too many endpoints! (change KUsbcMaxEndpoints: %d)", sl@0: KUsbcMaxEndpoints)); sl@0: goto exit_1; sl@0: } sl@0: caps = DeviceEndpointCaps(); sl@0: for (TInt i = 0; i < iDeviceTotalEndpoints; ++i) sl@0: { sl@0: iRealEndpoints[i].iEndpointAddr = EpIdx2Addr(i); sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Caps[%02d] - iTypes: 0x%08x iSizes: 0x%08x", sl@0: i, caps[i].iTypesAndDir, caps[i].iSizes)); sl@0: iRealEndpoints[i].iCaps = caps[i]; sl@0: iRealEndpoints[i].iCaps.iReserved[0] = 0; sl@0: iRealEndpoints[i].iCaps.iReserved[1] = 0; sl@0: if ((i > 1) && (caps[i].iTypesAndDir != KUsbEpNotAvailable)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" --> UsableEndpoint: #%d", i)); sl@0: iDeviceUsableEndpoints++; sl@0: } sl@0: } sl@0: sl@0: // Initialise Ep0 structures (logical endpoints are numbered 1..KMaxEndpointsPerClient, sl@0: // and virtual 0 is real 0): sl@0: // -- Ep0 OUT sl@0: iEp0MaxPacketSize = caps[0].MaxPacketSize(); sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" using Ep0 maxpacketsize of %d bytes", iEp0MaxPacketSize)); sl@0: info.iSize = iEp0MaxPacketSize; sl@0: ep = new TUsbcLogicalEndpoint(this, 0, info, NULL, &iRealEndpoints[KEp0_Out]); sl@0: if (!ep) sl@0: { sl@0: goto exit_1; sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" creating ep: mapping real ep %d --> logical ep 0", KEp0_Out)); sl@0: iRealEndpoints[KEp0_Out].iLEndpoint = ep; sl@0: // -- Ep0 IN sl@0: info.iDir = KUsbEpDirIn; sl@0: ep = new TUsbcLogicalEndpoint(this, 0, info, NULL, &iRealEndpoints[KEp0_In]); sl@0: if (!ep) sl@0: { sl@0: goto exit_2; sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" creating ep: mapping real ep %d --> logical ep 0", KEp0_In)); sl@0: iRealEndpoints[KEp0_In].iLEndpoint = ep; sl@0: sl@0: // Create the power handler sl@0: iPowerHandler = new DUsbcPowerHandler(this); sl@0: if (!iPowerHandler) sl@0: { sl@0: goto exit_3; sl@0: } sl@0: iPowerHandler->Add(); sl@0: sl@0: // Misc stuff sl@0: iTrackDeviceState = DeviceStateChangeCaps(); sl@0: if (!iTrackDeviceState) sl@0: { sl@0: // There shouldn't really be any PSL that doesn't support Device State sl@0: // tracking, but we cannot simply enforce it as we have to preserve sl@0: // backwards compatibility. sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Warning: USB Device State tracking not supported by PSL")); sl@0: } sl@0: sl@0: return ETrue; sl@0: sl@0: exit_3: sl@0: delete iRealEndpoints[KEp0_In].iLEndpoint; sl@0: exit_2: sl@0: delete iRealEndpoints[KEp0_Out].iLEndpoint; sl@0: exit_1: sl@0: iConfigs.ResetAndDestroy(); sl@0: sl@0: return EFalse; sl@0: } sl@0: sl@0: sl@0: /** The standard constructor for this class. sl@0: sl@0: @publishedPartner @released sl@0: */ sl@0: DUsbClientController::DUsbClientController() sl@0: : iEp0ReceivedNonStdRequest(EFalse), sl@0: iRmWakeupStatus_Enabled(EFalse), sl@0: iEp0_RxBuf(), sl@0: iDeviceTotalEndpoints(0), sl@0: iDeviceUsableEndpoints(0), sl@0: iDeviceState(EUsbcDeviceStateUndefined), sl@0: iDeviceStateB4Suspend(EUsbcDeviceStateUndefined), sl@0: iSelfPowered(EFalse), sl@0: iRemoteWakeup(EFalse), sl@0: iTrackDeviceState(EFalse), sl@0: iHardwareActivated(EFalse), sl@0: iOtgSupport(EFalse), sl@0: iOtgHnpHandledByHw(EFalse), sl@0: iOtgFuncMap(0), sl@0: iHighSpeed(EFalse), sl@0: iSetup(), sl@0: iEp0MaxPacketSize(0), sl@0: iEp0ClientId(NULL), sl@0: iEp0DataReceived(0), sl@0: iEp0DataReceiving(EFalse), sl@0: iEp0WritePending(EFalse), sl@0: iEp0ClientDataTransmitting(EFalse), sl@0: iEp0DeviceControl(NULL), sl@0: iDescriptors(iEp0_TxBuf), sl@0: iCurrentConfig(0), sl@0: iConfigs(1), sl@0: iRealEndpoints(), sl@0: iEp0_TxBuf(), sl@0: iEp0_RxExtraCount(0), sl@0: iEp0_RxExtraData(EFalse), sl@0: iEp0_TxNonStdCount(0), sl@0: iEp0ReadRequestCallbacks(_FOFF(TUsbcRequestCallback, iLink)), sl@0: iClientCallbacks(_FOFF(TUsbcClientCallback, iLink)), sl@0: iStatusCallbacks(_FOFF(TUsbcStatusCallback, iLink)), sl@0: iEpStatusCallbacks(_FOFF(TUsbcEndpointStatusCallback, iLink)), sl@0: iOtgCallbacks(_FOFF(TUsbcOtgFeatureCallback, iLink)), sl@0: iReconnectTimer(ReconnectTimerCallback, this), sl@0: iCableStatusTimer(CableStatusTimerCallback, this), sl@0: iPowerUpDfc(PowerUpDfc, this, 3), sl@0: iPowerDownDfc(PowerDownDfc, this, 3), sl@0: iStandby(EFalse), sl@0: #ifdef USB_OTG_CLIENT sl@0: // In the OTG case the device starts out disabled sl@0: iStackIsActive(EFalse), sl@0: #else sl@0: iStackIsActive(ETrue), sl@0: #endif // USB_OTG_CLIENT sl@0: iOtgClientConnect(EFalse), sl@0: iClientSupportReady(EFalse), sl@0: iDPlusEnabled(EFalse), sl@0: iUsbResetDeferred(EFalse), sl@0: iEnablePullUpOnDPlus(NULL), sl@0: iDisablePullUpOnDPlus(NULL), sl@0: iOtgContext(NULL) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DUsbClientController()")); sl@0: sl@0: #ifndef SEPARATE_USB_DFC_QUEUE sl@0: iPowerUpDfc.SetDfcQ(Kern::DfcQue0()); sl@0: iPowerDownDfc.SetDfcQ(Kern::DfcQue0()); sl@0: #endif // SEPARATE_USB_DFC_QUEUE sl@0: sl@0: for (TInt i = 0; i < KUsbcEpArraySize; i++) sl@0: iRequestCallbacks[i] = NULL; sl@0: } sl@0: sl@0: sl@0: /** This function gets called by the PSL upon detection of either of the following events: sl@0: - USB Reset, sl@0: - USB Suspend event, sl@0: - USB Resume signalling, sl@0: - The USB cable has been attached (inserted) or detached (removed). sl@0: sl@0: @param anEvent An enum denoting the event that has occured. sl@0: sl@0: @return KErrArgument if the event is not recognized, otherwise KErrNone. sl@0: sl@0: @publishedPartner @released sl@0: */ sl@0: TInt DUsbClientController::DeviceEventNotification(TUsbcDeviceEvent anEvent) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeviceEventNotification()")); sl@0: sl@0: // This function may be called by the PSL from within an ISR -- so we have sl@0: // to take care what we do here (and also in all functions that get called sl@0: // from here). sl@0: sl@0: switch (anEvent) sl@0: { sl@0: case EUsbEventSuspend: sl@0: return ProcessSuspendEvent(); sl@0: case EUsbEventResume: sl@0: return ProcessResumeEvent(); sl@0: case EUsbEventReset: sl@0: return ProcessResetEvent(); sl@0: case EUsbEventCableInserted: sl@0: return ProcessCableInsertEvent(); sl@0: case EUsbEventCableRemoved: sl@0: return ProcessCableRemoveEvent(); sl@0: } sl@0: return KErrArgument; sl@0: } sl@0: sl@0: sl@0: /** This function gets called by the PSL upon completion of a pending data transfer request. sl@0: sl@0: This function is not to be used for endpoint zero completions (use Ep0RequestComplete instead). sl@0: sl@0: @param aCallback A pointer to a data transfer request callback structure which was previously passed to sl@0: the PSL in a SetupReadBuffer() or SetupWriteBuffer() call. sl@0: sl@0: @publishedPartner @released sl@0: */ sl@0: void DUsbClientController::EndpointRequestComplete(TUsbcRequestCallback* aCallback) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EndpointRequestComplete(%p)", aCallback)); sl@0: sl@0: // This function may be called by the PSL from within an ISR -- so we have sl@0: // to take care what we do here (and also in all functions that get called sl@0: // from here). sl@0: sl@0: // We don't test aCallback for NULL here (and therefore risk a crash) sl@0: // because the PSL should never give us a NULL argument. If it does it sl@0: // means the PSL is buggy and ought to be fixed. sl@0: ProcessDataTransferDone(*aCallback); sl@0: } sl@0: sl@0: sl@0: /** This function should be called by the PSL after reception of an Ep0 sl@0: SET_FEATURE request with a feature selector of either {b_hnp_enable, sl@0: a_hnp_support, a_alt_hnp_support}, but only when that Setup packet is not sl@0: handed up to the PIL (for instance because it is auto-decoded and sl@0: 'swallowed' by the UDC hardware). sl@0: sl@0: @param aHnpState A bitmask indicating the present state of the three OTG sl@0: feature selectors as follows: sl@0: sl@0: bit.0 == a_alt_hnp_support sl@0: bit.1 == a_hnp_support sl@0: bit.2 == b_hnp_enable sl@0: sl@0: @see DUsbClientController::ProcessSetClearDevFeature() sl@0: sl@0: @publishedPartner @released sl@0: */ sl@0: void DUsbClientController::HandleHnpRequest(TInt aHnpState) sl@0: // This function is called by the PSL from within an ISR -- so we have to take care what we do here sl@0: // (and also in all functions that get called from here). sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::HandleHnpRequest(%d)", aHnpState)); sl@0: sl@0: if (!iOtgSupport) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only supported on a OTG device")); sl@0: return; sl@0: } sl@0: if (!(iOtgFuncMap & KUsbOtgAttr_HnpSupp)) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only valid if OTG device supports HNP")); sl@0: return; sl@0: } sl@0: // (case KUsbFeature_B_HnpEnable:) sl@0: if (aHnpState & 0x04) sl@0: { sl@0: iOtgFuncMap |= KUsbOtgAttr_B_HnpEnable; sl@0: } sl@0: // (case KUsbFeature_A_HnpSupport:) sl@0: if (aHnpState & 0x02) sl@0: { sl@0: iOtgFuncMap |= KUsbOtgAttr_A_HnpSupport; sl@0: } sl@0: // (case KUsbFeature_A_AltHnpSupport:) sl@0: if (aHnpState & 0x01) sl@0: { sl@0: iOtgFuncMap |= KUsbOtgAttr_A_AltHnpSupport; sl@0: } sl@0: OtgFeaturesNotify(); sl@0: } sl@0: sl@0: sl@0: /** This function gets called by the PSL upon completion of a pending endpoint zero data transfer request. sl@0: sl@0: @param aRealEndpoint Either 0 for Ep0 OUT (= Read), or 1 for Ep0 IN (= Write). sl@0: @param aCount The number of bytes received or transmitted, respectively. sl@0: @param aError The error status of the completed transfer request. Can be KErrNone if no error, KErrCancel sl@0: if transfer was cancelled, or KErrPrematureEnd if a premature status end was encountered. sl@0: sl@0: @return KErrNone if no error during transfer completion processing, KErrGeneral if the request was a read & sl@0: a Setup packet was received & the recipient for that packet couldn't be found (invalid packet: Ep0 has been sl@0: stalled), KErrNotFound if the request was a read & the recipient for that packet (Setup or data) _was_ sl@0: found - however no read had been set up by that recipient (this case should be used by the PSL to disable sl@0: the Ep0 interrupt at that point and give the LDD time to set up a new Ep0 read; once the 'missing' read sl@0: was set up either Ep0ReceiveProceed or Ep0ReadSetupPktProceed will be called by the PIL). sl@0: sl@0: @publishedPartner @released sl@0: */ sl@0: TInt DUsbClientController::Ep0RequestComplete(TInt aRealEndpoint, TInt aCount, TInt aError) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::Ep0RequestComplete(%d)", aRealEndpoint)); sl@0: sl@0: // This function may be called by the PSL from within an ISR -- so we have sl@0: // to take care what we do here (and also in all functions that get called sl@0: // from here). sl@0: sl@0: __ASSERT_DEBUG((aRealEndpoint < 2), Kern::Fault(KUsbPILPanicCat, __LINE__)); sl@0: if (aError != KErrNone && aError != KErrPrematureEnd) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Error: Ep0 request failed (code %d). " sl@0: "Setting up new Read request.", aError)); sl@0: if (aRealEndpoint == KEp0_Rx) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" (RX request failed)")); sl@0: StallEndpoint(KEp0_Out); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" (TX request failed)")); sl@0: iEp0WritePending = EFalse; sl@0: StallEndpoint(KEp0_In); sl@0: } sl@0: // our only remedy: set up a new read request sl@0: SetupEndpointZeroRead(); sl@0: return KErrNone; sl@0: } sl@0: TInt r; sl@0: if (aRealEndpoint & 0x01) sl@0: { sl@0: r = ProcessEp0TransmitDone(aCount, aError); sl@0: } sl@0: else sl@0: { sl@0: r = ProcessEp0ReceiveDone(aCount); sl@0: if (r == KErrNotFound) sl@0: { sl@0: // Don't set up new read yet if data weren't delivered. sl@0: // (The PSL is supposed, upon encountering this return value, sl@0: // to turn off Ep0's interrupt.) sl@0: return r; sl@0: } sl@0: } sl@0: if (iEp0WritePending == EFalse) sl@0: { sl@0: // we're done & no write request has been set up. sl@0: // so: setup an Ep0 read again sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Setting up new Ep0 read request.")); sl@0: SetupEndpointZeroRead(); sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: /** This function should be called by the PSL once the UDC (and thus the USB device) is in the Address state. sl@0: sl@0: @publishedPartner @released sl@0: */ sl@0: void DUsbClientController::MoveToAddressState() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::MoveToAddressState()")); sl@0: sl@0: // This function may be called by the PSL from within an ISR -- so we have sl@0: // to take care what we do here (and also in all functions that get called sl@0: // from here). sl@0: sl@0: NextDeviceState(EUsbcDeviceStateAddress); sl@0: } sl@0: sl@0: sl@0: /** This function should be called by the PSL before certain UDC operations to inform the power model about sl@0: the electrical current requirements. sl@0: sl@0: (The exact use of this function is currently not quite clear, so not calling it probably won't harm.) sl@0: sl@0: @param aCurrent The required electrical current. sl@0: sl@0: @publishedPartner @released sl@0: */ sl@0: void DUsbClientController::SetCurrent(TInt aCurrent) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetCurrent(%d)", aCurrent)); sl@0: sl@0: // Not much for the moment... (What should we do here?) sl@0: return; sl@0: } sl@0: sl@0: sl@0: // sl@0: // === Platform Specific Layer (PSL) - private/virtual ============================================= sl@0: // sl@0: sl@0: TInt DUsbClientController::OpenDmaChannel(TInt aRealEndpoint) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::OpenDmaChannel(%d)", aRealEndpoint)); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::CloseDmaChannel(TInt aRealEndpoint) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CloseDmaChannel(%d)", aRealEndpoint)); sl@0: } sl@0: sl@0: sl@0: TBool DUsbClientController::CableDetectWithoutPowerCaps() const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CableDetectWithoutPowerCaps()")); sl@0: // Should be overridden in PSL if applicable. sl@0: return EFalse; sl@0: } sl@0: sl@0: sl@0: TBool DUsbClientController::DeviceHighSpeedCaps() const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeviceHighSpeedCaps()")); sl@0: // Should be overridden in PSL if applicable. sl@0: return EFalse; sl@0: } sl@0: sl@0: sl@0: TBool DUsbClientController::DeviceResourceAllocV2Caps() const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeviceResourceAllocV2Caps()")); sl@0: // Should be overridden in PSL if applicable. sl@0: return EFalse; sl@0: } sl@0: sl@0: sl@0: TBool DUsbClientController::DeviceHnpHandledByHardwareCaps() const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeviceHnpHandledByHardwareCaps()")); sl@0: // Should be overridden in PSL if applicable. sl@0: return EFalse; sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::EnterTestMode(TInt aTestSelector) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EnterTestMode(%d)", aTestSelector)); sl@0: // Should be overridden in PSL if applicable. sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: sl@0: TBool DUsbClientController::PowerDownWhenActive() const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::PowerDownWhenActive()")); sl@0: return EFalse; sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::PowerDown() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::PowerDown()")); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::PowerUp() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::PowerUp()")); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::OtgEnableUdc() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::OtgEnableUdc()")); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::OtgDisableUdc() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::OtgDisableUdc()")); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: // sl@0: // === USB Controller member function implementations - Internal utility functions (private) ======= sl@0: // sl@0: sl@0: TInt DUsbClientController::DeRegisterClientCallback(const DBase* aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeRegisterClientCallback()")); sl@0: __ASSERT_DEBUG((aClientId != NULL), Kern::Fault(KUsbPILPanicCat, __LINE__)); sl@0: TSglQueIter iter(iClientCallbacks); sl@0: TUsbcClientCallback* p; sl@0: while ((p = iter++) != NULL) sl@0: if (p->Owner() == aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" removing ClientCallback @ 0x%x", p)); sl@0: iClientCallbacks.Remove(*p); sl@0: return KErrNone; sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Client not found")); sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: sl@0: TBool DUsbClientController::CheckEpAvailability(TInt aEndpointsUsed, sl@0: const TUsbcEndpointInfoArray& aEndpointData, sl@0: TInt aIfcNumber) const sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CheckEpAvailability()")); sl@0: if (aEndpointsUsed > KMaxEndpointsPerClient) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: too many endpoints claimed (%d)", aEndpointsUsed)); sl@0: return EFalse; sl@0: } sl@0: TBool reserve[KUsbcEpArraySize]; // iDeviceTotalEndpoints can be equal to 32 sl@0: memset(reserve, EFalse, sizeof(reserve)); // reset the array sl@0: for (TInt i = 0; i < aEndpointsUsed; ++i) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" checking for (user) endpoint #%d availability...", i + 1)); sl@0: TInt j = 2; sl@0: while (j < iDeviceTotalEndpoints) sl@0: { sl@0: if ((iRealEndpoints[j].EndpointSuitable(&aEndpointData[i], aIfcNumber)) && sl@0: (reserve[j] == EFalse)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" ---> found suitable endpoint: RealEndpoint #%d", j)); sl@0: reserve[j] = ETrue; // found one: mark this ep as reserved sl@0: break; sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" -> endpoint not suitable: RealEndpoint #%d", j)); sl@0: j++; sl@0: } sl@0: if (j == iDeviceTotalEndpoints) sl@0: { sl@0: return EFalse; sl@0: } sl@0: } sl@0: return ETrue; sl@0: } sl@0: sl@0: sl@0: TUsbcInterface* DUsbClientController::CreateInterface(const DBase* aClientId, TInt aIfc, TUint32 aFeatureWord) sl@0: // We know that 9.2.3 says: "Interfaces are numbered from zero to one less than the number of sl@0: // concurrent interfaces supported by the configuration." But since we permit the user to sl@0: // change interface numbers, we can neither assume nor enforce anything about them here. sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CreateInterface(x, aIfc=%d)", aIfc)); sl@0: TUsbcInterfaceSet* ifcset_ptr = NULL; sl@0: TInt ifcset = ClientId2InterfaceNumber(aClientId); sl@0: TBool new_ifc; sl@0: if (ifcset < 0) sl@0: { sl@0: // New interface(set), so we need to find a number for it. sl@0: new_ifc = ETrue; sl@0: const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); sl@0: if (num_ifcsets == 255) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Too many interfaces already exist: 255")); sl@0: return NULL; sl@0: } sl@0: // Find the smallest interface number that has not yet been used. sl@0: for (ifcset = 0; ifcset < 256; ++ifcset) sl@0: { sl@0: TBool n_used = EFalse; sl@0: for (TInt i = 0; i < num_ifcsets; ++i) sl@0: { sl@0: if ((iConfigs[0]->iInterfaceSets[i]->iInterfaceNumber) == ifcset) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" interface number %d already used", ifcset)); sl@0: n_used = ETrue; sl@0: break; sl@0: } sl@0: } sl@0: if (!n_used) sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: if (ifcset == 256) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no available interface number found")); sl@0: return NULL; sl@0: } sl@0: // append the ifcset sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" creating new InterfaceSet %d first", ifcset)); sl@0: if (aIfc != 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface setting number (1): %d", aIfc)); sl@0: return NULL; sl@0: } sl@0: if ((ifcset_ptr = new TUsbcInterfaceSet(aClientId, ifcset)) == NULL) sl@0: { sl@0: __KTRACE_OPT(KPANIC, sl@0: Kern::Printf(" Error: new TUsbcInterfaceSet(aClientId, ifcset_num) failed")); sl@0: return NULL; sl@0: } sl@0: iConfigs[0]->iInterfaceSets.Append(ifcset_ptr); sl@0: } sl@0: else /* if (ifcset_num >= 0) */ sl@0: { sl@0: // use an existent ifcset sl@0: new_ifc = EFalse; sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" using existing InterfaceSet %d", ifcset)); sl@0: ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); sl@0: if (aIfc != ifcset_ptr->iInterfaces.Count()) sl@0: { sl@0: // 9.2.3: "Alternate settings range from zero to one less than the number of alternate sl@0: // settings for a specific interface." (Thus we can here only append a setting.) sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface setting number (2): %d", aIfc)); sl@0: return NULL; sl@0: } sl@0: // Check whether the existing interface belongs indeed to this client sl@0: if (ifcset_ptr->iClientId != aClientId) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: iClientId (%p) != aClientId (%p)", sl@0: ifcset_ptr->iClientId, aClientId)); sl@0: return NULL; sl@0: } sl@0: } sl@0: const TBool no_ep0_requests = aFeatureWord & KUsbcInterfaceInfo_NoEp0RequestsPlease; sl@0: TUsbcInterface* const ifc_ptr = new TUsbcInterface(ifcset_ptr, aIfc, no_ep0_requests); sl@0: if (!ifc_ptr) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: new TUsbcInterface(ifcset, aIfc) failed")); sl@0: if (new_ifc) sl@0: { sl@0: DeleteInterfaceSet(ifcset); sl@0: } sl@0: return NULL; sl@0: } sl@0: ifcset_ptr->iInterfaces.Append(ifc_ptr); sl@0: return ifc_ptr; sl@0: } sl@0: sl@0: sl@0: #define RESET_SETTINGRESERVE \ sl@0: for (TInt i = start_ep; i < iDeviceTotalEndpoints; i++) \ sl@0: { \ sl@0: if (iRealEndpoints[i].iSettingReserve) \ sl@0: iRealEndpoints[i].iSettingReserve = EFalse; \ sl@0: } \ sl@0: sl@0: TInt DUsbClientController::CreateEndpoints(TUsbcInterface* aIfc, TInt aEndpointsUsed, sl@0: const TUsbcEndpointInfoArray& aEndpointData, sl@0: TInt aRealEpNumbers[]) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CreateEndpoints()")); sl@0: const TInt ifc_num = aIfc->iInterfaceSet->iInterfaceNumber; sl@0: const TInt start_ep = 2; sl@0: for (TInt i = 0; i < aEndpointsUsed; ++i) sl@0: { sl@0: for (TInt j = start_ep; j < iDeviceTotalEndpoints; ++j) sl@0: { sl@0: if (iRealEndpoints[j].EndpointSuitable(&aEndpointData[i], ifc_num)) sl@0: { sl@0: // Logical endpoints are numbered 1..KMaxEndpointsPerClient (virtual 0 is real 0 and 1) sl@0: TUsbcLogicalEndpoint* const ep = new TUsbcLogicalEndpoint(this, i + 1, aEndpointData[i], sl@0: aIfc, &iRealEndpoints[j]); sl@0: if (!ep) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: new TUsbcLogicalEndpoint() failed")); sl@0: aIfc->iEndpoints.ResetAndDestroy(); sl@0: RESET_SETTINGRESERVE; sl@0: return KErrNoMemory; sl@0: } sl@0: aIfc->iEndpoints.Append(ep); sl@0: // Check on logical endpoint's sizes for compliance with special restrictions. sl@0: if (aIfc->iSettingCode == 0) sl@0: { sl@0: // For details see last paragraph of 5.7.3 "Interrupt Transfer Packet Size Constraints". sl@0: if ((ep->iInfo.iType == KUsbEpTypeInterrupt) && (ep->iEpSize_Hs > 64)) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: INT ep HS size = %d on default ifc setting", sl@0: ep->iEpSize_Hs)); sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" (should be <= 64)")); sl@0: } sl@0: // For details see last paragraph of 5.6.3 "Isochronous Transfer Packet Size Constraints". sl@0: else if ((ep->iInfo.iType == KUsbEpTypeIsochronous) && (ep->iInfo.iSize > 0)) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: ISO ep size = %d on default ifc setting", sl@0: ep->iInfo.iSize)); sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" (should be zero or ep non-existent)")); sl@0: } sl@0: } sl@0: // If the endpoint doesn't support DMA (now or never) the next operation sl@0: // will be a successful no-op. sl@0: const TInt r = OpenDmaChannel(j); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Opening of DMA channel failed")); sl@0: aIfc->iEndpoints.ResetAndDestroy(); sl@0: RESET_SETTINGRESERVE; sl@0: return r; sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" creating ep: mapping real ep %d -> logical ep %d", sl@0: j, i + 1)); sl@0: iRealEndpoints[j].iIfcNumber = &aIfc->iInterfaceSet->iInterfaceNumber; sl@0: iRealEndpoints[j].iSettingReserve = ETrue; sl@0: __KTRACE_OPT(KUSB, sl@0: Kern::Printf(" ep->iInfo: iType=0x%x iDir=0x%x iSize=%d iInterval=%d", sl@0: ep->iInfo.iType, ep->iInfo.iDir, ep->iInfo.iSize, sl@0: ep->iInfo.iInterval)); sl@0: __KTRACE_OPT(KUSB, sl@0: Kern::Printf(" ep->iInfo: iInterval_Hs=%d iTransactions=%d iExtra=%d", sl@0: ep->iInfo.iInterval_Hs, ep->iInfo.iTransactions, sl@0: ep->iInfo.iExtra)); sl@0: // Store real endpoint numbers: sl@0: // array[x] holds the number for logical ep x. sl@0: aRealEpNumbers[i + 1] = j; sl@0: break; sl@0: } sl@0: } sl@0: } sl@0: aRealEpNumbers[0] = 0; // ep0: 0. sl@0: __KTRACE_OPT(KUSB,{ sl@0: Kern::Printf(" Endpoint Mapping for Interface %d / Setting %d:", ifc_num, aIfc->iSettingCode); sl@0: Kern::Printf("Logical | Real"); sl@0: Kern::Printf("Endpoint | Endpoint"); sl@0: for (TInt ep = 0; ep <= aEndpointsUsed; ++ep) Kern::Printf(" %2d %3d",ep, aRealEpNumbers[ep]); sl@0: }); sl@0: RESET_SETTINGRESERVE; sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::SetupIfcDescriptor(TUsbcInterface* aIfc, TUsbcClassInfo& aClass, DThread* aThread, sl@0: TDesC8* aString, const TUsbcEndpointInfoArray& aEndpointData) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetupIfcDescriptor()")); sl@0: sl@0: // Interface descriptor sl@0: TUsbcDescriptorBase* d = TUsbcInterfaceDescriptor::New(aIfc->iInterfaceSet->iInterfaceNumber, sl@0: aIfc->iSettingCode, sl@0: aIfc->iEndpoints.Count(), sl@0: aClass); sl@0: if (!d) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for ifc desc failed.")); sl@0: return KErrNoMemory; sl@0: } sl@0: iDescriptors.InsertDescriptor(d); sl@0: sl@0: // Interface string descriptor sl@0: if (aString) sl@0: { sl@0: // we don't know the length of the string, so we have to allocate memory dynamically sl@0: TUint strlen = Kern::ThreadGetDesLength(aThread, aString); sl@0: if (strlen > KUsbStringDescStringMaxSize) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Warning: $ descriptor too long - string will be truncated")); sl@0: strlen = KUsbStringDescStringMaxSize; sl@0: } sl@0: HBuf8* const stringbuf = HBuf8::New(strlen); sl@0: if (!stringbuf) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for ifc $ desc string failed.")); sl@0: iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, sl@0: aIfc->iSettingCode); sl@0: return KErrNoMemory; sl@0: } sl@0: stringbuf->SetMax(); sl@0: // the aString points to data that lives in user memory, so we have to copy it: sl@0: TInt r = Kern::ThreadDesRead(aThread, aString, *stringbuf, 0); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Thread read error")); sl@0: iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, sl@0: aIfc->iSettingCode); sl@0: delete stringbuf; sl@0: return r; sl@0: } sl@0: TUsbcStringDescriptor* const sd = TUsbcStringDescriptor::New(*stringbuf); sl@0: if (!sd) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for ifc $ desc failed.")); sl@0: iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, sl@0: aIfc->iSettingCode); sl@0: delete stringbuf; sl@0: return KErrNoMemory; sl@0: } sl@0: iDescriptors.SetIfcStringDescriptor(sd, aIfc->iInterfaceSet->iInterfaceNumber, aIfc->iSettingCode); sl@0: delete stringbuf; // the (EPOC) descriptor was copied by New() sl@0: } sl@0: sl@0: // Endpoint descriptors sl@0: for (TInt i = 0; i < aIfc->iEndpoints.Count(); ++i) sl@0: { sl@0: // The reason for using another function argument for Endpoint Info sl@0: // (and not possibly - similar to the Endpoint Address - sl@0: // "aIfc->iEndpoints[i]->iPEndpoint->iLEndpoint->iInfo") is that this time sl@0: // there are no logical endpoints associated with our real endpoints, sl@0: // i.e. iLEndpoint is NULL!. sl@0: if (aEndpointData[i].iExtra) sl@0: { sl@0: // if a non-standard endpoint descriptor is requested... sl@0: if (aEndpointData[i].iExtra != 2) sl@0: { sl@0: // ...then it must be a Audio Class endpoint descriptor. Else... sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: EP desc extension > 2 bytes (%d)", sl@0: aEndpointData[i].iExtra)); sl@0: iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, sl@0: aIfc->iSettingCode); sl@0: return KErrArgument; sl@0: } sl@0: d = TUsbcAudioEndpointDescriptor::New(aIfc->iEndpoints[i]->iPEndpoint->iEndpointAddr, sl@0: aEndpointData[i]); sl@0: } sl@0: else sl@0: { sl@0: d = TUsbcEndpointDescriptor::New(aIfc->iEndpoints[i]->iPEndpoint->iEndpointAddr, sl@0: aEndpointData[i]); sl@0: } sl@0: if (!d) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Memory allocation for ep desc #%d failed.", i)); sl@0: iDescriptors.DeleteIfcDescriptor(aIfc->iInterfaceSet->iInterfaceNumber, sl@0: aIfc->iSettingCode); sl@0: return KErrNoMemory; sl@0: } sl@0: iDescriptors.InsertDescriptor(d); sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::ClientId2InterfaceNumber(const DBase* aClientId) const sl@0: { sl@0: const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); sl@0: for (TInt i = 0; i < num_ifcsets; ++i) sl@0: { sl@0: if (iConfigs[0]->iInterfaceSets[i]->iClientId == aClientId) sl@0: { sl@0: return iConfigs[0]->iInterfaceSets[i]->iInterfaceNumber; sl@0: } sl@0: } sl@0: return -1; sl@0: } sl@0: sl@0: sl@0: TUsbcInterfaceSet* DUsbClientController::ClientId2InterfacePointer(const DBase* aClientId) const sl@0: { sl@0: const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); sl@0: for (TInt i = 0; i < num_ifcsets; ++i) sl@0: { sl@0: if (iConfigs[0]->iInterfaceSets[i]->iClientId == aClientId) sl@0: { sl@0: return iConfigs[0]->iInterfaceSets[i]; sl@0: } sl@0: } sl@0: return NULL; sl@0: } sl@0: sl@0: sl@0: const DBase* DUsbClientController::InterfaceNumber2ClientId(TInt aIfcSet) const sl@0: { sl@0: if (!InterfaceExists(aIfcSet)) sl@0: { sl@0: return NULL; sl@0: } sl@0: return InterfaceNumber2InterfacePointer(aIfcSet)->iClientId; sl@0: } sl@0: sl@0: sl@0: TUsbcInterfaceSet* DUsbClientController::InterfaceNumber2InterfacePointer(TInt aIfcSet) const sl@0: { sl@0: const TInt num_ifcsets = iConfigs[0]->iInterfaceSets.Count(); sl@0: for (TInt i = 0; i < num_ifcsets; ++i) sl@0: { sl@0: if ((iConfigs[0]->iInterfaceSets[i]->iInterfaceNumber) == aIfcSet) sl@0: { sl@0: return iConfigs[0]->iInterfaceSets[i]; sl@0: } sl@0: } sl@0: return NULL; sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::ActivateHardwareController() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ActivateHardwareController()")); sl@0: if (iHardwareActivated) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" already active -> returning")); sl@0: return KErrNone; sl@0: } sl@0: // Initialise HW sl@0: TInt r = StartUdc(); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: StartUdc() failed")); sl@0: return KErrHardwareNotAvailable; sl@0: } sl@0: r = OtgEnableUdc(); // turn on UDC (OTG flavour) sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: OtgEnableUdc() failed: %d", r)); sl@0: } sl@0: iHardwareActivated = ETrue; sl@0: sl@0: // Configure & enable endpoint zero sl@0: const TUsbcLogicalEndpoint* const ep0_0 = iRealEndpoints[0].iLEndpoint; sl@0: const TUsbcLogicalEndpoint* const ep0_1 = iRealEndpoints[1].iLEndpoint; sl@0: if (iHighSpeed) sl@0: { sl@0: const_cast(ep0_0)->iInfo.iSize = ep0_0->iEpSize_Hs; sl@0: const_cast(ep0_1)->iInfo.iSize = ep0_1->iEpSize_Hs; sl@0: } sl@0: else sl@0: { sl@0: const_cast(ep0_0)->iInfo.iSize = ep0_0->iEpSize_Fs; sl@0: const_cast(ep0_1)->iInfo.iSize = ep0_1->iEpSize_Fs; sl@0: } sl@0: ConfigureEndpoint(0, ep0_0->iInfo); sl@0: ConfigureEndpoint(1, ep0_1->iInfo); sl@0: iEp0MaxPacketSize = ep0_0->iInfo.iSize; sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Controller activated.")); sl@0: if (UsbConnectionStatus()) sl@0: { sl@0: if (iDeviceState == EUsbcDeviceStateUndefined) sl@0: { sl@0: NextDeviceState(EUsbcDeviceStateAttached); sl@0: } sl@0: NextDeviceState(EUsbcDeviceStatePowered); sl@0: } sl@0: return KErrNone;; sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::DeActivateHardwareController() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeActivateHardwareController()")); sl@0: if (!iHardwareActivated) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" not active -> returning")); sl@0: return; sl@0: } sl@0: // Deconfigure & disable endpoint zero sl@0: DeConfigureEndpoint(KEp0_Out); sl@0: DeConfigureEndpoint(KEp0_In); sl@0: // Stop HW sl@0: TInt r = OtgDisableUdc(); // turn off UDC (OTG flavour) sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: OtgDisableUdc() failed: %d", r)); sl@0: } sl@0: StopUdc(); sl@0: iHardwareActivated = EFalse; sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Controller deactivated.")); sl@0: if (UsbConnectionStatus()) sl@0: { sl@0: NextDeviceState(EUsbcDeviceStateAttached); sl@0: } sl@0: return; sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::DeleteInterfaceSet(TInt aIfcSet) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeleteInterfaceSet(%d)", aIfcSet)); sl@0: TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(aIfcSet); sl@0: if (!ifcset_ptr) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface number: %d", aIfcSet)); sl@0: return; sl@0: } sl@0: const TInt idx = iConfigs[0]->iInterfaceSets.Find(ifcset_ptr); sl@0: if (idx == KErrNotFound) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: interface not found in array")); sl@0: return; sl@0: } sl@0: iConfigs[0]->iInterfaceSets.Remove(idx); sl@0: delete ifcset_ptr; sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::DeleteInterface(TInt aIfcSet, TInt aIfc) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeleteInterface(%d, %d)", aIfcSet, aIfc)); sl@0: TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(aIfcSet); sl@0: if (!ifcset_ptr) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface number: %d", aIfcSet)); sl@0: return; sl@0: } sl@0: if (ifcset_ptr->iInterfaces.Count() <= aIfc) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid interface setting: %d", aIfc)); sl@0: return; sl@0: } sl@0: TUsbcInterface* const ifc_ptr = ifcset_ptr->iInterfaces[aIfc]; sl@0: // Always first remove, then delete (see ~TUsbcLogicalEndpoint() for the reason why) sl@0: ifcset_ptr->iInterfaces.Remove(aIfc); sl@0: delete ifc_ptr; sl@0: if (aIfc == ifcset_ptr->iCurrentInterface) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" > Warning: deleting current interface setting")); sl@0: ifcset_ptr->iCurrentInterface = 0; sl@0: } sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::CancelTransferRequests(TInt aRealEndpoint) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CancelTransferRequests(aRealEndpoint=%d)", sl@0: aRealEndpoint)); sl@0: const DBase* const clientId = PEndpoint2ClientId(aRealEndpoint); sl@0: if (EpIdx2Addr(aRealEndpoint) & KUsbEpAddress_In) sl@0: { sl@0: CancelWriteBuffer(clientId, aRealEndpoint); sl@0: } sl@0: else sl@0: { sl@0: CancelReadBuffer(clientId, aRealEndpoint); sl@0: } sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::DeleteRequestCallback(const DBase* aClientId, TInt aEndpointNum, sl@0: TTransferDirection aTransferDir) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeleteRequestCallback()")); sl@0: // Ep0 OUT sl@0: if (aEndpointNum == 0) sl@0: { sl@0: const TInt irq = NKern::DisableAllInterrupts(); sl@0: TSglQueIter iter(iEp0ReadRequestCallbacks); sl@0: TUsbcRequestCallback* p; sl@0: while ((p = iter++) != NULL) sl@0: { sl@0: if (p->Owner() == aClientId) sl@0: { sl@0: __ASSERT_DEBUG((p->iRealEpNum == 0), Kern::Fault(KUsbPILPanicCat, __LINE__)); sl@0: __ASSERT_DEBUG((p->iTransferDir == EControllerRead), Kern::Fault(KUsbPILPanicCat, __LINE__)); sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" removing RequestCallback @ 0x%x (ep0)", p)); sl@0: iEp0ReadRequestCallbacks.Remove(*p); sl@0: } sl@0: } sl@0: NKern::RestoreInterrupts(irq); sl@0: return; sl@0: } sl@0: // Other endpoints sl@0: TUsbcRequestCallback* const p = iRequestCallbacks[aEndpointNum]; sl@0: if (p) sl@0: { sl@0: __ASSERT_DEBUG((p->Owner() == aClientId), Kern::Fault(KUsbPILPanicCat, __LINE__)); sl@0: __ASSERT_DEBUG((p->iTransferDir == aTransferDir), Kern::Fault(KUsbPILPanicCat, __LINE__)); sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" removing RequestCallback @ 0x%x", p)); sl@0: iRequestCallbacks[aEndpointNum] = NULL; sl@0: } sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::DeleteRequestCallbacks(const DBase* aClientId) sl@0: { sl@0: // aClientId being NULL means: delete all requests for *all* clients. sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DeleteRequestCallbacks()")); sl@0: // Ep0 OUT sl@0: const TInt irq = NKern::DisableAllInterrupts(); sl@0: TSglQueIter iter(iEp0ReadRequestCallbacks); sl@0: TUsbcRequestCallback* p; sl@0: while ((p = iter++) != NULL) sl@0: { sl@0: if (!aClientId || p->Owner() == aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" removing RequestCallback @ 0x%x (ep0)", p)); sl@0: iEp0ReadRequestCallbacks.Remove(*p); sl@0: } sl@0: } sl@0: NKern::RestoreInterrupts(irq); sl@0: // Other endpoints sl@0: for (TInt i = 1; i < KUsbcEpArraySize; i++) sl@0: { sl@0: TUsbcRequestCallback* const p = iRequestCallbacks[i]; sl@0: if (p && (!aClientId || p->Owner() == aClientId)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" removing RequestCallback @ 0x%x", p)); sl@0: iRequestCallbacks[i] = NULL; sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::StatusNotify(TUsbcDeviceState aState, const DBase* aClientId) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::StatusNotify()")); sl@0: sl@0: // This function may be called by the PSL (via chapter9.cpp) from within an sl@0: // ISR -- so we have to take care what we do here (and also in all sl@0: // functions that get called from here). sl@0: sl@0: TSglQueIter iter(iStatusCallbacks); sl@0: TUsbcStatusCallback* p; sl@0: while ((p = iter++) != NULL) sl@0: { sl@0: if (!aClientId || aClientId == p->Owner()) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" notifying LDD @ 0x%x about %d", p->Owner(), aState)); sl@0: p->SetState(aState); sl@0: p->DoCallback(); sl@0: } sl@0: } sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::EpStatusNotify(TInt aRealEndpoint) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EpStatusNotify()")); sl@0: sl@0: // This function may be called by the PSL (via chapter9.cpp) from within an sl@0: // ISR -- so we have to take care what we do here (and also in all sl@0: // functions that get called from here). sl@0: sl@0: const DBase* const client_id = PEndpoint2ClientId(aRealEndpoint); sl@0: if (!client_id) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Client not found for real ep %d", aRealEndpoint)); sl@0: return; sl@0: } sl@0: // Check if there is a notification request queued for that client (if not, we can return here). sl@0: TSglQueIter iter(iEpStatusCallbacks); sl@0: TUsbcEndpointStatusCallback* p; sl@0: while ((p = iter++) != NULL) sl@0: { sl@0: if (p->Owner() == client_id) sl@0: { sl@0: break; sl@0: } sl@0: } sl@0: if (!p) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" No notification request for that client, returning")); sl@0: return; sl@0: } sl@0: const TInt ifcset = ClientId2InterfaceNumber(client_id); sl@0: if (ifcset < 0) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Ifcset not found for clientid %d", client_id)); sl@0: return; sl@0: } sl@0: const TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(ifcset); sl@0: if (!ifcset_ptr) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Ifcset pointer not found for ifcset %d", ifcset)); sl@0: return; sl@0: } sl@0: const TUsbcInterface* const ifc_ptr = ifcset_ptr->CurrentInterface(); sl@0: if (!ifc_ptr) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Current ifc pointer not found for ifcset %d", ifcset)); sl@0: return; sl@0: } sl@0: TUint state = 0; sl@0: const TInt eps = ifc_ptr->iEndpoints.Count(); sl@0: for (TInt i = 0; i < eps; i++) sl@0: { sl@0: const TUsbcLogicalEndpoint* const ep_ptr = ifc_ptr->iEndpoints[i]; sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" checking logical ep #%d for stall state...", sl@0: ep_ptr->iLEndpointNum)); sl@0: if (ep_ptr->iPEndpoint->iHalt) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" -- stalled")); sl@0: // set the bit n to 1, where n is the logical endpoint number minus one sl@0: state |= (1 << (ep_ptr->iLEndpointNum - 1)); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" -- not stalled")); sl@0: } sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" passing ep state 0x%x on to LDD @ 0x%x", state, client_id)); sl@0: p->SetState(state); sl@0: p->DoCallback(); sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::OtgFeaturesNotify() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::OtgFeaturesNotify()")); sl@0: sl@0: // This function may be called from the PSL (via PIL's chapter9.cpp) from sl@0: // within an ISR -- so we have to take care what we do here (and also in sl@0: // all functions that get called from here). sl@0: sl@0: TSglQueIter iter(iOtgCallbacks); sl@0: TUsbcOtgFeatureCallback* p; sl@0: while ((p = iter++) != NULL) sl@0: { sl@0: p->SetFeatures(iOtgFuncMap & 0x1C); sl@0: p->DoCallback(); sl@0: } sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::RunClientCallbacks() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::RunClientCallbacks()")); sl@0: TSglQueIter iter(iClientCallbacks); sl@0: TUsbcClientCallback* p; sl@0: while ((p = iter++) != NULL) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Callback 0x%x", p)); sl@0: p->DoCallback(); sl@0: } sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::ProcessDataTransferDone(TUsbcRequestCallback& aRcb) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessDataTransferDone()")); sl@0: // This piece can only be called in thread context from ProcessEp0DataReceived() / sl@0: // ProcessEp0SetupReceived() via the call to ProcessEp0ReceiveDone() in sl@0: // SetupReadBuffer(), which is guarded by an interrupt lock. sl@0: TInt ep = aRcb.iRealEpNum; sl@0: if (ep == 0) sl@0: { sl@0: if (aRcb.iTransferDir == EControllerRead) sl@0: { sl@0: // Ep0 OUT is special sl@0: iEp0ReadRequestCallbacks.Remove(aRcb); sl@0: } sl@0: else // EControllerWrite sl@0: { sl@0: // Ep0 IN needs to be adjusted: it's '1' within the PIL. sl@0: ep = KEp0_Tx; sl@0: } sl@0: } sl@0: if (ep > 0) // not 'else'! sl@0: { sl@0: __ASSERT_DEBUG((iRequestCallbacks[ep] == &aRcb), Kern::Fault(KUsbPILPanicCat, __LINE__)); sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" > removing RequestCallback[%d] @ 0x%x", ep, &aRcb)); sl@0: iRequestCallbacks[ep] = NULL; sl@0: } sl@0: aRcb.DoCallback(); sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::NextDeviceState(TUsbcDeviceState aNextState) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::NextDeviceState()")); sl@0: #ifdef _DEBUG sl@0: const char* const states[] = {"Undefined", "Attached", "Powered", "Default", sl@0: "Address", "Configured", "Suspended"}; sl@0: if ((aNextState >= EUsbcDeviceStateUndefined) && sl@0: (aNextState <= EUsbcDeviceStateSuspended)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" next device state: %s", states[aNextState])); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown next device state: %d", aNextState)); sl@0: } sl@0: // Print a warning when an invalid state transition is detected sl@0: // 'Undefined' is not a state that is mentioned in the USB spec, but sl@0: // that's what we're in once the cable gets pulled (for instance). sl@0: switch (iDeviceState) sl@0: { sl@0: case EUsbcDeviceStateUndefined: sl@0: // valid: Undefined -> Attached sl@0: if (aNextState != EUsbcDeviceStateAttached) sl@0: break; sl@0: goto OK; sl@0: case EUsbcDeviceStateAttached: sl@0: // valid: Attached -> {Undefined, Powered} sl@0: if ((aNextState != EUsbcDeviceStateUndefined) && sl@0: (aNextState != EUsbcDeviceStatePowered)) sl@0: break; sl@0: goto OK; sl@0: case EUsbcDeviceStatePowered: sl@0: // valid: Powered -> {Undefined, Attached, Default, Suspended} sl@0: if ((aNextState != EUsbcDeviceStateUndefined) && sl@0: (aNextState != EUsbcDeviceStateAttached) && sl@0: (aNextState != EUsbcDeviceStateDefault) && sl@0: (aNextState != EUsbcDeviceStateSuspended)) sl@0: break; sl@0: goto OK; sl@0: case EUsbcDeviceStateDefault: sl@0: // valid: Default -> {Undefined, Powered, Default, Address, Suspended} sl@0: if ((aNextState != EUsbcDeviceStateUndefined) && sl@0: (aNextState != EUsbcDeviceStatePowered) && sl@0: (aNextState != EUsbcDeviceStateDefault) && sl@0: (aNextState != EUsbcDeviceStateAddress) && sl@0: (aNextState != EUsbcDeviceStateSuspended)) sl@0: break; sl@0: goto OK; sl@0: case EUsbcDeviceStateAddress: sl@0: // valid: Address -> {Undefined, Powered, Default, Configured, Suspended} sl@0: if ((aNextState != EUsbcDeviceStateUndefined) && sl@0: (aNextState != EUsbcDeviceStatePowered) && sl@0: (aNextState != EUsbcDeviceStateDefault) && sl@0: (aNextState != EUsbcDeviceStateConfigured) && sl@0: (aNextState != EUsbcDeviceStateSuspended)) sl@0: break; sl@0: goto OK; sl@0: case EUsbcDeviceStateConfigured: sl@0: // valid: Configured -> {Undefined, Powered, Default, Address, Suspended} sl@0: if ((aNextState != EUsbcDeviceStateUndefined) && sl@0: (aNextState != EUsbcDeviceStatePowered) && sl@0: (aNextState != EUsbcDeviceStateDefault) && sl@0: (aNextState != EUsbcDeviceStateAddress) && sl@0: (aNextState != EUsbcDeviceStateSuspended)) sl@0: break; sl@0: goto OK; sl@0: case EUsbcDeviceStateSuspended: sl@0: // valid: Suspended -> {Undefined, Powered, Default, Address, Configured} sl@0: if ((aNextState != EUsbcDeviceStateUndefined) && sl@0: (aNextState != EUsbcDeviceStatePowered) && sl@0: (aNextState != EUsbcDeviceStateDefault) && sl@0: (aNextState != EUsbcDeviceStateAddress) && sl@0: (aNextState != EUsbcDeviceStateConfigured)) sl@0: break; sl@0: goto OK; sl@0: default: sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown current device state: %d", iDeviceState)); sl@0: goto OK; sl@0: } sl@0: // KUSB only (instead of KPANIC) so as not to worry people too much where sl@0: // a particular h/w regularly enforces invalid (but harmless) transitions sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Warning: Invalid next state from %s", states[iDeviceState])); sl@0: OK: sl@0: #endif // _DEBUG sl@0: sl@0: iDeviceState = aNextState; sl@0: StatusNotify(iDeviceState); sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::ProcessSuspendEvent() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSuspendEvent()")); sl@0: // A suspend interrupt has been received and needs attention. sl@0: iDeviceStateB4Suspend = iDeviceState; sl@0: // We have to move to the Suspend state immediately (in case it's a genuine Suspend) sl@0: // because 7.1.7.6 says: "The device must actually be suspended, [...] after no more sl@0: // than 10ms of bus inactivity [...]." Assuming we got the interrupt 3ms after the sl@0: // Suspend condition arose, we have now 7ms left. sl@0: NextDeviceState(EUsbcDeviceStateSuspended); sl@0: Suspend(); sl@0: // For some reason we get this interrupt also when the USB cable has been pulled. sl@0: // So we want to see if that is the case in order to move to the Undefined state instead. sl@0: // However, instead of immediately checking the status of the USB cable we wait for a sl@0: // short moment (KUsbCableStatusDelay, see top of file), until things have become stable. sl@0: // Then, in the timer callback, we can change the device state once more if necessary. sl@0: iCableStatusTimer.OneShot(KUsbCableStatusDelay); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: // sl@0: // ISR (from CableStatusTimerCallback) sl@0: // sl@0: TInt DUsbClientController::ProcessSuspendEventProceed() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSuspendEventProceed()")); sl@0: if (!UsbConnectionStatus()) sl@0: { sl@0: // If we are no longer connected to the bus, we go into Undefined state (from Suspend). sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" > USB cable detached")); sl@0: NextDeviceState(EUsbcDeviceStateUndefined); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::ProcessResumeEvent() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessResumeEvent()")); sl@0: iCableStatusTimer.Cancel(); sl@0: if (iDeviceState == EUsbcDeviceStateSuspended) sl@0: { sl@0: NextDeviceState(iDeviceStateB4Suspend); sl@0: } sl@0: Resume(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::ProcessResetEvent(TBool aPslUpcall) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessResetEvent()")); sl@0: sl@0: if (aPslUpcall) sl@0: { sl@0: // Call back into PSL if we're coming from there. sl@0: // Also, do it always, even when PIL processing will be deferred. sl@0: Reset(); sl@0: } sl@0: sl@0: #ifdef USB_OTG_CLIENT sl@0: if (iUsbResetDeferred) // implies (iOtgHnpHandledByHw == ETrue) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" User-side (still) not ready -> returning")); sl@0: return KErrNone; sl@0: } sl@0: else if (iOtgHnpHandledByHw && !iClientSupportReady) sl@0: { sl@0: // Wait with the PIL Reset processing until user-side is ready sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" User-side not ready -> deferring")); sl@0: iUsbResetDeferred = ETrue; sl@0: return KErrNone; sl@0: } sl@0: #endif // USB_OTG_CLIENT sl@0: sl@0: iCableStatusTimer.Cancel(); sl@0: if (iDeviceState == EUsbcDeviceStateAttached) sl@0: { sl@0: NextDeviceState(EUsbcDeviceStatePowered); sl@0: } sl@0: // Notify the world. (This will just queue a DFC, so users won't actually be sl@0: // notified before we return. But we change the device state already here so sl@0: // ChangeConfiguration will see the correct one.) sl@0: NextDeviceState(EUsbcDeviceStateDefault); sl@0: // Tear down the current configuration (never called from thread) sl@0: ChangeConfiguration(0); sl@0: // Reset essential vars sl@0: iRmWakeupStatus_Enabled = EFalse; sl@0: ResetEp0DataOutVars(); sl@0: iEp0_RxExtraData = EFalse; sl@0: iEp0WritePending = EFalse; sl@0: iEp0ClientDataTransmitting = EFalse; sl@0: // Reset OTG features, leave attributes as is sl@0: iOtgFuncMap &= KUsbOtgAttr_SrpSupp | KUsbOtgAttr_HnpSupp; sl@0: if (iOtgSupport) sl@0: { sl@0: OtgFeaturesNotify(); sl@0: } sl@0: sl@0: // Check whether there's a speed change sl@0: const TBool was_hs = iHighSpeed; sl@0: iHighSpeed = CurrentlyUsingHighSpeed(); sl@0: if (!was_hs && iHighSpeed) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Moving to High-speed")); sl@0: EnterHighSpeed(); sl@0: } sl@0: else if (was_hs && !iHighSpeed) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Moving to Full-speed")); sl@0: EnterFullSpeed(); sl@0: } sl@0: sl@0: // Setup initial Ep0 read (SetupEndpointZeroRead never called from thread) sl@0: if (SetupEndpointZeroRead() != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: while setting up Ep0 read")); sl@0: return KErrGeneral; sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::ProcessCableInsertEvent() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessCableInsertEvent()")); sl@0: #ifdef USB_OTG_CLIENT sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: EUsbEventCableInsert shouldn't be sent by an OTG Client PSL")); sl@0: return KErrArgument; sl@0: #else sl@0: NextDeviceState(EUsbcDeviceStateAttached); sl@0: if (iHardwareActivated) sl@0: { sl@0: NextDeviceState(EUsbcDeviceStatePowered); sl@0: } sl@0: return KErrNone; sl@0: #endif // #ifdef USB_OTG_CLIENT sl@0: } sl@0: sl@0: sl@0: TInt DUsbClientController::ProcessCableRemoveEvent() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessCableRemoveEvent()")); sl@0: #ifdef USB_OTG_CLIENT sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: EUsbEventCableRemoved shouldn't be sent by an OTG Client PSL")); sl@0: return KErrArgument; sl@0: #else sl@0: // Tear down the current configuration (if any) sl@0: ChangeConfiguration(0); sl@0: NextDeviceState(EUsbcDeviceStateUndefined); sl@0: return KErrNone; sl@0: #endif // #ifdef USB_OTG_CLIENT sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::EnterFullSpeed() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EnterFullSpeed()")); sl@0: iDescriptors.UpdateDescriptorsFs(); sl@0: } sl@0: sl@0: sl@0: void DUsbClientController::EnterHighSpeed() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EnterHighSpeed()")); sl@0: iDescriptors.UpdateDescriptorsHs(); sl@0: } sl@0: sl@0: sl@0: // sl@0: // Called whenever either iOtgClientConnect or iClientSupportReady changes value. sl@0: // sl@0: TInt DUsbClientController::EvaluateOtgConnectFlags() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EvaluateOtgConnectFlags()")); sl@0: sl@0: TInt r = KErrNone; sl@0: sl@0: // Check to see if the current flag states result in a change to the sl@0: // need to activate the DPLUS pull-up sl@0: TBool enableDPlus; sl@0: if (!iOtgHnpHandledByHw) sl@0: { sl@0: // the default sl@0: enableDPlus = (iOtgClientConnect && iClientSupportReady); sl@0: } sl@0: else sl@0: { sl@0: // certain h/w: handles HNP connect/disconnect automatically sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" HNP-handling h/w: only considering user-side readiness")); sl@0: enableDPlus = iClientSupportReady; sl@0: } sl@0: sl@0: if (enableDPlus == iDPlusEnabled) sl@0: { sl@0: return r; sl@0: } sl@0: sl@0: // There has been a changed requirement that must be serviced... sl@0: if (enableDPlus) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" calling (*iEnablePullUpOnDPlus)()")); sl@0: if (iEnablePullUpOnDPlus != NULL) sl@0: { sl@0: iDPlusEnabled = enableDPlus; sl@0: // First we move to Suspend state to trigger a state change sl@0: // notification in any case, even if no cable and/or host are sl@0: // connected. The next Reset will get us out of it again. sl@0: iDeviceStateB4Suspend = iDeviceState; sl@0: NextDeviceState(EUsbcDeviceStateSuspended); sl@0: r = (*iEnablePullUpOnDPlus)(iOtgContext); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: iEnablePullUpOnDPlus() = %d", r)); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Warning: iEnablePullUpOnDPlus pointer not ready")); sl@0: // We cannot enforce the presence of the pointer (via an ASSERT) sl@0: // since it might only be available at a later point. sl@0: // We shouldn't return an error at this point either, since the sl@0: // problem will be a systematic one. sl@0: } sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" calling (*iDisablePullUpOnDPlus)()")); sl@0: if (iDisablePullUpOnDPlus != NULL) sl@0: { sl@0: iDPlusEnabled = enableDPlus; sl@0: r = (*iDisablePullUpOnDPlus)(iOtgContext); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: iDisablePullUpOnDPlus() = %d", r)); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Warning: iDisablePullUpOnDPlus pointer not ready")); sl@0: // We cannot enforce the presence of the pointer (via an ASSERT) sl@0: // since it might only be available at a later point. sl@0: // We shouldn't return an error at this point either, since the sl@0: // problem will be a systematic one. sl@0: } sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: // sl@0: // DFC (static) sl@0: // sl@0: void DUsbClientController::ReconnectTimerCallback(TAny *aPtr) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ReconnectTimerCallback()")); sl@0: if (!aPtr) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: !aPtr")); sl@0: return; sl@0: } sl@0: DUsbClientController* const ptr = static_cast(aPtr); sl@0: ptr->UsbConnect(); sl@0: } sl@0: sl@0: sl@0: // sl@0: // ISR (static) sl@0: // sl@0: void DUsbClientController::CableStatusTimerCallback(TAny *aPtr) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::CableStatusTimerCallback()")); sl@0: if (!aPtr) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: !aPtr")); sl@0: return; sl@0: } sl@0: DUsbClientController* const ptr = static_cast(aPtr); sl@0: ptr->ProcessSuspendEventProceed(); sl@0: } sl@0: sl@0: sl@0: // sl@0: // static sl@0: // sl@0: void DUsbClientController::PowerUpDfc(TAny* aPtr) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::PowerUpDfc")); sl@0: if (!aPtr) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: !aPtr")); sl@0: return; sl@0: } sl@0: DUsbClientController* const ptr = static_cast(aPtr); sl@0: __PM_ASSERT(ptr->iStandby); sl@0: (void) ptr->PowerUp(); sl@0: ptr->iStandby = EFalse; sl@0: ptr->iPowerHandler->PowerUpDone(); sl@0: } sl@0: sl@0: sl@0: // sl@0: // static sl@0: // sl@0: void DUsbClientController::PowerDownDfc(TAny* aPtr) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::PowerDownDfc")); sl@0: if (!aPtr) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: !aPtr")); sl@0: return; sl@0: } sl@0: DUsbClientController* const ptr = static_cast(aPtr); sl@0: __PM_ASSERT(!ptr->iStandby); sl@0: ptr->iStandby = ETrue; sl@0: // We might not want to power down when the UDC is active: sl@0: if (!ptr->iHardwareActivated || ptr->PowerDownWhenActive()) sl@0: { sl@0: (void) ptr->PowerDown(); sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Calling PowerHandler->PowerDownDone()")); sl@0: ptr->iPowerHandler->PowerDownDone(); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Not calling PowerHandler->PowerDownDone()")); sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" because UDC is active.")); sl@0: } sl@0: } sl@0: sl@0: sl@0: // -EOF-