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