diff -r 000000000000 -r 96e5fb8b040d kernel/eka/drivers/usbcc/chapter9.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbcc/chapter9.cpp Thu Dec 17 09:24:54 2009 +0200 @@ -0,0 +1,1291 @@ +// Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the License "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// e32/drivers/usbcc/chapter9.cpp +// Platform independent layer (PIL) of the USB Device controller driver: +// Processing of USB spec chapter 9 standard requests. +// +// + +/** + @file chapter9.cpp + @internalTechnology +*/ + +#include + + +//#define ENABLE_EXCESSIVE_DEBUG_OUTPUT + +// +// The way functions are called after an request has been completed by the PSL: +// +// Ep0RequestComplete +// | +// ------------------------------------------------ +// | | +// ProcessEp0ReceiveDone ProcessEp0TransmitDone +// | | +// --------------------------------------- | +// | | | +// ProcessEp0SetupReceived ProcessEp0DataReceived ProcessDataTransferDone +// | | +// --------------------- --------------- +// | | | | +// ProcessXXX ProcessDataTransferDone ProceedXXX ProcessDataTransferDone +// +// XXX = Specific_Request +// + +// +// === USB Controller member function implementation - PSL API (protected) ======================== +// + +/** Used to synchronize the Ep0 state machine between the PSL and PIL. + Accepts a SETUP packet and returns the next Ep0 state. + + @param aSetupBuf The SETUP packet just received by the PSL. + @return The next Ep0 state. + + @publishedPartner @released +*/ +TUsbcEp0State DUsbClientController::EnquireEp0NextState(const TUint8* aSetupBuf) const + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::EnquireEp0NextState()")); + + // This function may be called by the PSL from within an ISR -- so we have + // to take care what we do here (and also in all functions that get called + // from here). + + if (SWAP_BYTES_16((reinterpret_cast(aSetupBuf)[3])) == 0) // iLength + { + __KTRACE_OPT(KUSB, Kern::Printf(" --> EEp0StateStatusIn")); + return EEp0StateStatusIn; // No-data Control => Status_IN + } + else if ((aSetupBuf[0] & KUsbRequestType_DirMask) == KUsbRequestType_DirToDev) + { + __KTRACE_OPT(KUSB, Kern::Printf(" --> EEp0StateDataOut")); + return EEp0StateDataOut; // Control Write => Data_OUT + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" --> EEp0StateDataIn")); + return EEp0StateDataIn; // Control Read => Data_IN + } + } + + +TInt DUsbClientController::ProcessEp0ReceiveDone(TInt aCount) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessEp0ReceiveDone()")); + TInt r; + if (iEp0DataReceiving == EFalse) + { + // It's obviously a Setup packet, so... + r = ProcessEp0SetupReceived(aCount); + } + else + { + // If it isn't a Setup, it must be data... + // (This is actually not quite true, as it could also be - in theory - a new Setup packet + // when the host has abandoned, for whatever reason, the previous one which was still + // in progress. However no such case is known to have occurred with this driver, or at + // least it didn't lead to problems. + // Some UDCs have a dedicated interrupt for Setup packets, but so far this driver hasn't + // made use of such a feature (as it would require a PSL/PIL API change).) + r = ProcessEp0DataReceived(aCount); + } + return r; + } + + +TInt DUsbClientController::ProcessEp0TransmitDone(TInt aCount, TInt aError) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessEp0TransmitDone()")); + // In any case: there's now no longer a write pending + iEp0WritePending = EFalse; + // If it was a client who set up this transmission, we report to that client + if (iEp0ClientDataTransmitting) + { + iEp0ClientDataTransmitting = EFalse; + TUsbcRequestCallback* const p = iRequestCallbacks[KEp0_Tx]; + if (p) + { + __ASSERT_DEBUG((p->iTransferDir == EControllerWrite), Kern::Fault(KUsbPILPanicCat, __LINE__)); + p->iError = aError; + p->iTxBytes = aCount; + ProcessDataTransferDone(*p); + return KErrNone; + } + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DUsbClientController::ProcessEpTransmitDone: Stalling Ep0")); + StallEndpoint(KEp0_In); // request not found + return KErrNotFound; + } + // If _we_ sent the data, we simply do nothing here... + return KErrNone; + } + + +#define USB_PROCESS_REQUEST(request) \ + if (Process ## request(packet) != KErrNone) \ + { \ + __KTRACE_OPT(KUSB, \ + Kern::Printf(" ProcessEp0SetupReceived: Stalling Ep0")); \ + StallEndpoint(KEp0_In); \ + } + +TInt DUsbClientController::ProcessEp0SetupReceived(TInt aCount) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessEp0SetupReceived()")); + + if (aCount > iEp0MaxPacketSize) + { + // Fatal error: too much data! + aCount = iEp0MaxPacketSize; + } + + // first we split the data into meaningful units: + TUsbcSetup packet; + Buffer2Setup(iEp0_RxBuf, packet); + +#if defined(_DEBUG) && defined(ENABLE_EXCESSIVE_DEBUG_OUTPUT) + // let's see what we've got: + __KTRACE_OPT(KUSB, Kern::Printf(" bmRequestType = 0x%02x", packet.iRequestType)); + if ((packet.iRequestType & KUsbRequestType_TypeMask) == KUsbRequestType_TypeStd) + { + switch (packet.iRequest) + { + case KUsbRequest_GetStatus: + __KTRACE_OPT(KUSB, Kern::Printf(" bRequest = 0x%02x (GET_STATUS)", + KUsbRequest_GetStatus)); + break; + case KUsbRequest_ClearFeature: + __KTRACE_OPT(KUSB, Kern::Printf(" bRequest = 0x%02x (CLEAR_FEATURE)", + KUsbRequest_ClearFeature)); + break; + case KUsbRequest_SetFeature: + __KTRACE_OPT(KUSB, Kern::Printf(" bRequest = 0x%02x (SET_FEATURE)", + KUsbRequest_SetFeature)); + break; + case KUsbRequest_SetAddress: + __KTRACE_OPT(KUSB, Kern::Printf(" bRequest = 0x%02x (SET_ADDRESS)", + KUsbRequest_SetAddress)); + break; + case KUsbRequest_GetDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf(" bRequest = 0x%02x (GET_DESCRIPTOR)", + KUsbRequest_GetDescriptor)); + break; + case KUsbRequest_SetDescriptor: + __KTRACE_OPT(KUSB, Kern::Printf(" bRequest = 0x%02x (SET_DESCRIPTOR)", + KUsbRequest_SetDescriptor)); + break; + case KUsbRequest_GetConfig: + __KTRACE_OPT(KUSB, Kern::Printf(" bRequest = 0x%02x (GET_CONFIGURATION)", + KUsbRequest_GetConfig)); + break; + case KUsbRequest_SetConfig: + __KTRACE_OPT(KUSB, Kern::Printf(" bRequest = 0x%02x (SET_CONFIGURATION)", + KUsbRequest_SetConfig)); + break; + case KUsbRequest_GetInterface: + __KTRACE_OPT(KUSB, Kern::Printf(" bRequest = 0x%02x (GET_INTERFACE)", + KUsbRequest_GetInterface)); + break; + case KUsbRequest_SetInterface: + __KTRACE_OPT(KUSB, Kern::Printf(" bRequest = 0x%02x (SET_INTERFACE)", + KUsbRequest_SetInterface)); + break; + case KUsbRequest_SynchFrame: + __KTRACE_OPT(KUSB, Kern::Printf(" bRequest = 0x%02x (SYNCH_FRAME)", + KUsbRequest_SynchFrame)); + break; + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: bRequest = 0x%02x (UNKNWON STANDARD REQUEST)", + packet.iRequest)); + break; + } + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" bRequest = 0x%02x (NON-STANDARD REQUEST)", + packet.iRequest)); + } + __KTRACE_OPT(KUSB, Kern::Printf(" wValue = 0x%04x", packet.iValue)); + __KTRACE_OPT(KUSB, Kern::Printf(" wIndex = 0x%04x", packet.iIndex)); + __KTRACE_OPT(KUSB, Kern::Printf(" wLength = 0x%04x", packet.iLength)); +#endif // defined(_DEBUG) && defined(ENABLE_EXCESSIVE_DEBUG_OUTPUT) + + // now the actual analysis + if ((packet.iRequestType & KUsbRequestType_TypeMask) == KUsbRequestType_TypeStd) + { + iEp0ReceivedNonStdRequest = EFalse; + switch (packet.iRequest) + { + case KUsbRequest_GetStatus: + switch (packet.iRequestType & KUsbRequestType_DestMask) + { // Recipient + case KUsbRequestType_DestDevice: + USB_PROCESS_REQUEST(GetDeviceStatus); + break; + case KUsbRequestType_DestIfc: + USB_PROCESS_REQUEST(GetInterfaceStatus); + break; + case KUsbRequestType_DestEp: + USB_PROCESS_REQUEST(GetEndpointStatus); + break; + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: GET STATUS - Other or Unknown recipient")); + __KTRACE_OPT(KPANIC, Kern::Printf(" -> DUsbClientController::ProcessEp0SetupReceived: " + "Stalling Ep0")); + StallEndpoint(KEp0_In); + break; + } + break; + case KUsbRequest_ClearFeature: + case KUsbRequest_SetFeature: + switch (packet.iRequestType & KUsbRequestType_DestMask) + { // Recipient + case KUsbRequestType_DestDevice: + USB_PROCESS_REQUEST(SetClearDevFeature); + break; + case KUsbRequestType_DestIfc: + USB_PROCESS_REQUEST(SetClearIfcFeature); + break; + case KUsbRequestType_DestEp: + USB_PROCESS_REQUEST(SetClearEpFeature); + break; + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: SET/CLEAR FEATURE - " + "Other or Unknown recipient")); + __KTRACE_OPT(KPANIC, Kern::Printf(" -> Stalling Ep0")); + StallEndpoint(KEp0_In); + break; + } + break; + case KUsbRequest_SetAddress: + USB_PROCESS_REQUEST(SetAddress); + break; + case KUsbRequest_GetDescriptor: + USB_PROCESS_REQUEST(GetDescriptor); + break; + case KUsbRequest_SetDescriptor: + USB_PROCESS_REQUEST(SetDescriptor); + break; + case KUsbRequest_GetConfig: + USB_PROCESS_REQUEST(GetConfiguration); + break; + case KUsbRequest_SetConfig: + USB_PROCESS_REQUEST(SetConfiguration); + break; + case KUsbRequest_GetInterface: + USB_PROCESS_REQUEST(GetInterface); + break; + case KUsbRequest_SetInterface: + USB_PROCESS_REQUEST(SetInterface); + break; + case KUsbRequest_SynchFrame: + USB_PROCESS_REQUEST(SynchFrame); + break; + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown/unsupported Std Setup Request")); + __KTRACE_OPT(KPANIC, Kern::Printf(" -> Stalling Ep0")); + StallEndpoint(KEp0_In); + break; + } + } + else + { + // Type mask != KUsbRequestType_TypeStd => class- or vendor-specific request + iEp0ReceivedNonStdRequest = ETrue; + const DBase* client = NULL; + switch (packet.iRequestType & KUsbRequestType_DestMask) + { // Recipient + case KUsbRequestType_DestDevice: + client = iEp0DeviceControl; + break; + case KUsbRequestType_DestIfc: + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + } + else + { + const TUsbcInterfaceSet* const ifcset_ptr = + InterfaceNumber2InterfacePointer(packet.iIndex); + if (ifcset_ptr) + { + if (ifcset_ptr->CurrentInterface()->iNoEp0Requests) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Recipient says: NoEp0RequestsPlease")); + } + else + { + client = ifcset_ptr->iClientId; + } + } + else + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface 0x%02x does not exist", + packet.iIndex)); + } + } + break; + case KUsbRequestType_DestEp: + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + } + else if (EndpointExists(packet.iIndex) == EFalse) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint 0x%02x does not exist", + packet.iIndex)); + } + else + { + const TInt idx = EpAddr2Idx(packet.iIndex); + const TUsbcInterfaceSet* const ifcset_ptr = + iRealEndpoints[idx].iLEndpoint->iInterface->iInterfaceSet; + if (ifcset_ptr->CurrentInterface()->iNoEp0Requests) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Recipient says: NoEp0RequestsPlease")); + } + else + { + client = ifcset_ptr->iClientId; + } + } + break; + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Other or Unknown recipient")); + break; + } + if (client != NULL) + { + // Try to relay packet to the appropriate recipient + TSglQueIter iter(iEp0ReadRequestCallbacks); + TUsbcRequestCallback* p; + while ((p = iter++) != NULL) + { + if (p->Owner() == client) + { + __ASSERT_DEBUG((p->iEndpointNum == 0), Kern::Fault(KUsbPILPanicCat, __LINE__)); + __ASSERT_DEBUG((p->iTransferDir == EControllerRead), Kern::Fault(KUsbPILPanicCat, __LINE__)); + __KTRACE_OPT(KUSB, Kern::Printf(" Found Ep0 read request")); + if (packet.iLength != 0) + { + if ((packet.iRequestType & KUsbRequestType_DirMask) == KUsbRequestType_DirToDev) + { + // Data transfer & direction OUT => there'll be a DATA_OUT stage + __KTRACE_OPT(KUSB, Kern::Printf(" Next is DATA_OUT: setting up DataOutVars")); + SetEp0DataOutVars(packet, client); + } + else if ((packet.iRequestType & KUsbRequestType_DirMask) == KUsbRequestType_DirToHost) + { + // For possible later use (ZLP). + iEp0_TxNonStdCount = packet.iLength; + } + } + memcpy(p->iBufferStart, iEp0_RxBuf, aCount); + p->iError = KErrNone; // if it wasn't 'KErrNone' we wouldn't be here + *(p->iPacketSize) = aCount; + p->iRxPackets = 1; + *(p->iPacketIndex) = 0; + ProcessDataTransferDone(*p); + return KErrNone; + } + } + __KTRACE_OPT(KUSB, Kern::Printf(" Ep0 read request not found: setting RxExtra vars (Setup)")); + iEp0_RxExtraCount = aCount; + iEp0_RxExtraData = ETrue; + return KErrNotFound; + } + else // if (client == NULL) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Ep0 request error: Stalling Ep0")); + StallEndpoint(KEp0_In); + return KErrGeneral; + } + } + return KErrNone; + } + +#undef USB_PROCESS_REQUEST + + +TInt DUsbClientController::ProcessEp0DataReceived(TInt aCount) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessEp0DataReceived()")); + + __KTRACE_OPT(KUSB, Kern::Printf(" : %d bytes", aCount)); + + if (aCount > iEp0MaxPacketSize) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Too much data")); + aCount = iEp0MaxPacketSize; + } + iEp0DataReceived += aCount; + if (iEp0ClientId == NULL) + { + // it is us (not an app), who owns this transaction + switch (iSetup.iRequest) + { +#ifdef USB_SUPPORTS_SET_DESCRIPTOR_REQUEST + case KUsbRequest_SetDescriptor: + memcpy(iEp0_RxCollectionBuf + iEp0DataReceived, iEp0_RxBuf, aCount); + ProceedSetDescriptor(); + break; +#endif + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: invalid request in iSetup")); + __KTRACE_OPT(KPANIC, Kern::Printf(" -> DUsbClientController::ProcessEp0DataReceived: Stalling Ep0")); + StallEndpoint(KEp0_In); + ResetEp0DataOutVars(); + break; + } + } + else + { + // pass the data on to a client + TSglQueIter iter(iEp0ReadRequestCallbacks); + TUsbcRequestCallback* p; + while ((p = iter++) != NULL) + { + if (p->Owner() == iEp0ClientId) + { + __ASSERT_DEBUG((p->iEndpointNum == 0), Kern::Fault(KUsbPILPanicCat, __LINE__)); + __ASSERT_DEBUG((p->iTransferDir == EControllerRead), Kern::Fault(KUsbPILPanicCat, __LINE__)); + __KTRACE_OPT(KUSB, Kern::Printf(" Found Ep0 read request")); + memcpy(p->iBufferStart, iEp0_RxBuf, aCount); + p->iError = KErrNone; // if it wasn't 'KErrNone' we wouldn't be here + *(p->iPacketSize) = aCount; + p->iRxPackets = 1; + *(p->iPacketIndex) = 0; + ProcessDataTransferDone(*p); + goto found; + } + } + __KTRACE_OPT(KUSB, Kern::Printf(" Ep0 read request not found: setting RxExtra vars (Data)")); + iEp0_RxExtraCount = aCount; + iEp0_RxExtraData = ETrue; + iEp0DataReceived -= aCount; + return KErrNotFound; + } + found: + if (iEp0DataReceived >= iSetup.iLength) + { + // all data seems now to be here + ResetEp0DataOutVars(); + } + return KErrNone; + } + + +// --- The USB Spec Chapter 9 Standard Endpoint Zero Device Requests --- + +TInt DUsbClientController::ProcessGetDeviceStatus(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessGetDeviceStatus()")); + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateAddress) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + const TUint16 status = ((DeviceSelfPowered() ? KUsbDevStat_SelfPowered : 0) | + (iRmWakeupStatus_Enabled ? KUsbDevStat_RemoteWakeup : 0)); + __KTRACE_OPT(KUSB, Kern::Printf(" Reporting device status: 0x%02x", status)); + *reinterpret_cast(iEp0_TxBuf) = SWAP_BYTES_16(status); + if (SetupEndpointZeroWrite(iEp0_TxBuf, sizeof(status)) == KErrNone) + { + iEp0WritePending = ETrue; + } + return KErrNone; + } + + +TInt DUsbClientController::ProcessGetInterfaceStatus(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessGetInterfaceStatus()")); + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + if (InterfaceExists(aPacket.iIndex) == EFalse) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Interface does not exist")); + return KErrGeneral; + } + const TUint16 status = 0x0000; // as of USB Spec 2.0 + __KTRACE_OPT(KUSB, Kern::Printf(" Reporting interface status: 0x%02x", status)); + *reinterpret_cast(iEp0_TxBuf) = SWAP_BYTES_16(status); + if (SetupEndpointZeroWrite(iEp0_TxBuf, sizeof(status)) == KErrNone) + { + iEp0WritePending = ETrue; + } + return KErrNone; + } + + +TInt DUsbClientController::ProcessGetEndpointStatus(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessGetEndpointStatus()")); + if (iTrackDeviceState && + ((iDeviceState < EUsbcDeviceStateAddress) || + (iDeviceState == EUsbcDeviceStateAddress && (aPacket.iIndex & KUsbEpAddress_Portmask) != 0))) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + if (EndpointExists(aPacket.iIndex) == EFalse) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint does not exist")); + return KErrGeneral; + } + const TInt ep = EpAddr2Idx(aPacket.iIndex); + const TUint16 status = (iRealEndpoints[ep].iHalt) ? KUsbEpStat_Halt : 0; + __KTRACE_OPT(KUSB, Kern::Printf(" Reporting endpoint status 0x%02x for real endpoint %d", + status, ep)); + *reinterpret_cast(iEp0_TxBuf) = SWAP_BYTES_16(status); + if (SetupEndpointZeroWrite(iEp0_TxBuf, 2) == KErrNone) + { + iEp0WritePending = ETrue; + } + return KErrNone; + } + + +TInt DUsbClientController::ProcessSetClearDevFeature(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetClearDevFeature()")); + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateDefault) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + + TUint test_sel = 0; + + if (aPacket.iRequest == KUsbRequest_SetFeature) + { + switch (aPacket.iValue) + { + case KUsbFeature_RemoteWakeup: + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateAddress) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + iRmWakeupStatus_Enabled = ETrue; + break; + case KUsbFeature_TestMode: + if (!iHighSpeed) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only supported in High-Speed mode")); + return KErrGeneral; + } + if (LowByte(aPacket.iIndex) != 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Lower byte of wIndex must be zero")); + return KErrGeneral; + } + test_sel = HighByte(aPacket.iIndex); + if ((test_sel < KUsbTestSelector_Test_J) || (test_sel > KUsbTestSelector_Test_Force_Enable)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid test selector: %d", test_sel)); + return KErrGeneral; + } + break; + case KUsbFeature_B_HnpEnable: + if (!iOtgSupport) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only supported on a OTG device")); + return KErrGeneral; + } + if (!(iOtgFuncMap & KUsbOtgAttr_HnpSupp)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only valid if OTG device supports HNP")); + return KErrGeneral; + } + iOtgFuncMap |= KUsbOtgAttr_B_HnpEnable; + OtgFeaturesNotify(); + break; + case KUsbFeature_A_HnpSupport: + if (!iOtgSupport) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only supported on a OTG device")); + return KErrGeneral; + } + if (!(iOtgFuncMap & KUsbOtgAttr_HnpSupp)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only valid if OTG device supports HNP")); + return KErrGeneral; + } + iOtgFuncMap |= KUsbOtgAttr_A_HnpSupport; + OtgFeaturesNotify(); + break; + case KUsbFeature_A_AltHnpSupport: + if (!iOtgSupport) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only supported on a OTG device")); + return KErrGeneral; + } + if (!(iOtgFuncMap & KUsbOtgAttr_HnpSupp)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Request only valid if OTG device supports HNP")); + return KErrGeneral; + } + iOtgFuncMap |= KUsbOtgAttr_A_AltHnpSupport; + OtgFeaturesNotify(); + break; + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown feature requested")); + return KErrGeneral; + } + } + else // KUsbRequest_ClearFeature + { + switch (aPacket.iValue) + { + case KUsbFeature_RemoteWakeup: + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateAddress) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + iRmWakeupStatus_Enabled = EFalse; + break; + default: + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown feature requested")); + return KErrGeneral; + } + } + + SendEp0ZeroByteStatusPacket(); // success: zero bytes data during status stage + + // 9.4.9: "The transition to test mode of an upstream facing port must not happen until + // after the status stage of the request." + if (test_sel) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Entering HS Test Mode %d", test_sel)); + EnterTestMode(test_sel); + } + + return KErrNone; + } + + +TInt DUsbClientController::ProcessSetClearIfcFeature(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetClearIfcFeature()")); + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + // No interface features defined in USB spec, thus + return KErrGeneral; + } + + +TInt DUsbClientController::ProcessSetClearEpFeature(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetClearEpFeature()")); + if (iTrackDeviceState && + ((iDeviceState < EUsbcDeviceStateAddress) || + (iDeviceState == EUsbcDeviceStateAddress && (aPacket.iIndex & KUsbEpAddress_Portmask) != 0))) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + if (aPacket.iValue != KUsbFeature_EndpointHalt) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Unknown feature requested")); + return KErrGeneral; + } + if (EndpointExists(aPacket.iIndex) == EFalse) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint does not exist")); + return KErrGeneral; + } + const TInt ep = EpAddr2Idx(aPacket.iIndex); + if (iRealEndpoints[ep].iLEndpoint->iInfo.iType == KUsbEpTypeControl || + iRealEndpoints[ep].iLEndpoint->iInfo.iType == KUsbEpTypeIsochronous) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint is Control or Isochronous")); + return KErrGeneral; + } + SetClearHaltFeature(ep, aPacket.iRequest); + SendEp0ZeroByteStatusPacket(); // success: zero bytes data during status stage + return KErrNone; + } + + +TInt DUsbClientController::ProcessSetAddress(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetAddress()")); + if (iTrackDeviceState && iDeviceState > EUsbcDeviceStateAddress) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + const TUint16 addr = aPacket.iValue; + if (addr > 127) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Bad address value: %d (>127)", addr)); + return KErrGeneral; + } + if (addr == 0) + { + // Enter Default state (from Default or Address) + NextDeviceState(EUsbcDeviceStateDefault); + } + __KTRACE_OPT(KUSB, Kern::Printf(" USB address: %d", addr)); + // The spec says, under section 9.4.6: + // "Stages after the initial Setup packet assume the same device address as the Setup packet. The USB + // device does not change its device address until after the Status stage of this request is completed + // successfully. Note that this is a difference between this request and all other requests. For all other + // requests, the operation indicated must be completed before the Status stage." + // Therefore, here we first send the status packet and only then actually execute the request. + SendEp0ZeroByteStatusPacket(); + SetDeviceAddress(addr); + return KErrNone; + } + + +TInt DUsbClientController::ProcessGetDescriptor(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessGetDescriptor()")); + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateDefault) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + + // Make sure we assume the correct speed + __ASSERT_DEBUG((iHighSpeed == CurrentlyUsingHighSpeed()), Kern::Fault(KUsbPILPanicCat, __LINE__)); + + TInt size = 0; + const TInt result = iDescriptors.FindDescriptor(HighByte(aPacket.iValue), // Type + LowByte(aPacket.iValue), // Index + aPacket.iIndex, // Language ID + size); + + if ((result != KErrNone) || (size == 0)) + { + // This doesn't have to be an error - protocol-wise it's OK. + __KTRACE_OPT(KUSB, Kern::Printf(" Couldn't retrieve descriptor")); + return KErrGeneral; + } + + __KTRACE_OPT(KUSB, Kern::Printf(" Descriptor found, size: %d (requested: %d)", + size, aPacket.iLength)); + if (size > KUsbcBufSz_Ep0Tx) + { + // This should actually not be possible (i.e. we should never get here). + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Ep0_Tx buffer too small")); + } + if (size > aPacket.iLength) + { + // Send only as much data as requested by the host + size = aPacket.iLength; + } + +#ifdef ENABLE_EXCESSIVE_DEBUG_OUTPUT + __KTRACE_OPT(KUSB, + Kern::Printf(" Data: 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x ...", + iEp0_TxBuf[0], iEp0_TxBuf[1], iEp0_TxBuf[2], iEp0_TxBuf[3], + iEp0_TxBuf[4], iEp0_TxBuf[5], iEp0_TxBuf[6], iEp0_TxBuf[7])); +#endif + // If we're about to send less bytes than expected by the host AND our number is a + // multiple of the packet size, in order to indicate the end of the control transfer, + // we must finally send a zero length data packet (ZLP): + const TBool zlp = ((size < aPacket.iLength) && (size % iEp0MaxPacketSize == 0)); + if (SetupEndpointZeroWrite(iEp0_TxBuf, size, zlp) == KErrNone) + { + iEp0WritePending = ETrue; + } + + return KErrNone; + } + + +TInt DUsbClientController::ProcessSetDescriptor(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetDescriptor()")); +#ifndef USB_SUPPORTS_SET_DESCRIPTOR_REQUEST + return KErrGeneral; +#else + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateAddress) + { + // Error: Invalid device state! + return KErrGeneral; + } + if (aPacket.iLength > KUsbcBufSz_Ep0Rx) + { + // Error: Our Rx buffer is too small! (Raise a defect to make it larger) + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Ep0_Rx buffer too small")); + return KErrGeneral; + } + SetEp0DataOutVars(aPacket); + SetupEndpointZeroRead(); + return KErrNone; +#endif + } + + +TInt DUsbClientController::ProcessGetConfiguration(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessGetConfiguration()")); + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateAddress) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + if (iTrackDeviceState && iDeviceState == EUsbcDeviceStateAddress && iCurrentConfig != 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DeviceState Address && Config != 0")); + return KErrGeneral; + } + if (iTrackDeviceState && iDeviceState == EUsbcDeviceStateConfigured && iCurrentConfig == 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: DeviceState Configured && Config == 0")); + return KErrGeneral; + } + if (aPacket.iLength != 1) // "unspecified behavior" + { + __KTRACE_OPT(KUSB, Kern::Printf(" Warning: wLength != 1 (= %d)", aPacket.iLength)); + } + __KTRACE_OPT(KUSB, Kern::Printf(" Reporting configuration value %d", iCurrentConfig)); + if (SetupEndpointZeroWrite(&iCurrentConfig, sizeof(iCurrentConfig)) == KErrNone) + { + iEp0WritePending = ETrue; + } + return KErrNone; + } + + +/** Changes the device's configuration value, including interface setup and/or + teardown and state change notification of higher-layer clients. + May also be called by the PSL in special cases - therefore publishedPartner. + + @param aPacket The received Ep0 SET_CONFIGURATION setup request packet. + @return KErrGeneral in case of a protocol error, KErrNone otherwise. + + @publishedPartner @released +*/ +TInt DUsbClientController::ProcessSetConfiguration(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetConfiguration()")); + + // This function may be called by the PSL from within an ISR -- so we have + // to take care what we do here (and also in all functions that get called + // from here). + + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateAddress) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + const TUint16 value = aPacket.iValue; + if (value > 1) // we support only one configuration + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Configuration value too large: %d", value)); + return KErrGeneral; + } + + __KTRACE_OPT(KUSB, Kern::Printf(" Configuration value: %d", value)); + ChangeConfiguration(value); + + // In 9.4.5 under GET_STATUS we read, that after SET_CONFIGURATION the HALT feature + // for all endpoints is reset to zero. + TInt num = 0; + (TAny) DoForEveryEndpointInUse(&DUsbClientController::ClearHaltFeature, num); + __KTRACE_OPT(KUSB, Kern::Printf(" Called ClearHaltFeature() for %d endpoints", num)); + SendEp0ZeroByteStatusPacket(); // success: zero bytes data during status stage + return KErrNone; + } + + +TInt DUsbClientController::ProcessGetInterface(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessGetInterface()")); + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + if (iCurrentConfig == 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device not configured")); + return KErrGeneral; + } + const TInt number = aPacket.iIndex; + if (!InterfaceExists(number)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Bad interface index: %d", number)); + return KErrGeneral; + } + // Send alternate setting code of iCurrentInterface of Interface(set) of the current + // config (iCurrentConfig). + const TUint8 setting = InterfaceNumber2InterfacePointer(number)->iCurrentInterface; + __KTRACE_OPT(KUSB, Kern::Printf(" Reporting interface setting %d", setting)); + if (SetupEndpointZeroWrite(&setting, 1) == KErrNone) + { + iEp0WritePending = ETrue; + } + return KErrNone; + } + + +TInt DUsbClientController::ProcessSetInterface(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSetInterface()")); + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + if (iCurrentConfig == 0) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Device not configured")); + return KErrGeneral; + } + const TInt number = aPacket.iIndex; + if (!InterfaceExists(number)) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Bad interface index: %d", number)); + return KErrGeneral; + } + const TInt setting = aPacket.iValue; + TUsbcInterfaceSet* const ifcset_ptr = InterfaceNumber2InterfacePointer(number); + RPointerArray& ifcs = ifcset_ptr->iInterfaces; + if (setting >= ifcs.Count()) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Alt Setting >= bNumAltSettings: %d", setting)); + return KErrGeneral; + } + __KTRACE_OPT(KUSB, Kern::Printf(" Interface setting:: %d", setting)); + // Set iCurrentInterface of Interface(set) of the current config + // (iCurrentConfig) to alternate setting . + ChangeInterface(ifcs[setting]); + // In 9.4.5 under GET_STATUS we read, that after SET_INTERFACE the HALT feature + // for all endpoints (of the now current interface setting) is reset to zero. + RPointerArray& eps = ifcset_ptr->CurrentInterface()->iEndpoints; + const TInt num_eps = eps.Count(); + for (TInt i = 0; i < num_eps; i++) + { + const TInt ep_num = EpAddr2Idx(eps[i]->iPEndpoint->iEndpointAddr); + (TAny) ClearHaltFeature(ep_num); + } + SendEp0ZeroByteStatusPacket(); // success: zero bytes data during status stage + return KErrNone; + } + + +TInt DUsbClientController::ProcessSynchFrame(const TUsbcSetup& aPacket) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProcessSynchFrame()")); + if (iTrackDeviceState && iDeviceState < EUsbcDeviceStateConfigured) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Invalid device state")); + return KErrGeneral; + } + const TInt ep = aPacket.iIndex; + if (EndpointExists(ep) == EFalse) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint does not exist")); + return KErrGeneral; + } + if (iRealEndpoints[EpAddr2Idx(ep)].iLEndpoint->iInfo.iType != KUsbEpTypeIsochronous) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint is not isochronous")); + return KErrGeneral; + } + // We always send 0: + *reinterpret_cast(iEp0_TxBuf) = 0x00; + if (SetupEndpointZeroWrite(iEp0_TxBuf, 2) == KErrNone) + { + iEp0WritePending = ETrue; + } + return KErrNone; + } + + +#ifdef USB_SUPPORTS_SET_DESCRIPTOR_REQUEST +void DUsbClientController::ProceedSetDescriptor() + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ProceedSetDescriptor()")); + // iEp0DataReceived already reflects the current buffer state + if (iEp0DataReceived < iSetup.iLength) + { + // Not yet all data received => proceed + return; + } + if (iEp0DataReceived > iSetup.iLength) + { + // Error: more data received than expected + // but we don't care... + } + // at this point: iEp0DataReceived == iSetup.iLength + const TUint8 type = HighByte(iSetup.iValue); + if (type == KUsbDescType_String) + { + // set/add new string descriptor + } + else + { + // set/add new ordinary descriptor + } + TUint8 index = LowByte(iSetup.iValue); + TUint16 langid = iSetup.iIndex; + TUint16 length_total = iSetup.iLength; + } +#endif + + +// --- Secondary (Helper) Functions + +void DUsbClientController::SetClearHaltFeature(TInt aRealEndpoint, TUint8 aRequest) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::SetClearHaltFeature()")); + if (aRequest == KUsbRequest_SetFeature) + { + if (iRealEndpoints[aRealEndpoint].iHalt) + { + // (This condition is not really an error) + __KTRACE_OPT(KUSB, Kern::Printf(" Warning: HALT feature already set")); + return; + } + __KTRACE_OPT(KUSB, Kern::Printf(" setting HALT feature for real endpoint %d", + aRealEndpoint)); + StallEndpoint(aRealEndpoint); + iRealEndpoints[aRealEndpoint].iHalt = ETrue; + } + else // KUsbRequest_ClearFeature + { + if (iRealEndpoints[aRealEndpoint].iHalt == EFalse) + { + // In this case, before we return, the data toggles are reset to DATA0. + __KTRACE_OPT(KUSB, Kern::Printf(" Warning: HALT feature already cleared")); + ResetDataToggle(aRealEndpoint); + return; + } + __KTRACE_OPT(KUSB, Kern::Printf(" clearing HALT feature for real endpoint %d", + aRealEndpoint)); + ResetDataToggle(aRealEndpoint); + ClearStallEndpoint(aRealEndpoint); + iRealEndpoints[aRealEndpoint].iHalt = EFalse; + } + EpStatusNotify(aRealEndpoint); // only called if actually something changed + } + + +TInt DUsbClientController::ClearHaltFeature(TInt aRealEndpoint) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ClearHaltFeature()")); + if (iRealEndpoints[aRealEndpoint].iHalt != EFalse) + { + ClearStallEndpoint(aRealEndpoint); + iRealEndpoints[aRealEndpoint].iHalt = EFalse; + } + return KErrNone; + } + + +void DUsbClientController::ChangeConfiguration(TUint16 aValue) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ChangeConfiguration()")); + // New configuration is the same as the old one: 0 + if (iCurrentConfig == 0 && aValue == 0) + { + // no-op + __KTRACE_OPT(KUSB, Kern::Printf(" Configuration: New == Old == 0 --> exiting")); + return; + } + // New configuration is the same as the old one (but not 0) + if (iCurrentConfig == aValue) + { + // no-op + __KTRACE_OPT(KUSB, Kern::Printf(" Configuration: New == Old == %d --> exiting", aValue)); + return; + } + // Device is already configured + if (iCurrentConfig != 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Device was configured: %d", iCurrentConfig)); + // Tear down all interface(set)s of the old configuration + RPointerArray& ifcsets = CurrentConfig()->iInterfaceSets; + for (TInt i = 0; i < ifcsets.Count(); ++i) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Tearing down InterfaceSet %d", i)); + InterfaceSetTeardown(ifcsets[i]); + } + iCurrentConfig = 0; + // Enter Address state (from Configured) + if (iDeviceState == EUsbcDeviceStateConfigured) + NextDeviceState(EUsbcDeviceStateAddress); + } + // Device gets a new configuration + if (aValue != 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Device gets new configuration...")); + // Setup all alternate settings 0 of all interfaces + // (Don't separate the next two lines of code.) + iCurrentConfig = aValue; + RPointerArray& ifcsets = CurrentConfig()->iInterfaceSets; + const TInt n = ifcsets.Count(); + for (TInt i = 0; i < n; ++i) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Setting up InterfaceSet %d", i)); + InterfaceSetup(ifcsets[i]->iInterfaces[0]); + } + // Enter Configured state (from Address or Configured) + NextDeviceState(EUsbcDeviceStateConfigured); + } + __KTRACE_OPT(KUSB, Kern::Printf(" New configuration: %d", iCurrentConfig)); + return; + } + + +void DUsbClientController::InterfaceSetup(TUsbcInterface* aIfc) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::InterfaceSetup()")); + const TInt num_eps = aIfc->iEndpoints.Count(); + for (TInt i = 0; i < num_eps; i++) + { + // Prepare this endpoint for I/O + TUsbcLogicalEndpoint* const ep = aIfc->iEndpoints[i]; + // (TUsbcLogicalEndpoint's FS/HS endpoint sizes and interval values got + // adjusted in its constructor.) + if (iHighSpeed) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Setting Ep info size to %d (HS)", ep->iEpSize_Hs)); + ep->iInfo.iSize = ep->iEpSize_Hs; + } + else + { + __KTRACE_OPT(KUSB, Kern::Printf(" Setting Ep info size to %d (FS)", ep->iEpSize_Fs)); + ep->iInfo.iSize = ep->iEpSize_Fs; + } + const TInt idx = EpAddr2Idx(ep->iPEndpoint->iEndpointAddr); + if (ConfigureEndpoint(idx, ep->iInfo) != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint %d configuration failed", idx)); + continue; + } + // Should there be a problem with it then we could try resetting the ep + // data toggle at this point (or before the Configure) as well. + __KTRACE_OPT(KUSB, Kern::Printf(" Connecting real ep addr 0x%02x & logical ep #%d", + ep->iPEndpoint->iEndpointAddr, ep->iLEndpointNum)); + ep->iPEndpoint->iLEndpoint = ep; + } + aIfc->iInterfaceSet->iCurrentInterface = aIfc->iSettingCode; + return; + } + + +void DUsbClientController::InterfaceSetTeardown(TUsbcInterfaceSet* aIfcSet) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::InterfaceSetTeardown()")); + if (aIfcSet->iInterfaces.Count() == 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" No interfaces exist - returning")); + return; + } + RPointerArray& eps = aIfcSet->CurrentInterface()->iEndpoints; + const TInt num_eps = eps.Count(); + for (TInt i = 0; i < num_eps; i++) + { + TUsbcLogicalEndpoint* const ep = eps[i]; + const TInt idx = EpAddr2Idx(ep->iPEndpoint->iEndpointAddr); + + CancelTransferRequests(idx); + + if (!ep->iPEndpoint->iLEndpoint) + { + __KTRACE_OPT(KUSB, Kern::Printf(" real ep %d not configured: skipping", idx)); + continue; + } + if (ResetDataToggle(idx) != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint %d data toggle reset failed", idx)); + } + if (DeConfigureEndpoint(idx) != KErrNone) + { + __KTRACE_OPT(KPANIC, Kern::Printf(" Error: Endpoint %d de-configuration failed", idx)); + } + + __KTRACE_OPT(KUSB, Kern::Printf(" disconnecting real ep & logical ep")); + ep->iPEndpoint->iLEndpoint = NULL; + } + if (aIfcSet->CurrentInterface() != 0) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Resetting alternate interface setting to 0")); + aIfcSet->iCurrentInterface = 0; + } + return; + } + + +void DUsbClientController::ChangeInterface(TUsbcInterface* aIfc) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::ChangeInterface()")); + TUsbcInterfaceSet* ifcset = aIfc->iInterfaceSet; + const TUint8 setting = aIfc->iSettingCode; + if (ifcset->iCurrentInterface == setting) + { + __KTRACE_OPT(KUSB, Kern::Printf(" New Ifc == old Ifc: nothing to do")); + return; + } + __KTRACE_OPT(KUSB, Kern::Printf(" Setting new interface setting #%d", setting)); + InterfaceSetTeardown(ifcset); + InterfaceSetup(aIfc); + StatusNotify(static_cast(KUsbAlternateSetting | setting), ifcset->iClientId); + } + + +// aFunction gets called, successively, with the endpoint index of every ep in-use as its argument. +// (BTW: The declaration "type (class::*name)(params)" makes a "pointer to element function".) +// +TInt DUsbClientController::DoForEveryEndpointInUse(TInt (DUsbClientController::*aFunction)(TInt), TInt& aCount) + { + __KTRACE_OPT(KUSB, Kern::Printf("DUsbClientController::DoForEveryEndpointInUse()")); + aCount = 0; + TUsbcConfiguration* const config = CurrentConfig(); + if (!config) + { + __KTRACE_OPT(KUSB, Kern::Printf(" Device is not configured - returning")); + return KErrNone; + } + RPointerArray& ifcsets = config->iInterfaceSets; + const TInt num_ifcsets = ifcsets.Count(); + for (TInt i = 0; i < num_ifcsets; i++) + { + RPointerArray& eps = ifcsets[i]->CurrentInterface()->iEndpoints; + const TInt num_eps = eps.Count(); + for (TInt j = 0; j < num_eps; j++) + { + const TInt ep_num = EpAddr2Idx(eps[j]->iPEndpoint->iEndpointAddr); + const TInt result = (this->*aFunction)(ep_num); + ++aCount; + if (result != KErrNone) + { + return result; + } + } + } + return KErrNone; + } + + +// -eof-