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\usbcsc\d_usbcsc.cpp sl@0: // LDD for USB Device driver stack, using shared chunks: sl@0: // The channel object. sl@0: // sl@0: // sl@0: sl@0: /** sl@0: @file d_usbcsc.cpp sl@0: @internalTechnology sl@0: */ sl@0: sl@0: #include sl@0: #include "platform.h" sl@0: sl@0: /*****************************************************************************\ sl@0: * DUsbcScLogDevice * sl@0: * * sl@0: * Inherits from DLogicalDevice, the USB Shared Chunk LDD factory class * sl@0: * * sl@0: \*****************************************************************************/ sl@0: sl@0: _LIT(KUsbScLddName, "Usbcsc"); sl@0: sl@0: static const TInt KUsbRequestCallbackPriority = 2; sl@0: sl@0: /** Real entry point from the Kernel: return a new driver. sl@0: */ sl@0: DECLARE_STANDARD_LDD() sl@0: { sl@0: return new DUsbcScLogDevice; sl@0: } sl@0: sl@0: /** Create a channel on the device. sl@0: sl@0: @internalComponent sl@0: */ sl@0: TInt DUsbcScLogDevice::Create(DLogicalChannelBase*& aChannel) sl@0: { sl@0: aChannel = new DLddUsbcScChannel; sl@0: return aChannel ? KErrNone : KErrNoMemory; sl@0: } sl@0: sl@0: sl@0: DUsbcScLogDevice::DUsbcScLogDevice() sl@0: { sl@0: iParseMask = KDeviceAllowUnit; sl@0: iUnitsMask = 0xffffffff; // Leave units decision to the Controller sl@0: iVersion = TVersion(KUsbcScMajorVersion, KUsbcScMinorVersion, KUsbcScBuildVersion); sl@0: } sl@0: sl@0: sl@0: TInt DUsbcScLogDevice::Install() sl@0: { sl@0: // Only proceed if we have the Controller underneath us sl@0: if (!DUsbClientController::UsbcControllerPointer()) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf("LDD Install: USB Controller Not Present")); sl@0: return KErrGeneral; sl@0: } sl@0: return SetName(&KUsbScLddName); sl@0: } sl@0: sl@0: sl@0: // sl@0: // Return the USB controller capabilities. sl@0: // sl@0: void DUsbcScLogDevice::GetCaps(TDes8& aDes) const sl@0: { sl@0: TPckgBuf b; sl@0: b().version = iVersion; sl@0: Kern::InfoCopy(aDes, b); sl@0: } sl@0: sl@0: // End DUsbcScLogDevice sl@0: sl@0: /*****************************************************************************\ sl@0: * TUsbcScChunkInfo * sl@0: * * sl@0: * Where Chunk information is stored for the channel, and preseved for the * sl@0: * life of the chunk. * sl@0: * * sl@0: \*****************************************************************************/ sl@0: sl@0: void DfcChunkCleanup(TAny*); sl@0: sl@0: TUsbcScChunkInfo::TUsbcScChunkInfo(DLogicalDevice* aLdd) sl@0: : iChunk(NULL), sl@0: iCleanup((TDfcFn)&DfcChunkCleanup,this,Kern::SvMsgQue(),0), sl@0: iChunkMem(NULL), sl@0: iLdd(aLdd) sl@0: { sl@0: iPageNtz = (TInt8)__e32_find_ls1_32(Kern::RoundToPageSize(1)); sl@0: } sl@0: sl@0: TInt TUsbcScChunkInfo::CreateChunk(TInt aTotalSize) sl@0: { sl@0: // First, reserve an TUint of memory for each of pages needed to hold aTotalSize of memory. sl@0: // This will form the chunk map, so that we can look up the memory geometry. sl@0: iAllocatedSize = (aTotalSize>>iPageNtz)*sizeof(TUint); sl@0: iPhysicalMap = (TUint*) Kern::AllocZ(iAllocatedSize); sl@0: TInt r; sl@0: if (iPhysicalMap==NULL) sl@0: r = KErrNoMemory; sl@0: else sl@0: { sl@0: TChunkCreateInfo chunkInfo; sl@0: chunkInfo.iType = TChunkCreateInfo::ESharedKernelMultiple; sl@0: chunkInfo.iMaxSize = aTotalSize; sl@0: chunkInfo.iMapAttr = EMapAttrCachedMax; sl@0: chunkInfo.iOwnsMemory = EFalse; sl@0: chunkInfo.iDestroyedDfc = &iCleanup; sl@0: sl@0: TLinAddr chunkMem; sl@0: r = Kern::ChunkCreate(chunkInfo, iChunk, chunkMem, iChunkMapAttr); sl@0: iChunkMem = (TInt8*) chunkMem; sl@0: if (r==KErrNone) sl@0: iLdd->Open(); sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: sl@0: sl@0: // This method requests closing the chunk. sl@0: // Note that nothing may happen immediately, as something else may have the chunk open. sl@0: void TUsbcScChunkInfo::Close() sl@0: { sl@0: Kern::ChunkClose(iChunk); sl@0: } sl@0: sl@0: sl@0: TInt TUsbcScChunkInfo::ChunkAlloc(TInt aOffset, TInt aSize) sl@0: { sl@0: TUint pageMask = (~0)<>iPageNtz); rle>0; rle--, i++,physAddr+=pageSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("::phys offset 0x%x = 0x%x", sl@0: (aOffset>>iPageNtz)+i, (physAddr & pageMask) | ((rle>(TInt)rleMask)?(TInt)rleMask:rle))); sl@0: iPhysicalMap[(aOffset>>iPageNtz)+i] = (physAddr & pageMask) | ((rle>(TInt)rleMask)?(TInt)rleMask:rle); sl@0: } sl@0: } sl@0: } sl@0: else if (r==KErrNoMemory) sl@0: r = -KErrNoMemory; // Semi-expected error. sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: This method retrieves the physical address of a given offset into the Chunk, and returns sl@0: the length of contiguous physical memory from this point. sl@0: sl@0: @param aOffset the offset from the start of the chunk, to be queried. sl@0: @param aPhysical a pointer to a TPhysAddr, to be filled with the physical sl@0: address of the memory at the given offset. sl@0: sl@0: @returns the length of contiguous physical memory from the given offset. sl@0: */ sl@0: sl@0: TInt TUsbcScChunkInfo::GetPhysical(TInt aOffset, TPhysAddr* aPhysical) sl@0: { sl@0: // Use masks, to retrieve the two components from the physical map, we created of the memory. sl@0: TUint pageMask = (~0)<>iPageNtz]; sl@0: *aPhysical=(val & pageMask)+(aOffset & ~pageMask); sl@0: return ((val & ~pageMask)<ChunkCleanup(); sl@0: } sl@0: sl@0: sl@0: void TUsbcScChunkInfo::ChunkCleanup() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChunkInfo::ChunkCleanup()")); sl@0: TUint physAddr; sl@0: TInt length; sl@0: TInt offset = 0; sl@0: sl@0: // The part of the field used for the physical page address. sl@0: TUint pageMask = (~0)<>2); sl@0: sl@0: while (offset < records) sl@0: { sl@0: physAddr = iPhysicalMap[offset] & pageMask; sl@0: length = iPhysicalMap[offset] & rleMask; sl@0: sl@0: if (physAddr>0) sl@0: Epoc::FreePhysicalRam(physAddr, length); sl@0: sl@0: offset += (length>0)?length:1; sl@0: } sl@0: Kern::Free(iPhysicalMap); sl@0: sl@0: DLogicalDevice* ldd = iLdd; sl@0: delete this; sl@0: ldd->Close(NULL); sl@0: } sl@0: sl@0: TInt TUsbcScChunkInfo::New(TUsbcScChunkInfo*& aChunk, TInt aSize, DLogicalDevice* aLdd) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChunkInfo::New totalSize %d", aSize)); sl@0: sl@0: aChunk = new TUsbcScChunkInfo(aLdd); sl@0: if (aChunk==NULL) sl@0: { sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: TInt r = aChunk->CreateChunk(aSize); sl@0: if (r!=KErrNone) sl@0: { sl@0: delete aChunk; sl@0: aChunk=NULL; sl@0: return r; sl@0: } sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChunkInfo::New Created at 0x%x", aChunk->iChunkMem )); sl@0: return KErrNone; sl@0: } sl@0: sl@0: // End TUsbcScChunkInfo sl@0: sl@0: /*****************************************************************************\ sl@0: * TUsbcScBuffer * sl@0: * * sl@0: * Represents a buffer, within a chunk. Each buffers can be used by * sl@0: * differt endpoint on differnt alt settings * sl@0: * * sl@0: \*****************************************************************************/ sl@0: sl@0: sl@0: TInt TUsbcScBuffer::Construct(TInt aDirection, DLddUsbcScChannel* aLdd, TInt aBufferOffset, TInt aBufferEndOffset, TInt aMinReadSize, TInt aMaxPacketSize, TInt aMaxReadSize) sl@0: { sl@0: TInt r; sl@0: #ifdef _DEBUG sl@0: iSequence = aBufferOffset; // Initialized at this, so that each buffer starts with a diffrent sequence number sl@0: #endif sl@0: iMinReadSize = aMinReadSize; sl@0: TInt size = (aBufferEndOffset - aBufferOffset); sl@0: TInt pageSize = Kern::RoundToPageSize(1); sl@0: if (aMaxReadSize > 0) sl@0: iMaxReadSize = aMaxReadSize; sl@0: else sl@0: iMaxReadSize = pageSize + ((size/3) & ~(pageSize -1)); sl@0: iLdd = aLdd; sl@0: iDirection = aDirection; sl@0: iMode=0; sl@0: iChunkInfo = aLdd->iChunkInfo; sl@0: iChunkAddr = (TLinAddr) (aLdd->iChunkInfo->iChunkMem); //aChunkAddr; sl@0: sl@0: TInt headerSize = sizeof(TUsbcScTransferHeader)-4; // TransferHeader includes 4 bytes of data. sl@0: sl@0: sl@0: TUint maxAlignment; // Note: This is a mask for max Alignment, sl@0: sl@0: if (aMaxPacketSize) sl@0: { // EP0 packets are not DMAed, and so dont need ialignment. sl@0: iAlignMask = ~3; sl@0: maxAlignment = 3; sl@0: } sl@0: else sl@0: maxAlignment = 1023; // We don't know what the alignment requirement will be until enumeration, so assume worse case. sl@0: sl@0: iFirstPacket = aBufferOffset + sizeof(SUsbcScBufferHeader) + headerSize; sl@0: iFirstPacket = (iFirstPacket + maxAlignment) & ~maxAlignment; sl@0: sl@0: iBufferStart = (SUsbcScBufferHeader *) (iChunkAddr+aBufferOffset); sl@0: iBufferEnd = aBufferEndOffset; sl@0: sl@0: if ((iDirection&1)==KUsbcScOut) sl@0: iHead = iFirstPacket-headerSize;//aBufferOffset + sizeof(SUsbcScBufferHeader); sl@0: else sl@0: iSent = 0; sl@0: sl@0: iStalled=0; sl@0: iMaxPacketSize=0; sl@0: sl@0: r = iStatusList.Construct((aDirection==KUsbcScIn)?KUsbcScInRequests:KUsbcScOutRequests, iLdd->iClient); sl@0: if (!r) sl@0: { sl@0: iMaxPacketSize = aMaxPacketSize; // Indicates configured if ep0, otherwise not. sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: sl@0: void TUsbcScBuffer::CreateChunkBufferHeader() sl@0: { sl@0: if ((iDirection&1)==KUsbcScOut) sl@0: { sl@0: iBufferStart->iHead= iHead; sl@0: iBufferStart->iTail= iHead; // Initially no data! sl@0: iBufferStart->iBilTail=iHead; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: iHead 0x%x bufferHeader 0x%x", iHead,iBufferStart )); sl@0: sl@0: // Dont need to round here, as we will round it up on endpoint change. (configuration) sl@0: } sl@0: } sl@0: sl@0: /* sl@0: TUsbcScBuffer::StartEndpoint sl@0: sl@0: This method sets the nessesary paramenters to the buffer, for use for a particular endpoint. sl@0: sl@0: */ sl@0: void TUsbcScBuffer::StartEndpoint(TUsbcRequestCallback* aRequestInfo, TUint aFlags) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartEndpoint (0x%x) : ep %d(%d)",this,aRequestInfo->iEndpointNum, aRequestInfo->iRealEpNum)); sl@0: sl@0: iCallback=aRequestInfo; sl@0: iMaxPacketSize = iLdd->iController->EndpointPacketSize(iLdd, aRequestInfo->iRealEpNum); sl@0: iAlignMask = ~(((iMaxPacketSize+1) & 0xFFFFFFF8)-1); sl@0: iMode = aFlags; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartEndpoint : max Packets %d, mask 0x%x flags 0x%x", iMaxPacketSize, iAlignMask, iMode)); sl@0: if ((iDirection&1)==KUsbcScOut) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UsbcScOut\n")); sl@0: // Add dummy packet (doesnt have to be aligned, which avoids what if it changes issue) sl@0: // And Start next read. sl@0: iNeedsPacket=KEpIsStarting; sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: void TUsbcScBuffer::Destroy() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::Destroy()")); sl@0: Cancel(KErrCancel); sl@0: if (iLdd->iController && ((iDirection&1)==KUsbcScOut)) sl@0: { // Me must cancel reads to LDD to, an there will be no list for the callbacks to look into. sl@0: iLdd->iController->CancelReadBuffer(iLdd, iCallback->iRealEpNum); sl@0: } sl@0: iStatusList.Destroy(); sl@0: } sl@0: sl@0: sl@0: sl@0: TInt TUsbcScBuffer::StartDataRead() sl@0: { sl@0: if (!iMaxPacketSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataRead() - Not Configured")); sl@0: return KErrNone; sl@0: } sl@0: if (iStatusList.iState!=ENotRunning) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataRead() - Already Stated! (%d)",iStatusList.iState)); sl@0: return KErrNone; sl@0: } sl@0: sl@0: TInt maxLength; sl@0: TInt freeSpace; sl@0: TPhysAddr physAddr; sl@0: sl@0: // get next request sl@0: TUsbcScStatusElement* nextJob = iStatusList.Next(); sl@0: if (nextJob == NULL) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("No more jobs")); sl@0: if (iMode && KUsbScCoupledRead) sl@0: return KErrEof; sl@0: iStatusList.iState=EReadingAhead; sl@0: } sl@0: else sl@0: iStatusList.iState=EInProgress; sl@0: sl@0: TInt tail = iBufferStart->iTail; sl@0: TInt headerSize = sizeof(TUsbcScTransferHeader)-4; // TransferHeader includes 4 bytes of data. sl@0: maxLength = iChunkInfo->GetPhysical(iHead + headerSize, &physAddr); //returns all the bytes available after iHead + headerSize) sl@0: sl@0: __ASSERT_DEBUG(maxLength>0,Kern::Fault("TUsbcScBuffer::StartDataRead(", __LINE__)); sl@0: sl@0: sl@0: if (tail>iHead) // # # # H _ _ _ T # # # # sl@0: { sl@0: __KTRACE_OPT(KUSB,Kern::Printf("TUsbcScBuffer::StartDataRead() - tail 0x%x>head 0x%x, maxlength 0x%x", tail, iHead, maxLength)); sl@0: sl@0: freeSpace = (tail & iAlignMask) - (iHead +headerSize + (~iAlignMask+1) ); // Cant read right up to last buffer, or head/tail will cross. sl@0: sl@0: if (freeSpace iMaxReadSize) sl@0: maxLength = iMaxReadSize; sl@0: // else tail=iMinReadSize,Kern::Fault("TUsbcScBuffer::StartDataRead(", __LINE__)); sl@0: sl@0: TUint8* data = ((TUsbcScTransferHeader *) (iHead + iChunkAddr))->iData.b; sl@0: // set up callback stucture sl@0: sl@0: iCallback->SetRxBufferInfo(data, physAddr, iIndexArray, iSizeArray,maxLength); sl@0: TInt r; sl@0: // Go!! sl@0: r = iLdd->iController->SetupReadBuffer(*iCallback); sl@0: if (r!=KErrNone) sl@0: { sl@0: __KTRACE_OPT(KUSB,Kern::Printf("SetupReadBuffer Error: %d, RT %d",r, iStatusList.iState)); sl@0: iStatusList.Complete(r); sl@0: } sl@0: // After this, TUsbcScEndpoint::RequestCallback is called in a DFC. sl@0: // This in turn calls either TUsbcScBuffer::CompleteRead. sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: void TUsbcScBuffer::CompleteRead(TBool aStartNextRead) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::CompleteRead buff=%x",this)); sl@0: sl@0: // The first packet always contains the total #of bytes sl@0: const TInt byteCount = iCallback->iPacketSize[0]; sl@0: const TInt packetCount = iCallback->iRxPackets; sl@0: iCallback->iRxPackets=0; sl@0: TUint flags = 0; sl@0: sl@0: if (iCallback->iPacketSize[packetCount - 1] < (TUint) iMaxPacketSize) sl@0: flags = KUsbcScShortPacket; sl@0: sl@0: UpdateBufferList(byteCount, flags, aStartNextRead); sl@0: } sl@0: sl@0: sl@0: // This method "submits" the current transfer, and starts off the next read. sl@0: sl@0: void TUsbcScBuffer::UpdateBufferList(TInt aByteCount,TUint aFlags, TBool aStartNextRead) sl@0: { sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst aByteCount %d, flags 0x%x iHead 0x%x", aByteCount, aFlags, iHead)); sl@0: sl@0: TInt headerSize = sizeof(TUsbcScTransferHeader)-4; // TransferHeader includes 4 bytes of data. sl@0: TLinAddr dummy; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("iHead 0x%x headerSize 0x%x",iHead, headerSize)); sl@0: sl@0: // Find iNext sl@0: sl@0: TInt next = iHead + headerSize + aByteCount; // next unused byte in buffer. sl@0: TInt maxLength; sl@0: sl@0: // This may take a few loops before we settle on a value. sl@0: do sl@0: { sl@0: // round up. sl@0: next = (next + headerSize + ~iAlignMask) & iAlignMask; sl@0: maxLength = iChunkInfo->GetPhysical(next, &dummy); sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst next %x buffer end %x min-read: %x maxRun %x", next, iBufferEnd, iMinReadSize, maxLength)); sl@0: // At the end of the buffer - wrap it if needbe. sl@0: if ((TUint)(next + iMinReadSize) > iBufferEnd) sl@0: { sl@0: next = iFirstPacket; sl@0: continue; sl@0: } sl@0: // Not enough space, move onto next block. sl@0: if (maxLengthiHashId=59*(iLdd->iAlternateSetting+1)+iCallback->iRealEpNum; // Alt setting realated.... sl@0: header->iSequence=iSequence; sl@0: iSequence++; sl@0: #endif sl@0: header->iBytes=aByteCount; sl@0: header->iNext=next; sl@0: header->iAltSettingSeq=iLdd->iAsSeq; sl@0: header->iAltSetting=iLdd->iAlternateSetting; sl@0: header->iFlags=aFlags; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("We set next to 0x%x", next)); sl@0: sl@0: iStatusList.iState=ENotRunning; sl@0: if (next==iBufferStart->iTail) //or (othwise is as good as full) sl@0: { sl@0: iStalled=next; sl@0: } sl@0: else sl@0: { sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst StartRead?? ")); sl@0: TInt oldHead=iHead; sl@0: iHead = next; sl@0: sl@0: if ((aStartNextRead) && (StartDataRead() == KErrOverflow)) sl@0: { // Oh crumbs, set state as slalled. sl@0: if (oldHead != iBufferStart->iBilTail) sl@0: // If user has not read everything in the buffer sl@0: // then set up a stall, so that ldd get to be woken early sl@0: { sl@0: iStalled=next; sl@0: iHead=oldHead; sl@0: } sl@0: else // otherwise if everything is read sl@0: // no choice but to return what we have sl@0: { sl@0: iBufferStart->iHead = iHead; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: iBufferStart->iHead = next; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::UpdateBUfferLIst Compleating\n")); sl@0: } sl@0: // Complete userside sl@0: iStatusList.Complete(); sl@0: } sl@0: } sl@0: sl@0: void TUsbcScBuffer::PopStall() sl@0: { sl@0: if (iStalled==iBufferStart->iTail) sl@0: return; // Still stalled. sl@0: sl@0: if (iStalled!=-1) // If not Alt packet only stall sl@0: { sl@0: // pop off packet sl@0: iHead = iStalled; sl@0: } sl@0: iStalled=0; sl@0: // If Alt setting of the popped packet is different to now sl@0: // Add alt setting change packet. sl@0: sl@0: sl@0: if (StartDataRead() == KErrOverflow) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::PopStall Warning: Transfer was freed, but still no space!\n")); sl@0: } sl@0: sl@0: iBufferStart->iHead = iHead; sl@0: } sl@0: sl@0: sl@0: sl@0: void TUsbcScBuffer::StartDataWrite() sl@0: { sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataWrite()")); sl@0: TUsbcScStatusElement* nextJob = iStatusList.Next(); sl@0: TBool zlpReqd; sl@0: TInt length; sl@0: TUint start; sl@0: TUint8* startAddr; sl@0: TInt maxLength; sl@0: TPhysAddr physAddr; sl@0: TInt r; sl@0: if (!iMaxPacketSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataWrite() - Not Configured")); sl@0: return; sl@0: } sl@0: sl@0: if (nextJob == NULL) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataWrite() - No more jobs d=%d", iDirection)); sl@0: if (iDirection==KUsbcScBiIn) // assume this is EP0, if this is true. sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::StartDataWrite() Queue Read on EP0.")); sl@0: // Start other read again. sl@0: iLdd->iBuffers[iLdd->iEP0OutBuff].StartDataRead(); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if (iStatusList.iState==ENotRunning) sl@0: iSent=0; sl@0: iStatusList.iState=EInProgress; sl@0: sl@0: start = nextJob->iStart; sl@0: startAddr = (TUint8*) (start + ((TUint) (iChunkInfo->iChunkMem))); sl@0: sl@0: length = nextJob->iLength; sl@0: zlpReqd = (nextJob->iFlags & KUsbcScWriteFlagsZlp) !=0; sl@0: // get max read length sl@0: maxLength = iChunkInfo->GetPhysical( start, &physAddr); sl@0: sl@0: if (maxLength < length) sl@0: { sl@0: // modify request. sl@0: nextJob->iStart += maxLength; sl@0: nextJob->iLength -= maxLength; sl@0: // start this request. sl@0: iStatusList.iState=EFramgementInProgress; sl@0: zlpReqd=EFalse; sl@0: length = maxLength; sl@0: } sl@0: sl@0: if (iDirection==KUsbcScBiIn) // this is for EP0 sl@0: { sl@0: iLdd->iController->CancelReadBuffer(iLdd, iCallback->iRealEpNum); sl@0: iLdd->iBuffers[iLdd->iEP0OutBuff].iStatusList.iState=ENotRunning; sl@0: } sl@0: sl@0: iCallback->SetTxBufferInfo(startAddr, physAddr, length); sl@0: iCallback->iZlpReqd = zlpReqd; sl@0: r = iLdd->iController->SetupWriteBuffer(*iCallback); sl@0: if (r!=KErrNone) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("SetupWriteBUffer Error: %d",r)); sl@0: iStatusList.Complete(r); sl@0: } sl@0: } sl@0: sl@0: } sl@0: sl@0: void TUsbcScBuffer::CompleteWrite() sl@0: { sl@0: TInt error = iCallback->iError; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::CompleteWrite buff=%x, err=%d",this, error)); sl@0: iSent+= iCallback->iTxBytes; sl@0: sl@0: // More to send? sl@0: if (error || iStatusList.iState!=EFramgementInProgress) sl@0: { sl@0: // complete request with error (if one). sl@0: // Some data could have been transmitted, even with an error. sl@0: iStatusList.Complete(error); sl@0: } sl@0: sl@0: // Start next request, or next part of this one. sl@0: StartDataWrite(); sl@0: sl@0: } sl@0: sl@0: // Cancels the current request's callback. sl@0: // This is not to say it will cancel the actual operation, sl@0: // However it will cancel any further sections of the user perceived operation sl@0: // that are not yet started. sl@0: void TUsbcScBuffer::Cancel(TInt aErrorCode) sl@0: { sl@0: iStatusList.CancelQueued(); sl@0: if (iLdd->iController && ((iDirection&1)==KUsbcScIn)) sl@0: { sl@0: iLdd->iController->CancelWriteBuffer(iLdd, iCallback->iRealEpNum); sl@0: } sl@0: sl@0: iStatusList.Complete(aErrorCode); sl@0: } sl@0: sl@0: void TUsbcScBuffer::Ep0CancelLddRead() sl@0: { sl@0: // Stopping a read isn't as easy as one might think. sl@0: // We cancel the callback, but then check if any data was received (but not returned to us). sl@0: // If so, we must de-queue the request, and call the completion code. sl@0: sl@0: iLdd->iController->CancelReadBuffer(iLdd, iCallback->iRealEpNum); sl@0: if (iCallback->iRxPackets) // received data? sl@0: { sl@0: // remove DFC (if infact sent) sl@0: iCallback->iDfc.Cancel(); sl@0: sl@0: // process the callback now, but dont start another sl@0: CompleteRead(EFalse); sl@0: } sl@0: } sl@0: sl@0: void TUsbcScBuffer::SendEp0StatusPacket(TInt aState) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" TUsbcScBuffer::SendEp0StatusPacket(%d)", aState)); sl@0: sl@0: // We need to add a packet to the buffer, so we must stop the pending read, and start sl@0: // another after we have added out packet. sl@0: Ep0CancelLddRead(); sl@0: sl@0: TUint* state = ((TUsbcScTransferHeader *) (iHead + iChunkAddr))->iData.i; sl@0: *state = aState; sl@0: UpdateBufferList(4,KUsbcScStateChange); sl@0: } sl@0: sl@0: // End TUsbcScBuffer sl@0: sl@0: /*****************************************************************************\ sl@0: * TUsbcScStatusList * sl@0: * * sl@0: * This is a list of read or write requests, containing user status * sl@0: * requests, that should later be completed. * sl@0: * * sl@0: \*****************************************************************************/ sl@0: sl@0: /** sl@0: Constructor for TUsbcScStatusList. sl@0: sl@0: @param aSize is the number of requests to allow at any one time. This value sl@0: must be a power of two, for correct operation. sl@0: sl@0: @returns KErrNoMemory if memory allocation failure, otherwise KErrNone. sl@0: */ sl@0: sl@0: TInt TUsbcScStatusList::Construct(TInt aSize, DThread* aClient) sl@0: { sl@0: iSize=aSize; sl@0: iHead = 0; sl@0: iLength = 0; sl@0: iClient = aClient; sl@0: iElements=(TUsbcScStatusElement *) Kern::AllocZ(sizeof(TUsbcScStatusElement)*aSize); sl@0: return (iElements==NULL)?KErrNoMemory:KErrNone; sl@0: }; sl@0: sl@0: sl@0: // StatusList must be inactive before destroying. sl@0: void TUsbcScStatusList::Destroy() sl@0: { sl@0: if (iState!=ENotRunning) sl@0: Kern::Fault("TUsbcScStatusList::Destroy", __LINE__); sl@0: if (iElements) sl@0: { sl@0: Kern::Free(iElements); sl@0: iElements=NULL; sl@0: } sl@0: iClient=NULL; sl@0: } sl@0: sl@0: void TUsbcScStatusList::Pop() sl@0: { sl@0: if (iLength>0) sl@0: { sl@0: iLength--; sl@0: iHead = ((iHead+1) & (iSize-1)); sl@0: } sl@0: } sl@0: sl@0: TUsbcScStatusElement* TUsbcScStatusList::Next() sl@0: { sl@0: return (iLength==0)?NULL:&(iElements[iHead]); sl@0: } sl@0: sl@0: TInt TUsbcScStatusList ::Add(TRequestStatus* aStatus, TInt aLength, TUint aStart, TUint aFlags) sl@0: { sl@0: __KTRACE_OPT(KUSB,Kern::Printf("Adding request. iLength %d iSize %d", iLength, iSize)); sl@0: if (iLength0; elements2Complete--) sl@0: { sl@0: Kern::RequestComplete(iClient, iElements[head].iStatus, aError); sl@0: head = ((head+1) & (iSize-1)); sl@0: } sl@0: sl@0: } sl@0: sl@0: sl@0: /* This method Completes the head status request, and pops it from its list. sl@0: This version of Complete is to be used in cases where the next request is not sl@0: chained - usually because of an error. sl@0: sl@0: @Param aError - the code to complete with. sl@0: sl@0: returns KErrNotFound if there was no request to complete sl@0: */ sl@0: sl@0: sl@0: TInt TUsbcScStatusList::Complete(TInt aError) sl@0: { sl@0: if (iState==ENotRunning) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScStatusList::Complete() - iState == ENotRunning!")); sl@0: } sl@0: else sl@0: { sl@0: iState=ENotRunning; sl@0: if (iLength==0) sl@0: return KErrNotFound; sl@0: sl@0: Kern::RequestComplete(iClient, iElements[iHead].iStatus, aError); sl@0: sl@0: iLength--; sl@0: iHead = ((iHead+1) & (iSize-1)); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /* This method Completes the head status request, and pops it from its list. (If found.) sl@0: This version of Complete is to be used in cases where the request is successful, and sl@0: next request after this has (if present) been chained. sl@0: */ sl@0: sl@0: void TUsbcScStatusList::Complete() sl@0: { sl@0: if (iLength==0) sl@0: return; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Completing request. iLength %d", iLength)); sl@0: sl@0: Kern::RequestComplete(iClient, iElements[iHead].iStatus, KErrNone); sl@0: sl@0: iLength--; sl@0: iHead = ((iHead+1) & (iSize-1)); sl@0: } sl@0: sl@0: // End TUsbcScStatusList sl@0: sl@0: /*****************************************************************************\ sl@0: * TRealizeInfo * sl@0: * * sl@0: * Used by DLddUsbcScChannel::RealizeInterface to set up the chunk * sl@0: * * sl@0: \*****************************************************************************/ sl@0: sl@0: // Init sl@0: // sl@0: // This method works out the number potential maximum number of endpoints sl@0: // and the number of alt settings. With this information it allocs sl@0: // the necessary space for the given stucture to store information about sl@0: // the endpoints. sl@0: // This is intended to be called by RealizeInterface. This stucture is sl@0: // intended to be only temporary, and the space will be freed with Free() sl@0: // before RealizeInteface has finished. sl@0: sl@0: void TRealizeInfo::Init(TUsbcScAlternateSettingList* aAlternateSettingList) sl@0: { sl@0: iAlternateSettingList = aAlternateSettingList; sl@0: iMaxEndpoints=0; sl@0: iTotalSize =0; sl@0: iTotalBuffers=0; sl@0: iAltSettings =0; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: work out max endpoint")); sl@0: // Work out max endpoints and number of alternate settings. sl@0: sl@0: if (iAlternateSettingList) sl@0: { sl@0: TUsbcScAlternateSetting* alt = iAlternateSettingList->iHead; sl@0: while (alt != NULL) sl@0: { sl@0: iAltSettings++; sl@0: if (alt->iNumberOfEndpoints>iMaxEndpoints) sl@0: iMaxEndpoints = alt->iNumberOfEndpoints; sl@0: // could work out in/out specifics, but unnecessary. sl@0: alt = alt->iNext; sl@0: }; sl@0: } sl@0: sl@0: // Alloc some temporary working space for temp endpoint metadata sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: Alloc temp. Maxendpoints %d", iMaxEndpoints)); sl@0: TInt inout; sl@0: for (inout=KUsbcScIn; inoutiHead;alt!=NULL;alt = alt->iNext ) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: AlternateSetting %x", alt)); sl@0: sl@0: iBufs[KUsbcScIn].iEps =0; sl@0: iBufs[KUsbcScOut].iEps =0; sl@0: sl@0: // For alt setting, iterate eps sl@0: for (altEp=1; altEp <= alt->iNumberOfEndpoints; altEp++) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: Endpoint to add: %d",altEp)); sl@0: sl@0: TUsbcScEndpoint* nextEp = alt->iEndpoint[altEp]; sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: ep Buffer Size: %d",nextEp->EndpointInfo()->iBufferSize)); sl@0: sl@0: inout = (nextEp->EndpointInfo()->iDir==KUsbEpDirIn)?KUsbcScIn: sl@0: (nextEp->EndpointInfo()->iDir==KUsbEpDirOut)?KUsbcScOut:KUsbcScUnknown; sl@0: if (inout==KUsbcScUnknown) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: KUsbcScUnknown %x",nextEp->EndpointInfo()->iDir)); sl@0: return KErrArgument; sl@0: } sl@0: sl@0: bufsd = &(iBufs[inout]); sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: ep direction: %x # endpoints %d", inout, bufsd->iEps)); sl@0: sl@0: sl@0: // find and position ep, and insert. sl@0: sl@0: if (bufsd->iEps==0) // First entry. sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: Add first endpoint")); sl@0: endpointOffs = altSetting*iMaxEndpoints; sl@0: bufsd->iEp[endpointOffs] = nextEp; sl@0: } sl@0: else sl@0: { sl@0: placed = EFalse; sl@0: // Move down the list, until we find the right place. sl@0: for (endpoint=bufsd->iEps-1; endpoint>-1; endpoint--) sl@0: { sl@0: endpointOffs = altSetting*iMaxEndpoints + endpoint; sl@0: if (bufsd->iEp[endpointOffs]->EndpointInfo()->iBufferSize < nextEp->EndpointInfo()->iBufferSize) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: Shift Endpoint %d", endpoint)); sl@0: sl@0: bufsd->iEp[endpointOffs+1] = bufsd->iEp[endpointOffs]; sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: Insert After Endpoint %d", endpoint)); sl@0: sl@0: bufsd->iEp[endpointOffs+1] = nextEp; sl@0: placed = ETrue; sl@0: break; sl@0: } sl@0: } // end for endpoint sl@0: if (!placed) // if we didn't place it, it must be the biggest so far, so goes at the top. sl@0: bufsd->iEp[0] = nextEp; sl@0: } // endif sl@0: bufsd->iEps++; sl@0: } // for altEp sl@0: altSetting++; sl@0: } // for alt sl@0: }// if iAltsettingList sl@0: return KErrNone; sl@0: } sl@0: sl@0: // CalcBuffSizes sl@0: // sl@0: // This works out the sizes of all the buffers, and stores the result in aBufInfo sl@0: // based on the buffer information provided in the same structure. sl@0: // Realize_CopyAndSortEndpoints is used to fill the structure with the informaition sl@0: // required. sl@0: sl@0: void TRealizeInfo::CalcBuffSizes() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: Calculate Buffers")); sl@0: sl@0: TInt endpoint; sl@0: TInt inout; sl@0: TInt altSetting; sl@0: TUsbcScEndpoint* nextEp; sl@0: TInt bufferSize; sl@0: TEndpointSortBufs* bufsd; sl@0: sl@0: for (inout=KUsbcScIn; inoutiEp[altSetting* iMaxEndpoints + endpoint]; sl@0: if (nextEp!=NULL) sl@0: { sl@0: bufferSize = nextEp->EndpointInfo()->iBufferSize; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: comparing size %d", bufferSize)); sl@0: if (bufferSize> bufMaxSize) sl@0: bufMaxSize = bufferSize; sl@0: } sl@0: } // for altsetting sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: bufMaxSize %d", bufMaxSize)); sl@0: bufsd->iSizes[endpoint] = bufMaxSize; sl@0: if (bufMaxSize>0) sl@0: { sl@0: iTotalSize += bufsd->iSizes[endpoint]; sl@0: iTotalBuffers++; sl@0: } sl@0: } // for endpoint sl@0: } // for in/out sl@0: } sl@0: sl@0: // Free sl@0: // sl@0: // Cleans up after Init() sl@0: sl@0: void TRealizeInfo::Free() sl@0: { sl@0: TInt inout; sl@0: for (inout=KUsbcScIn; inoutiChunkMem; sl@0: sl@0: chkHdr->iBuffers = sizeof(TUsbcScChunkHdrOffs); // First struct just after this one. sl@0: iChunkStuct = (TUsbcScChunkBuffersHeader*) ( (TInt) aChunkInfo->iChunkMem + chkHdr->iBuffers); sl@0: sl@0: // Store number of buffers in chunk sl@0: iChunkStuct->iRecordSize = sizeof(TUsbcScBufferRecord); sl@0: iChunkStuct->iNumOfBufs=iTotalBuffers; sl@0: sl@0: iAltSettingsTbl = (TUsbcScChunkAltSettingHeader*) &(iChunkStuct->iBufferOffset[(iTotalBuffers+2)*sizeof(TUsbcScBufferRecord)]); // 2 extra for EP0 in and out. sl@0: sl@0: chkHdr->iAltSettings = (TUint) iAltSettingsTbl - (TUint) aChunkInfo->iChunkMem; sl@0: sl@0: iAltSettingsTbl->iEpRecordSize = sizeof(TUint); sl@0: iAltSettingsTbl->iNumOfAltSettings = iAltSettings; sl@0: sl@0: sl@0: TInt tableOffset = (TUint) iAltSettingsTbl->iAltTableOffset - (TUint) aChunkInfo->iChunkMem + iAltSettings*sizeof(TInt); sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: table offset: 0x%x, altTble %x iChnkMem %x altSettings %x",tableOffset, iAltSettingsTbl, aChunkInfo->iChunkMem, iAltSettings )); sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: populate chunk - create alt settings table")); sl@0: sl@0: // Create alt settings table. Set each element of altsettings table, to each induivatual alt setting table. sl@0: // then fill in the number of endpoints for that alt setting, in the table. sl@0: sl@0: TInt* noEpForAlt; sl@0: TInt altSetting; sl@0: TUsbcScAlternateSetting* alt; sl@0: if (iAlternateSettingList) sl@0: { sl@0: alt = iAlternateSettingList->iHead; sl@0: for (altSetting=0; altSettingiAltTableOffset[altSetting] = tableOffset; sl@0: noEpForAlt = (TInt*) &aChunkInfo->iChunkMem[tableOffset]; sl@0: sl@0: *noEpForAlt = alt->iNumberOfEndpoints; // Set NumberofEndpoints field in Altsetting table sl@0: tableOffset+= sizeof(TInt)+ alt->iNumberOfEndpoints*sizeof(TUsbcScHdrEndpointRecord); sl@0: alt = alt->iNext; sl@0: } sl@0: } sl@0: sl@0: } // end LayoutChunkHeader sl@0: sl@0: sl@0: sl@0: /*****************************************************************************\ sl@0: * DLddUsbcScChannel * sl@0: * * sl@0: * Inherits from DLogicalDevice, the USB Shared Chunk LDD factory class * sl@0: * * sl@0: \*****************************************************************************/ sl@0: sl@0: // sl@0: // Constructor sl@0: // sl@0: DLddUsbcScChannel::DLddUsbcScChannel() sl@0: : iValidInterface(EFalse), sl@0: iAlternateSettingList(NULL), sl@0: iEndpoint(NULL), sl@0: iCompleteAllCallbackInfo(this, DLddUsbcScChannel::EmergencyCompleteDfc, KUsbRequestCallbackPriority), sl@0: iStatusChangePtr(NULL), sl@0: iStatusCallbackInfo(this, DLddUsbcScChannel::StatusChangeCallback, KUsbRequestCallbackPriority), sl@0: iEndpointStatusChangePtr(NULL), sl@0: iEndpointStatusCallbackInfo(this, DLddUsbcScChannel::EndpointStatusChangeCallback, sl@0: KUsbRequestCallbackPriority), sl@0: iOtgFeatureChangePtr(NULL), sl@0: iOtgFeatureCallbackInfo(this, DLddUsbcScChannel::OtgFeatureChangeCallback, KUsbRequestCallbackPriority), sl@0: iNumberOfEndpoints(0), sl@0: iDeviceState(EUsbcDeviceStateUndefined), sl@0: iOwnsDeviceControl(EFalse), sl@0: iAlternateSetting(0), sl@0: iAsSeq(0), sl@0: iStatusFifo(NULL), sl@0: iUserKnowsAltSetting(ETrue), sl@0: iDeviceStatusNeeded(EFalse), sl@0: iChannelClosing(EFalse), sl@0: iRealizeCalled(EFalse), sl@0: iChunkInfo(NULL), sl@0: iNumBuffers(-1), sl@0: iBuffers(NULL), sl@0: iEp0Endpoint(NULL) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DLddUsbcScChannel()")); sl@0: iClient = &Kern::CurrentThread(); sl@0: iClient->Open(); sl@0: for (TInt i = 1; i < KUsbcMaxRequests; i++) sl@0: { sl@0: iRequestStatus[i] = NULL; sl@0: } sl@0: } sl@0: sl@0: sl@0: // sl@0: // Destructor sl@0: // sl@0: sl@0: DLddUsbcScChannel::~DLddUsbcScChannel() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::~DLddUsbcScChannel()")); sl@0: if (iController) sl@0: { sl@0: iStatusCallbackInfo.Cancel(); sl@0: iEndpointStatusCallbackInfo.Cancel(); sl@0: iOtgFeatureCallbackInfo.Cancel(); sl@0: iCompleteAllCallbackInfo.Cancel(); sl@0: DestroyAllInterfaces(); sl@0: if (iOwnsDeviceControl) sl@0: { sl@0: iController->ReleaseDeviceControl(this); sl@0: iOwnsDeviceControl = EFalse; sl@0: } sl@0: iController->DeRegisterClient(this); sl@0: iController=NULL; sl@0: DestroyEp0(); sl@0: if (iStatusFifo!=NULL) sl@0: { sl@0: delete iStatusFifo; sl@0: } sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Closing buffers")); sl@0: if (iBuffers) sl@0: { sl@0: TInt i; sl@0: for (i=0; i<(iNumBuffers+2); i++) sl@0: { sl@0: iBuffers[i].Destroy(); sl@0: } sl@0: Kern::Free(iBuffers); sl@0: } sl@0: sl@0: if (iRealizeCalled) sl@0: { sl@0: // Close Chunk sl@0: iChunkInfo->Close(); sl@0: // ChunkInfo will delete itself with DFC, but the pointer here is no longer needed. sl@0: iChunkInfo=NULL; sl@0: } sl@0: __KTRACE_OPT(KUSB, Kern::Printf("about to SafeClose")); sl@0: Kern::SafeClose((DObject*&)iClient, NULL); sl@0: } sl@0: sl@0: sl@0: // sl@0: // DoCreate - Create channel sl@0: // sl@0: sl@0: TInt DLddUsbcScChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("LDD DoCreateL 1 Ver = %02d %02d %02d", sl@0: aVer.iMajor, aVer.iMinor, aVer.iBuild)); sl@0: if (!Kern::CurrentThreadHasCapability(ECapabilityCommDD, sl@0: __PLATSEC_DIAGNOSTIC_STRING("Checked by USBCSC.LDD (USB Driver)"))) sl@0: { sl@0: return KErrPermissionDenied; sl@0: } sl@0: sl@0: iController = DUsbClientController::UsbcControllerPointer(); sl@0: sl@0: if (!iController) sl@0: { sl@0: return KErrGeneral; sl@0: } sl@0: sl@0: iStatusFifo = new TUsbcDeviceStatusQueue; sl@0: if (iStatusFifo == NULL) sl@0: { sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: if (!Kern::QueryVersionSupported(TVersion(KUsbcScMajorVersion, KUsbcScMinorVersion, KUsbcScBuildVersion), aVer)) sl@0: { sl@0: return KErrNotSupported; sl@0: } sl@0: sl@0: // set up the correct DFC queue sl@0: SetDfcQ(iController->DfcQ(0)); // sets the channel's dfc queue sl@0: iCompleteAllCallbackInfo.SetDfcQ(iDfcQ); sl@0: iStatusCallbackInfo.SetDfcQ(iDfcQ); // use the channel's dfcq for this dfc sl@0: iEndpointStatusCallbackInfo.SetDfcQ(iDfcQ); // use the channel's dfcq for this dfc sl@0: iOtgFeatureCallbackInfo.SetDfcQ(iDfcQ); sl@0: iMsgQ.Receive(); //start up the message q sl@0: TInt r = iController->RegisterClientCallback(iCompleteAllCallbackInfo); sl@0: if (r != KErrNone) sl@0: return r; sl@0: r = iController->RegisterForStatusChange(iStatusCallbackInfo); sl@0: if (r != KErrNone) sl@0: return r; sl@0: r = iController->RegisterForEndpointStatusChange(iEndpointStatusCallbackInfo); sl@0: if (r != KErrNone) sl@0: return r; sl@0: r = iController->RegisterForOtgFeatureChange(iOtgFeatureCallbackInfo); sl@0: if (r != KErrNone) sl@0: return r; sl@0: sl@0: return r; sl@0: } sl@0: // end DoCreate. sl@0: sl@0: sl@0: // sl@0: // HandleMsg sl@0: // sl@0: // Events from userside arrive here, and delegated to either DoRequest, DoControl or DoCancel. sl@0: // sl@0: sl@0: void DLddUsbcScChannel::HandleMsg(TMessageBase* aMsg) sl@0: { sl@0: TThreadMessage& m = *(TThreadMessage*)aMsg; sl@0: TInt id = m.iValue; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("HandleMsg 0x%x", id)); sl@0: sl@0: if (id == (TInt) ECloseMsg) sl@0: { sl@0: iChannelClosing = ETrue; sl@0: m.Complete(KErrNone, EFalse); sl@0: return; sl@0: } sl@0: sl@0: TInt r; sl@0: if (id < 0) sl@0: { sl@0: // DoRequest sl@0: TRequestStatus* pS = (TRequestStatus*) m.Ptr0(); sl@0: r = DoRequest(~id, pS, m.Ptr1(), m.Ptr2()); sl@0: m.Complete(r, ETrue); sl@0: } sl@0: else if (id & RDevUsbcScClient::ERequestCancel) sl@0: { sl@0: // DoCancel sl@0: r = DoCancel(id, (TUint) m.Ptr0(), (TUint) m.Ptr1()); sl@0: m.Complete(r, ETrue); sl@0: } sl@0: else sl@0: { sl@0: // DoControl sl@0: r = DoControl(id, m.Ptr0(), m.Ptr1()); sl@0: m.Complete(r, ETrue); sl@0: } sl@0: } sl@0: // end HandleMsg. sl@0: sl@0: sl@0: #define BREAK_IF_NULL_ARG(a,r) if (a==NULL) { r = KErrArgument; __KTRACE_OPT(KUSB,Kern::Printf("NULL Argument")); break; } sl@0: sl@0: // sl@0: // DoRequest - Asynchronous requests sl@0: // sl@0: // Overrides pure virtual, called by HandleMsg. (Above) sl@0: // sl@0: TInt DLddUsbcScChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) sl@0: { sl@0: TInt reqNo = aReqNo & RDevUsbcScClient::KFieldIdMask; sl@0: TInt r = KErrNone; // return via request notify sl@0: TBool needsCompletion =EFalse; sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DoRequest 0x%08x", aReqNo)); sl@0: sl@0: if ((reqNo>RDevUsbcScClient::ERequestReadDataNotify) && sl@0: (reqNo>RDevUsbcScClient::KFieldBuffPos)&RDevUsbcScClient::KFieldBuffMask; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("ERequestWriteData")); sl@0: BREAK_IF_NULL_ARG(a2,r); sl@0: sl@0: r = DoWriteData( aStatus, buffer, (TInt) a1 /*Start*/, (TInt) a2 /* Length */, sl@0: aReqNo>>RDevUsbcScClient::KFieldFlagsPos ); // Flags sl@0: break; sl@0: } sl@0: case RDevUsbcScClient::ERequestReadDataNotify: sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("ERequestReadDataNotify")); sl@0: return DoReadDataNotify(aStatus, (TInt) a1, (TInt) a2); // a1 = aBufferNumber, a2 - aLength; sl@0: } sl@0: sl@0: case RDevUsbcScClient::ERequestAlternateDeviceStatusNotify: sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("ERequestAlternateDeviceStatusNotify")); sl@0: BREAK_IF_NULL_ARG(a1,r); sl@0: iDeviceStatusNeeded = ETrue; sl@0: iStatusChangePtr = a1; sl@0: needsCompletion = AlternateDeviceStateTestComplete(); sl@0: break; sl@0: } sl@0: case RDevUsbcScClient::ERequestReEnumerate: sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("ERequestReEnumerate")); sl@0: // If successful, this will complete via the status notification. sl@0: r = iController->ReEnumerate(); sl@0: break; sl@0: } sl@0: case RDevUsbcScClient::ERequestEndpointStatusNotify: sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("ERequestEndpointStatusNotify")); sl@0: BREAK_IF_NULL_ARG(a1,r); sl@0: sl@0: iEndpointStatusChangePtr = a1; sl@0: break; sl@0: } sl@0: case RDevUsbcScClient::ERequestOtgFeaturesNotify: sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("ERequestOtgFeaturesNotify")); sl@0: BREAK_IF_NULL_ARG(a1,r); sl@0: sl@0: iOtgFeatureChangePtr = a1; sl@0: break; sl@0: } sl@0: default: sl@0: r = KErrNotSupported; sl@0: } sl@0: sl@0: if ((needsCompletion) || (r != KErrNone)) sl@0: { sl@0: iRequestStatus[reqNo] = aStatus; sl@0: Kern::RequestComplete(iClient, iRequestStatus[reqNo], r); sl@0: } sl@0: return KErrNone; sl@0: } sl@0: // end DoRequest. sl@0: sl@0: sl@0: // sl@0: // DoReadDataNotify sl@0: // sl@0: // This method sets up the request to facilitate the userside being notifed when new data has been read. sl@0: // sl@0: TInt DLddUsbcScChannel::DoReadDataNotify(TRequestStatus* aStatus, TInt aBufferNum, TInt aLength) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoReadDataNotify(x, %d, 0x%x)", aBufferNum, aLength)); sl@0: TInt r = KErrNone; sl@0: // check range sl@0: if ((aBufferNum<0) || (aBufferNum>=iNumBuffers)) // Indirectly checks that we are set up. sl@0: { sl@0: if (aBufferNum!=KUsbcScEndpointZero) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoReadDataNotify : Bad Buffer Number!")); sl@0: return KErrArgument; sl@0: } sl@0: else sl@0: { sl@0: aBufferNum = iEP0OutBuff; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // check direction sl@0: if (iBuffers[aBufferNum].iDirection!=KUsbcScOut) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoReadDataNotify : Bad Buffer Direction!")); sl@0: return KErrNotSupported; sl@0: } sl@0: if (!Configured()) sl@0: return KErrUsbInterfaceNotReady; sl@0: } sl@0: SUsbcScBufferHeader* scBuffer = (SUsbcScBufferHeader*) iBuffers[aBufferNum].iBufferStart; sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoReadDataNotify head %x tail %x", iBuffers[aBufferNum].iHead , scBuffer->iTail )); sl@0: sl@0: if (iBuffers[aBufferNum].iHead != scBuffer->iBilTail) sl@0: r = KErrCompletion; sl@0: else sl@0: if (iBuffers[aBufferNum].iStalled) sl@0: { sl@0: iBuffers[aBufferNum].PopStall(); sl@0: return KErrCompletion; sl@0: } sl@0: else sl@0: r = iBuffers[aBufferNum].iStatusList.Add(aStatus, aLength, 0,0); sl@0: sl@0: if (iBuffers[aBufferNum].iStatusList.iState==ENotRunning) sl@0: { sl@0: iBuffers[aBufferNum].StartDataRead(); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Job in Progress!")); sl@0: } sl@0: return r; sl@0: } sl@0: // end DoReadDataNotify. sl@0: sl@0: sl@0: sl@0: // sl@0: // DoWriteData sl@0: // sl@0: // This method sets up the request to write data to USB from userside. sl@0: // sl@0: TInt DLddUsbcScChannel::DoWriteData(TRequestStatus* aStatus,TInt aBufferNum, TUint aStart, TUint aLength, TUint aFlags) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoWriteData(%d, 0x%x, 0x%x, 0x%x)", aBufferNum, aStart, aLength, aFlags)); sl@0: if (!iUserKnowsAltSetting) sl@0: return KErrEof; sl@0: // Check Buffer Number sl@0: if ((aBufferNum<0) || (aBufferNum>=iNumBuffers)) sl@0: { sl@0: if ((TUint)aBufferNum!=RDevUsbcScClient::KFieldBuffMask) // KUsbcScEndpointZero & KFieldBuffMas = KFieldBuffMas; sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoWriteData : Bad Buffer Number!")); sl@0: return KErrArgument; sl@0: } sl@0: else sl@0: { sl@0: aBufferNum = iEP0InBuff; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // check direction sl@0: if (iBuffers[aBufferNum].iDirection!=KUsbcScIn) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoWriteData Bad endpoint Direction")); sl@0: return KErrArgument; sl@0: } sl@0: } sl@0: sl@0: TUsbcScBuffer& buf=iBuffers[aBufferNum]; sl@0: sl@0: if ((aStart< (((TLinAddr) buf.iBufferStart)-buf.iChunkAddr)) || ((aStart+aLength)>iBuffers[aBufferNum].iBufferEnd)) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DoWriteData Bad Range aStart or aLength 0x%x > 0x%x + 0x%x < 0x%x", (((TLinAddr) buf.iBufferStart)-buf.iChunkAddr),aStart, aLength, iBuffers[aBufferNum].iBufferEnd )); sl@0: return KErrArgument; sl@0: } sl@0: sl@0: if ( (aBufferNum != iEP0InBuff) && !Configured()) sl@0: return KErrUsbInterfaceNotReady; sl@0: sl@0: if (aStart & ~buf.iAlignMask) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScBuffer::DoDataWrite: address 0x%x unaligned.",aStart)); sl@0: return KErrArgument; sl@0: } sl@0: sl@0: TInt r = iBuffers[aBufferNum].iStatusList.Add(aStatus, aLength, aStart, aFlags); //update sl@0: sl@0: if (iBuffers[aBufferNum].iStatusList.iState==ENotRunning) sl@0: { sl@0: iBuffers[aBufferNum].StartDataWrite(); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Job in Progress!")); sl@0: } sl@0: sl@0: sl@0: return r; sl@0: } sl@0: // end DoWriteData. sl@0: sl@0: sl@0: // sl@0: // Cancel an outstanding request // Cancel need reworking. sl@0: // sl@0: TInt DLddUsbcScChannel::DoCancel(TInt aReqNo, TUint aBuff, TUint aSpair) sl@0: { sl@0: TInt r = KErrNone; sl@0: TInt direction=KUsbcScOut; sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DoCancel: 0x%x aBuff 0x%x", aReqNo, aBuff)); sl@0: switch (aReqNo) sl@0: { sl@0: case RDevUsbcScClient::ERequestCancel: sl@0: TInt buffer; sl@0: TInt mask; sl@0: sl@0: for (buffer=1, mask=1; bufferAbortTransfer(); sl@0: if (direction==KUsbcScIn) sl@0: aBuff=iEP0InBuff; sl@0: else sl@0: aBuff=iEP0OutBuff; sl@0: } sl@0: else if ((TInt)aBuff >= iNumBuffers) // check buff no range. sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Error: Bad buffer number")); sl@0: return KErrArgument; sl@0: } sl@0: sl@0: if ((iBuffers[aBuff].iDirection&1)!=direction) // Does direction match call type? sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Error: Bad buffer direction")); sl@0: return KErrArgument; sl@0: } sl@0: iBuffers[aBuff].iStatusList.CancelQueued(); sl@0: iBuffers[aBuff].Cancel(KErrCancel); sl@0: sl@0: return KErrNone; sl@0: sl@0: case RDevUsbcScClient::ERequestAlternateDeviceStatusNotifyCancel: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DoCancel: ERequestAlternateDeviceStatusNotify 0x%x", aReqNo)); sl@0: iDeviceStatusNeeded = EFalse; sl@0: iStatusFifo->FlushQueue(); sl@0: if (iStatusChangePtr) sl@0: { sl@0: TInt deviceState = iController->GetDeviceStatus(); sl@0: r = Kern::ThreadRawWrite(iClient, iStatusChangePtr, &deviceState, sizeof(deviceState), iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: iStatusChangePtr = NULL; sl@0: } sl@0: break; sl@0: sl@0: case RDevUsbcScClient::ERequestReEnumerateCancel: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestReEnumerate: 0x%x", aReqNo)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::ERequestEndpointStatusNotifyCancel: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestEndpointStatusNotify: 0x%x", aReqNo)); sl@0: CancelNotifyEndpointStatus(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::ERequestOtgFeaturesNotifyCancel: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DoCancel ERequestOtgFeaturesNotify: 0x%x", aReqNo)); sl@0: CancelNotifyOtgFeatures(); sl@0: break; sl@0: sl@0: default: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DoCancel Unknown! 0x%x", aReqNo)); sl@0: return KErrArgument; sl@0: } sl@0: sl@0: Kern::RequestComplete(iClient,iRequestStatus[aReqNo & ~RDevUsbcScClient::ERequestCancel], KErrCancel); sl@0: return r; sl@0: } sl@0: sl@0: sl@0: void DLddUsbcScChannel::CancelNotifyEndpointStatus() sl@0: { sl@0: if (iEndpointStatusChangePtr) sl@0: { sl@0: TUint epBitmap = 0; sl@0: for (TInt i = 1; i <= iNumberOfEndpoints; i++) sl@0: { sl@0: TInt v = iController->GetEndpointStatus(this, iEndpoint[i]->RealEpNumber()); sl@0: TUint b; sl@0: (v == EEndpointStateStalled) ? b = 1 : b = 0; sl@0: epBitmap |= b << i; sl@0: } sl@0: TInt r=Kern::ThreadRawWrite(iClient, iEndpointStatusChangePtr, (TUint8*) &epBitmap, sizeof(epBitmap), iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: iEndpointStatusChangePtr = NULL; sl@0: } sl@0: } sl@0: sl@0: void DLddUsbcScChannel::CancelNotifyOtgFeatures() sl@0: { sl@0: if (iOtgFeatureChangePtr) sl@0: { sl@0: TUint8 features; sl@0: iController->GetCurrentOtgFeatures(features); sl@0: TInt r=Kern::ThreadRawWrite(iClient, iOtgFeatureChangePtr, (TUint8*)&features, sizeof(features), iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: iOtgFeatureChangePtr = NULL; sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: // sl@0: // DoControl - Synchronous requests sl@0: // sl@0: // Called from HandleMsg. sl@0: sl@0: TInt DLddUsbcScChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DoControl: %d", aFunction)); sl@0: sl@0: TInt r = KErrNone; sl@0: TInt ep, param; sl@0: TUsbcScEndpoint* pEndpoint; sl@0: TPtrC8 pZeroDesc(NULL, 0); sl@0: TEndpointDescriptorInfo epInfo; sl@0: TUsbcScIfcInfo ifcInfo; sl@0: TCSDescriptorInfo desInfo; sl@0: TUsbcEndpointResource epRes; sl@0: sl@0: switch (aFunction) sl@0: { sl@0: case RDevUsbcScClient::EControlEndpointZeroRequestError: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointZeroRequestError")); sl@0: r = KErrNone; sl@0: if (iOwnsDeviceControl || (iValidInterface && iDeviceState == EUsbcDeviceStateConfigured)) sl@0: { sl@0: iController->Ep0Stall(this); sl@0: } sl@0: else sl@0: { sl@0: if (iDeviceState != EUsbcDeviceStateConfigured) sl@0: r = KErrUsbDeviceNotConfigured; sl@0: else sl@0: r = KErrUsbInterfaceNotReady; sl@0: } sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetAlternateSetting: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetAlternateSetting")); sl@0: if (iValidInterface && iDeviceState == EUsbcDeviceStateConfigured) sl@0: { sl@0: r = iController->GetInterfaceNumber(this, param); sl@0: if (r == KErrNone) sl@0: { sl@0: r = Kern::ThreadRawWrite(iClient, a1, ¶m, sizeof(param), iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if (iDeviceState != EUsbcDeviceStateConfigured) sl@0: r = KErrUsbDeviceNotConfigured; sl@0: else sl@0: r = KErrUsbInterfaceNotReady; sl@0: } sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlDeviceStatus: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceStatus")); sl@0: param = iController->GetDeviceStatus(); sl@0: r = Kern::ThreadRawWrite(iClient, a1, ¶m, sizeof(param), iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlEndpointStatus: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointStatus")); sl@0: if (iValidInterface && ValidEndpoint((TInt) a1)) sl@0: { sl@0: pEndpoint = iEndpoint[(TInt)a1]; sl@0: if (pEndpoint == NULL) sl@0: r = KErrNotSupported; sl@0: else sl@0: { sl@0: param = iController->GetEndpointStatus(this, iEndpoint[(TInt)a1]->RealEpNumber()); sl@0: r = Kern::ThreadRawWrite(iClient, a2, ¶m, sizeof(param), iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: } sl@0: } sl@0: else sl@0: { sl@0: if (iDeviceState != EUsbcDeviceStateConfigured) sl@0: r = KErrUsbDeviceNotConfigured; sl@0: else sl@0: r = KErrUsbInterfaceNotReady; sl@0: } sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlEndpointCaps: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointCaps")); sl@0: r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: iController->EndpointCaps(this, *((TDes8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlDeviceCaps: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceCaps")); sl@0: r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: iController->DeviceCaps(this, *((TDes8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSendEp0StatusPacket: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSendEp0StatusPacket")); sl@0: iController->SendEp0StatusPacket(this); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlHaltEndpoint: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlHaltEndpoint")); sl@0: if (iValidInterface && ValidEndpoint((TInt) a1)) sl@0: { sl@0: r = iController->HaltEndpoint(this, iEndpoint[(TInt)a1]->RealEpNumber()); sl@0: } sl@0: else sl@0: { sl@0: if (iDeviceState != EUsbcDeviceStateConfigured) sl@0: r = KErrUsbDeviceNotConfigured; sl@0: else sl@0: r = KErrUsbInterfaceNotReady; sl@0: } sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlClearHaltEndpoint: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlClearHaltEndpoint")); sl@0: if (iValidInterface && ValidEndpoint((TInt) a1)) sl@0: { sl@0: r = iController->ClearHaltEndpoint(this, iEndpoint[(TInt)a1]->RealEpNumber()); sl@0: } sl@0: else sl@0: { sl@0: if (iDeviceState != EUsbcDeviceStateConfigured) sl@0: r = KErrUsbDeviceNotConfigured; sl@0: else sl@0: r = KErrUsbInterfaceNotReady; sl@0: } sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlDumpRegisters: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlDumpRegisters")); sl@0: iController->DumpRegisters(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlReleaseDeviceControl: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlReleaseDeviceControl")); sl@0: iController->ReleaseDeviceControl(this); sl@0: iOwnsDeviceControl = EFalse; sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlEndpointZeroMaxPacketSizes: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlEndpointZeroMaxPacketSizes")); sl@0: r = iController->EndpointZeroMaxPacketSizes(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetEndpointZeroMaxPacketSize: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetEndpointZeroMaxPacketSize")); sl@0: r = iController->SetEndpointZeroMaxPacketSize(reinterpret_cast(a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetEndpointZeroMaxPacketSize: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointZeroMaxPacketSize")); sl@0: r = iController->Ep0PacketSize(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetDeviceDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceDescriptor")); sl@0: r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: r = iController->GetDeviceDescriptor(iClient, *((TDes8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetDeviceDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceDescriptor")); sl@0: BREAK_IF_NULL_ARG(a1,r); sl@0: r = iController->SetDeviceDescriptor(iClient, *((TDes8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetDeviceDescriptorSize: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceDescriptorSize")); sl@0: BREAK_IF_NULL_ARG(a1,r); sl@0: r = iController->GetDeviceDescriptorSize(iClient, *((TDes8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetConfigurationDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationDescriptor")); sl@0: r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0 , 0, iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: r = iController->GetConfigurationDescriptor(iClient, *((TDes8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetConfigurationDescriptorSize: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationDescriptorSize")); sl@0: if (a1 != NULL) sl@0: { sl@0: r = iController->GetConfigurationDescriptorSize(iClient, *((TDes8*) a1)); sl@0: } sl@0: else sl@0: r = KErrArgument; sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetConfigurationDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetConfigurationDescriptor")); sl@0: r = iController->SetConfigurationDescriptor(iClient, *((TDes8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetInterfaceDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetInterfaceDescriptor")); sl@0: r = iController->GetInterfaceDescriptor(iClient, this, (TInt) a1, *((TDes8*) a2)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetInterfaceDescriptorSize: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetInterfaceDescriptorSize")); sl@0: r = iController->GetInterfaceDescriptorSize(iClient, this, (TInt) a1, *(TDes8*) a2); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetInterfaceDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetInterfaceDescriptor")); sl@0: r = iController->SetInterfaceDescriptor(iClient, this, (TInt) a1, *((TDes8*) a2)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetEndpointDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointDescriptor")); sl@0: r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); sl@0: r = (ep<0)?ep:iController->GetEndpointDescriptor(iClient, this, epInfo.iSetting, sl@0: ep, *(TDes8*) epInfo.iArg); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetEndpointDescriptorSize: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetEndpointDescriptorSize")); sl@0: r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); sl@0: r = iController->GetEndpointDescriptorSize(iClient, this, epInfo.iSetting, sl@0: ep, *(TDes8*) epInfo.iArg); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetEndpointDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetEndpointDescriptor")); sl@0: r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); sl@0: r = iController->SetEndpointDescriptor(iClient, this, epInfo.iSetting, sl@0: ep, *(TDes8*)epInfo.iArg); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetDeviceQualifierDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetDeviceQualifierDescriptor")); sl@0: r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0, 0, iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: r = iController->GetDeviceQualifierDescriptor(iClient, *((TDes8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetDeviceQualifierDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceQualifierDescriptor")); sl@0: BREAK_IF_NULL_ARG(a1,r); sl@0: r = iController->SetDeviceQualifierDescriptor(iClient, *((TDes8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetOtherSpeedConfigurationDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetOtherSpeedConfigurationDescriptor")); sl@0: r = Kern::ThreadDesWrite(iClient, a1, pZeroDesc, 0 , 0, iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: r = iController->GetOtherSpeedConfigurationDescriptor(iClient, *((TDes8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetOtherSpeedConfigurationDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetOtherSpeedConfigurationDescriptor")); sl@0: r = iController->SetOtherSpeedConfigurationDescriptor(iClient, *((TDes8*) a1)); sl@0: break; sl@0: sl@0: sl@0: case RDevUsbcScClient::EControlGetCSInterfaceDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSInterfaceDescriptor")); sl@0: r = iController->GetCSInterfaceDescriptorBlock(iClient, this, (TInt) a1, *((TDes8*) a2)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetCSInterfaceDescriptorSize: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSInterfaceDescriptorSize")); sl@0: r = iController->GetCSInterfaceDescriptorBlockSize(iClient, this, (TInt) a1, *(TDes8*) a2); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetCSEndpointDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSEndpointDescriptor")); sl@0: r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); sl@0: r = iController->GetCSEndpointDescriptorBlock(iClient, this, epInfo.iSetting, sl@0: ep, *(TDes8*) epInfo.iArg); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetCSEndpointDescriptorSize: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetCSEndpointDescriptorSize")); sl@0: r = Kern::ThreadRawRead(iClient, a1, &epInfo, sizeof(epInfo)); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: ep = EpFromAlternateSetting(epInfo.iSetting, epInfo.iEndpoint); sl@0: r = iController->GetCSEndpointDescriptorBlockSize(iClient, this, epInfo.iSetting, sl@0: ep, *(TDes8*) epInfo.iArg); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSignalRemoteWakeup: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSignalRemoteWakeup")); sl@0: r = iController->SignalRemoteWakeup(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlDeviceDisconnectFromHost: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceDisconnectFromHost")); sl@0: r = iController->UsbDisconnect(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlDeviceConnectToHost: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlDeviceConnectToHost")); sl@0: r = iController->UsbConnect(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlDevicePowerUpUdc: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlDevicePowerUpUdc")); sl@0: r = iController->PowerUpUdc(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetDeviceControl: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceControl")); sl@0: r = iController->SetDeviceControl(this); sl@0: if (r == KErrNone) sl@0: { sl@0: iOwnsDeviceControl = ETrue; sl@0: if (iEp0Endpoint == NULL) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetDeviceControl")); sl@0: r = SetupEp0(); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: SetupEp0() failed")); sl@0: iController->ReleaseDeviceControl(this); sl@0: iOwnsDeviceControl=EFalse; sl@0: DestroyEp0(); sl@0: } sl@0: } sl@0: } sl@0: else sl@0: r = KErrInUse; sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlCurrentlyUsingHighSpeed: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlCurrentlyUsingHighSpeed")); sl@0: r = iController->CurrentlyUsingHighSpeed(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetInterface: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetInterface")); sl@0: r = Kern::ThreadRawRead(iClient, a2, &ifcInfo, sizeof(ifcInfo)); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: r = SetInterface((TInt) a1, &ifcInfo); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlReleaseInterface: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlReleaseInterface")); sl@0: if (!iRealizeCalled) sl@0: { sl@0: r = iController->ReleaseInterface(this, (TInt) a1); sl@0: if (r == KErrNone) sl@0: { sl@0: DestroyInterface((TUint) a1); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error in PIL: LDD interface won't be released.")); sl@0: } sl@0: } sl@0: else sl@0: r = KErrUsbAlreadyRealized; sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetCSInterfaceDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetCSInterfaceDescriptor")); sl@0: r = Kern::ThreadRawRead(iClient, a1, &desInfo, sizeof(desInfo)); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: r = iController->SetCSInterfaceDescriptorBlock(iClient, this, desInfo.iSetting, sl@0: *reinterpret_cast(desInfo.iArg), sl@0: desInfo.iSize); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetCSEndpointDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetCSEndpointDescriptor")); sl@0: r = Kern::ThreadRawRead(iClient, a1, &desInfo, sizeof(desInfo)); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: ep = EpFromAlternateSetting(desInfo.iSetting, desInfo.iEndpoint); sl@0: r = iController->SetCSEndpointDescriptorBlock(iClient, this, desInfo.iSetting, ep, sl@0: *reinterpret_cast(desInfo.iArg), sl@0: desInfo.iSize); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetStringDescriptorLangId: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetStringDescriptorLangId")); sl@0: r = iController->GetStringDescriptorLangId(iClient, *((TDes8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetStringDescriptorLangId: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetStringDescriptorLangId")); sl@0: r = iController->SetStringDescriptorLangId(reinterpret_cast(a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetManufacturerStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetManufacturerStringDescriptor")); sl@0: r = iController->GetManufacturerStringDescriptor(iClient, *((TPtr8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetManufacturerStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetManufacturerStringDescriptor")); sl@0: r = iController->SetManufacturerStringDescriptor(iClient, *((TPtr8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlRemoveManufacturerStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveManufacturerStringDescriptor")); sl@0: r = iController->RemoveManufacturerStringDescriptor(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetProductStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetProductStringDescriptor")); sl@0: r = iController->GetProductStringDescriptor(iClient, *((TPtr8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetProductStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetProductStringDescriptor")); sl@0: r = iController->SetProductStringDescriptor(iClient, *((TPtr8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlRemoveProductStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveProductStringDescriptor")); sl@0: r = iController->RemoveProductStringDescriptor(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetSerialNumberStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetSerialNumberStringDescriptor")); sl@0: r = iController->GetSerialNumberStringDescriptor(iClient, *((TPtr8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetSerialNumberStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetSerialNumberStringDescriptor")); sl@0: r = iController->SetSerialNumberStringDescriptor(iClient, *((TPtr8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlRemoveSerialNumberStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveSerialNumberStringDescriptor")); sl@0: r = iController->RemoveSerialNumberStringDescriptor(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetConfigurationStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetConfigurationStringDescriptor")); sl@0: r = iController->GetConfigurationStringDescriptor(iClient, *((TPtr8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetConfigurationStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetConfigurationStringDescriptor")); sl@0: r = iController->SetConfigurationStringDescriptor(iClient, *((TPtr8*) a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlRemoveConfigurationStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveConfigurationStringDescriptor")); sl@0: r = iController->RemoveConfigurationStringDescriptor(); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetStringDescriptor")); sl@0: r = iController->GetStringDescriptor(iClient, (TUint8) (TInt) a1, *((TPtr8*) a2)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlSetStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetStringDescriptor")); sl@0: r = iController->SetStringDescriptor(iClient, (TUint8) (TInt) a1, *((TPtr8*) a2)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlRemoveStringDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlRemoveStringDescriptor")); sl@0: r = iController->RemoveStringDescriptor((TUint8) (TInt) a1); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlAllocateEndpointResource: sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlAllocateEndpointResource")); sl@0: epRes = (TUsbcEndpointResource)((TInt) a2); sl@0: TInt realEp=-1; sl@0: r = GetRealEpForEpResource((TInt)a1, realEp); sl@0: if (r==KErrNone) sl@0: r = iController->AllocateEndpointResource(this, realEp, epRes); sl@0: break; sl@0: } sl@0: case RDevUsbcScClient::EControlDeAllocateEndpointResource: sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlDeAllocateEndpointResource")); sl@0: epRes = (TUsbcEndpointResource)((TInt) a2); sl@0: TInt realEp=-1; sl@0: r = GetRealEpForEpResource((TInt)a1, realEp); sl@0: if (r==KErrNone) sl@0: r = iController->DeAllocateEndpointResource(this, realEp, epRes); sl@0: break; sl@0: } sl@0: case RDevUsbcScClient::EControlQueryEndpointResourceUse: sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlQueryEndpointResourceUse")); sl@0: epRes = (TUsbcEndpointResource)((TInt) a2); sl@0: TInt realEp=-1; sl@0: r = GetRealEpForEpResource((TInt)a1, realEp); sl@0: if (r==KErrNone) sl@0: r = iController->QueryEndpointResource(this, realEp, epRes); sl@0: break; sl@0: } sl@0: case RDevUsbcScClient::EControlSetOtgDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlSetOtgDescriptor")); sl@0: r = iController->SetOtgDescriptor(iClient, *((const TDesC8*)a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetOtgDescriptor: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetOtgDescriptor")); sl@0: r = iController->GetOtgDescriptor(iClient, *((TDes8*)a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlGetOtgFeatures: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlGetOtgFeatures")); sl@0: r = iController->GetOtgFeatures(iClient, *((TDes8*)a1)); sl@0: break; sl@0: sl@0: case RDevUsbcScClient::EControlRealizeInterface: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlRealizeInterface")); sl@0: r = RealizeInterface(); sl@0: break; sl@0: case RDevUsbcScClient::EControlStartNextInAlternateSetting: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EControlStartNextInAlternateSetting")); sl@0: r = StartNextInAlternateSetting(); sl@0: break; sl@0: sl@0: default: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Function code not supported")); sl@0: r = KErrNotSupported; sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: // end DoControl. sl@0: sl@0: sl@0: sl@0: // sl@0: // Overriding DObject virtual sl@0: // sl@0: TInt DLddUsbcScChannel::RequestUserHandle(DThread* aThread, TOwnerType /*aType*/) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::RequestUserHandle")); sl@0: // The USB client LDD is not designed for a channel to be shared between sl@0: // threads. It saves a pointer to the current thread when it is opened, and sl@0: // uses this to complete any asynchronous requests. sl@0: // It is therefore not acceptable for the handle to be duplicated and used sl@0: // by another thread: sl@0: if (aThread == iClient) sl@0: { sl@0: return KErrNone; sl@0: } sl@0: else sl@0: { sl@0: return KErrAccessDenied; sl@0: } sl@0: } sl@0: sl@0: inline TInt DLddUsbcScChannel::GetRealEpForEpResource(TInt aEndpoint, TInt& aRealEp) sl@0: { sl@0: if (iEndpoint) // if we've enumerated at least once, proceed as normal. sl@0: { sl@0: if (aEndpoint <= iNumberOfEndpoints && aEndpoint >= 0) sl@0: { sl@0: aRealEp=iEndpoint[aEndpoint]->RealEpNumber(); sl@0: return KErrNone; sl@0: } sl@0: } sl@0: else // Assume alternate setting 0. sl@0: { sl@0: if (iAlternateSettingList) // Check it has been set up. sl@0: { sl@0: TUsbcScAlternateSetting* alt = iAlternateSettingList->iHead; sl@0: if (alt && (aEndpoint <= alt->iNumberOfEndpoints && aEndpoint >= 0)) sl@0: { sl@0: aRealEp= alt->iEndpoint[aEndpoint]->RealEpNumber(); sl@0: return KErrNone; sl@0: } sl@0: } sl@0: } sl@0: return KErrUsbDeviceNotConfigured; sl@0: } sl@0: sl@0: sl@0: TUsbcEndpointInfoArray::TUsbcEndpointInfoArray(const TUsbcScEndpointInfo* aData, TInt aDataSize) sl@0: { sl@0: iType = EUsbcScEndpointInfo; sl@0: iData = (TUint8*) aData; sl@0: if (aDataSize>0) sl@0: iDataSize = aDataSize; sl@0: else sl@0: iDataSize = sizeof(TUsbcScEndpointInfo); sl@0: } sl@0: sl@0: sl@0: // sl@0: // SetInterface sl@0: // sl@0: // Called from DoControl. Sets the configuration of a given Interface. // Needs changing sl@0: // All interfaces must be configured before one can be used. sl@0: // sl@0: sl@0: TInt DLddUsbcScChannel::SetInterface(TInt aInterfaceNumber, TUsbcScIfcInfo* aInfoBuf) sl@0: { sl@0: // Copy interface description. sl@0: sl@0: if (iRealizeCalled) sl@0: return KErrUsbAlreadyRealized; sl@0: sl@0: if (!iAlternateSettingList) sl@0: { sl@0: iAlternateSettingList = new TUsbcScAlternateSettingList; sl@0: if (iAlternateSettingList==NULL) sl@0: { sl@0: return KErrNoMemory; sl@0: } sl@0: } sl@0: sl@0: // Read descriptor in sl@0: TUsbcScInterfaceInfoBuf ifc_info_buf; sl@0: TUsbcScInterfaceInfoBuf* const ifc_info_buf_ptr = aInfoBuf->iInterfaceData; sl@0: const TInt srcLen = Kern::ThreadGetDesLength(iClient, ifc_info_buf_ptr); sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("SetInterface srcLen = %d len = %d", srcLen, ifc_info_buf.Length() )); sl@0: sl@0: if (srcLen < ifc_info_buf.Length()) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("SetInterface can't copy")); sl@0: PanicClientThread(EDesOverflow); sl@0: } sl@0: sl@0: TInt r = Kern::ThreadDesRead(iClient, ifc_info_buf_ptr, ifc_info_buf, 0, KChunkShiftBy0); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("SetInterface Copy failed reason=%d", r)); sl@0: PanicClientThread(r); sl@0: } sl@0: sl@0: // The list of endpoints is within the interface info. sl@0: TUsbcScEndpointInfo* pEndpointData = ifc_info_buf().iEndpointData; sl@0: sl@0: const TInt num_endpoints = ifc_info_buf().iTotalEndpointsUsed; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("SetInterface num_endpoints=%d", num_endpoints)); sl@0: if (num_endpoints>KMaxEndpointsPerClient) sl@0: return KErrOverflow; sl@0: sl@0: sl@0: // Initialize real ep numbers list. sl@0: TInt i; sl@0: TInt real_ep_numbers[KMaxEndpointsPerClient+1]; // range 1->KMaxEndpointsPerClient (0 not used) sl@0: for (i=0; i<=KMaxEndpointsPerClient; i++) sl@0: real_ep_numbers[i] = -1; sl@0: sl@0: sl@0: // See if PIL will accept this interface sl@0: __KTRACE_OPT(KUSB, Kern::Printf("SetInterface Calling controller")); sl@0: TUsbcEndpointInfoArray endpointData = TUsbcEndpointInfoArray(ifc_info_buf().iEndpointData); sl@0: sl@0: r = iController->SetInterface(this, sl@0: iClient, sl@0: aInterfaceNumber, sl@0: ifc_info_buf().iClass, sl@0: aInfoBuf->iString, sl@0: (TInt) ifc_info_buf().iTotalEndpointsUsed, sl@0: endpointData, sl@0: &real_ep_numbers[0], sl@0: ifc_info_buf().iFeatureWord); sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("SetInterface controller returned %d", r)); sl@0: if (r != KErrNone) sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf("SetInterface failed reason=%d", r)); sl@0: return r; sl@0: } sl@0: sl@0: // create alternate setting record sl@0: TUsbcScAlternateSetting* alternateSettingListRec = new TUsbcScAlternateSetting; sl@0: if (!alternateSettingListRec) sl@0: { sl@0: r = KErrNoMemory; sl@0: goto ReleaseInterface; sl@0: } sl@0: sl@0: // other endpoints sl@0: for (TInt i = 1; i <= num_endpoints; i++, pEndpointData++) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d", i)); sl@0: sl@0: if ((pEndpointData->iType==KUsbEpTypeControl) sl@0: || (pEndpointData->iDir != KUsbEpDirIn && pEndpointData->iDir != KUsbEpDirOut) sl@0: || (pEndpointData->iSize > 1024) || (pEndpointData->iSize<=0)) sl@0: { sl@0: r = KErrUsbBadEndpoint; sl@0: goto CleanUp; sl@0: } sl@0: // Check data sl@0: sl@0: TUint* bufferSize = &(pEndpointData->iBufferSize); sl@0: if (*bufferSize==0) sl@0: *bufferSize= KUsbcScDefaultBufferSize; sl@0: sl@0: TInt pageSize = Kern::RoundToPageSize(1); sl@0: // Round buffersize up to nearest pagesize. sl@0: *bufferSize = (*bufferSize+pageSize-1) & ~(pageSize-1); sl@0: sl@0: TUsbcScEndpoint* ep = new TUsbcScEndpoint(this, iController, pEndpointData, i); sl@0: alternateSettingListRec->iEndpoint[i] = ep; sl@0: if (!ep) sl@0: { sl@0: r = KErrNoMemory; sl@0: goto CleanUp; sl@0: } sl@0: if (ep->Construct() != KErrNone) sl@0: { sl@0: r = KErrNoMemory; sl@0: goto CleanUp; sl@0: } sl@0: sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("SetInterface for ep=%d rec=0x%08x ep==0x%08x", sl@0: i, alternateSettingListRec, ep)); sl@0: } sl@0: sl@0: if (iAlternateSettingList->iHead) sl@0: { sl@0: iAlternateSettingList->iTail->iNext = alternateSettingListRec; sl@0: alternateSettingListRec->iPrevious = iAlternateSettingList->iTail; sl@0: iAlternateSettingList->iTail = alternateSettingListRec; sl@0: } sl@0: else sl@0: { sl@0: iAlternateSettingList->iHead = alternateSettingListRec; sl@0: iAlternateSettingList->iTail = alternateSettingListRec; sl@0: } sl@0: sl@0: alternateSettingListRec->iNext = NULL; sl@0: alternateSettingListRec->iSetting = aInterfaceNumber; sl@0: alternateSettingListRec->iNumberOfEndpoints = num_endpoints; sl@0: sl@0: // Record the 'real' endpoint number used by the PDD in both the Ep and sl@0: // the Req callback: sl@0: for (TInt i = 1; i <= num_endpoints; i++) sl@0: { sl@0: alternateSettingListRec->iEndpoint[i]->SetRealEpNumber(real_ep_numbers[i]); sl@0: } sl@0: sl@0: return KErrNone; sl@0: sl@0: CleanUp: sl@0: delete alternateSettingListRec; sl@0: //Fall Through sl@0: sl@0: ReleaseInterface: sl@0: #if _DEBUG sl@0: TInt r1 = iController->ReleaseInterface(this, aInterfaceNumber); sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Release Interface controller returned %d", r1)); sl@0: #else sl@0: (void) iController->ReleaseInterface(this, aInterfaceNumber); sl@0: #endif sl@0: return r; sl@0: } sl@0: // end SetInterface sl@0: sl@0: sl@0: sl@0: #ifdef _DEBUG sl@0: void RealizeInterface_Dump(TUint* aMem) sl@0: { sl@0: TUint *mem= NULL; sl@0: __KTRACE_OPT(KUSB, mem = aMem); sl@0: if (mem!=NULL) sl@0: { sl@0: TInt j; sl@0: Kern::Printf("Final chunk header State:"); sl@0: for (j=0; j<30; j+=8) sl@0: Kern::Printf("%2x: %8x %8x %8x %8x %8x %8x %8x %8x", j, mem[j], mem[j+1], mem[j+2], mem[j+3], mem[j+4], mem[j+5], mem[j+6], mem[j+7] ); sl@0: }; sl@0: }; sl@0: #endif sl@0: sl@0: sl@0: /* sl@0: Chunk Created, filled with structure, and passed back to userside. sl@0: */ sl@0: TInt DLddUsbcScChannel::RealizeInterface(void) sl@0: { sl@0: if (iRealizeCalled) sl@0: return KErrUsbAlreadyRealized; sl@0: sl@0: TRealizeInfo bufInfo; sl@0: sl@0: TInt errorOrChunk = KErrNone; sl@0: TBool openedCS = EFalse; sl@0: TInt offset =0; sl@0: sl@0: // Start by creating a temporary scratchpad for endpoint calculations. sl@0: bufInfo.Init(iAlternateSettingList); sl@0: sl@0: // Fill in our scratchpad with all the required endpoints, sorting them sl@0: // in order of size required. sl@0: errorOrChunk = bufInfo.CopyAndSortEndpoints(); sl@0: if (errorOrChunk!=KErrNone) sl@0: { sl@0: goto realize_end; sl@0: } sl@0: sl@0: // We now have endpoints sorted in order of size for each altsetting. sl@0: // The very largest for each endpoint will share the first buffer, and all of sl@0: // the second largest ends points will share the second buffer, and so on. sl@0: // Find the highest buffer size for each row, to determine the buffer size, sl@0: // and keep a total of total space needed. sl@0: bufInfo.CalcBuffSizes(); sl@0: sl@0: // We now have the max sizes wanted for each endpoint buffer. sl@0: // we also have to total size for all endpoints. sl@0: // and finally we have the total number of buffers. sl@0: sl@0: // Add on size for header, then add on size for guard pages. sl@0: bufInfo.iTotalSize+= KHeaderSize + bufInfo.iTotalBuffers * KGuardSize; sl@0: sl@0: // Create shared Chunk . . . . . . . . . . sl@0: if (iChunkInfo==NULL) sl@0: { sl@0: NKern::ThreadEnterCS(); sl@0: openedCS = ETrue; sl@0: errorOrChunk = TUsbcScChunkInfo::New(iChunkInfo, bufInfo.iTotalSize, (DLogicalDevice*) iDevice); sl@0: if (errorOrChunk!=KErrNone) sl@0: { sl@0: goto realize_end; sl@0: } sl@0: } sl@0: else sl@0: { sl@0: // As of writing, the was no way for iChunk to be anything other then NULL. sl@0: // You cannot 'unrealise' and iChunk cannot be set any other way. sl@0: Kern::Fault("DLddUsbcScChannel::RealizeInterface", __LINE__); sl@0: } sl@0: sl@0: // Populate the shared chunk . . . . . . . sl@0: sl@0: sl@0: // First create chunk header. sl@0: errorOrChunk = iChunkInfo->ChunkAlloc(offset, KHeaderSize); sl@0: if (errorOrChunk!=KErrNone) sl@0: { sl@0: if (errorOrChunk==-KErrNoMemory) sl@0: errorOrChunk=KErrNoMemory; sl@0: goto realize_end; sl@0: } sl@0: sl@0: sl@0: offset+=KHeaderSize + KGuardSize; // Also any more for EP0? sl@0: sl@0: // Next, lay out the geometry of the chunk header. sl@0: sl@0: bufInfo.LayoutChunkHeader(iChunkInfo); sl@0: sl@0: sl@0: { // Scope ep0Size sl@0: TInt ep0Size=0; sl@0: sl@0: // Create K-side buffer table sl@0: if (!iBuffers) sl@0: iBuffers = (TUsbcScBuffer *) Kern::AllocZ(sizeof(TUsbcScBuffer) * (bufInfo.iTotalBuffers+2)); // +2 is for ep0. sl@0: if (!iBuffers) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: Error: Alloc iBufers failed!")); sl@0: errorOrChunk = KErrNoMemory; sl@0: goto realize_end; sl@0: } sl@0: sl@0: sl@0: errorOrChunk = SetupEp0(); sl@0: if (errorOrChunk) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: SetupEp0 . ERROR %d",errorOrChunk)); sl@0: goto realize_end; sl@0: } sl@0: sl@0: ep0Size = iEp0Endpoint->EndpointInfo()->iSize; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: Setup EP0. max packet size %d", ep0Size)); sl@0: sl@0: // Create EP0 buffers sl@0: iEP0OutBuff=bufInfo.iTotalBuffers; sl@0: errorOrChunk = iBuffers[iEP0OutBuff].Construct(KUsbcScBiOut, this, KUsbScEP0OutBufPos, KUsbScEP0OutBufEnd, ep0Size, ep0Size, ep0Size); sl@0: if (errorOrChunk) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: Setup EP0 Out. ERROR %d",errorOrChunk)); sl@0: goto realize_end; sl@0: } sl@0: sl@0: iBuffers[iEP0OutBuff].CreateChunkBufferHeader(); sl@0: iBuffers[iEP0OutBuff].iCallback = iEp0Endpoint->iRequestCallbackInfo; sl@0: ((TUsbcScBufferRecord*) &( sl@0: bufInfo.iChunkStuct->iBufferOffset[KUsbcScEp0OutBuff*sizeof(TUsbcScBufferRecord)] sl@0: )) ->Set(KUsbScEP0OutBufPos, KUsbScEP0OutBufEnd); sl@0: sl@0: sl@0: iEP0InBuff=bufInfo.iTotalBuffers+1; sl@0: errorOrChunk = iBuffers[iEP0InBuff].Construct( KUsbcScBiIn , this, KUsbScEP0InBufPos , KUsbScEP0InBufEnd , ep0Size, ep0Size, ep0Size); sl@0: if (errorOrChunk) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: Setup EP0 In. ERROR %d",errorOrChunk)); sl@0: goto realize_end; sl@0: } sl@0: sl@0: iBuffers[iEP0InBuff].iCallback = iEp0Endpoint->iRequestCallbackInfo; sl@0: sl@0: ((TUsbcScBufferRecord*) &( sl@0: bufInfo.iChunkStuct->iBufferOffset[KUsbcScEp0InBuff*sizeof(TUsbcScBufferRecord)] sl@0: ))->Set(KUsbScEP0InBufPos, KUsbScEP0InBufEnd); sl@0: sl@0: sl@0: } // end ep0Size scope sl@0: sl@0: // Create resources and tables. . . . . . sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: Create resources tables")); sl@0: sl@0: { // scope of bufNum sl@0: // For each EP buffer sl@0: TInt buffNum=0; sl@0: TInt buffMinSize; sl@0: TInt endpointNumber; sl@0: TUsbcScEndpoint* endpointRecord; sl@0: TInt endpoint; sl@0: TInt inout; sl@0: TEndpointSortBufs* bufsd; sl@0: TUsbcScHdrEndpointRecord* epRecord; sl@0: for (endpoint=0; endpointiEp[altSetting*bufInfo.iMaxEndpoints + endpoint]; sl@0: if (endpointRecord) sl@0: { sl@0: endpointNumber = endpointRecord->EpNumber(); sl@0: endpointRecord->SetBuffer(&iBuffers[buffNum]); sl@0: sl@0: epRecord = (TUsbcScHdrEndpointRecord*) &iChunkInfo->iChunkMem[ sl@0: (bufInfo.iAltSettingsTbl->iAltTableOffset[altSetting]) // i.e. Just after altSettingsTbl sl@0: +sizeof(TInt) // after number of endpoints field sl@0: +(endpointNumber-1)*sizeof(TUsbcScHdrEndpointRecord) sl@0: ]; sl@0: epRecord->iBufferNo = (TUint8) buffNum; sl@0: sl@0: TInt epType=(endpointRecord->EndpointInfo()->iType); sl@0: epType= (epType& KUsbEpTypeControl)?KUsbScHdrEpTypeControl: sl@0: (epType& KUsbEpTypeIsochronous)?KUsbScHdrEpTypeIsochronous: sl@0: (epType& KUsbEpTypeBulk)?KUsbScHdrEpTypeBulk: sl@0: (epType& KUsbEpTypeInterrupt)?KUsbScHdrEpTypeInterrupt:KUsbScHdrEpTypeUnknown; sl@0: sl@0: epRecord->iType = (inout+1) | (epType<<2); sl@0: sl@0: if (endpointRecord->EndpointInfo()->iReadSize) sl@0: maxReadSize = (maxReadSize <= endpointRecord->EndpointInfo()->iReadSize) ? maxReadSize : endpointRecord->EndpointInfo()->iReadSize; sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: endpointNum %d in altSetting %d, alt table @ %d", sl@0: endpointNumber, altSetting,bufInfo.iAltSettingsTbl->iAltTableOffset[altSetting])); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: endpointNum NA in altSetting %d", altSetting)); sl@0: } sl@0: sl@0: } // end for sl@0: sl@0: sl@0: // Alloc memory for buffer. sl@0: TInt grabSize = needed; sl@0: // Generally, a buffer fragmented into smaller memory regions will reduce the efficiency sl@0: // of reading or writing data, and so avoiding the allocation of very small sections sl@0: // is advantageous. sl@0: // However, if only a small amount is being allocated to start with, it is likely sl@0: // smaller amounts of data are to be sent (reducing this advantage), and 1 memory page sl@0: // is a much bigger proportion of the buffer, and so more worth allocating individually. sl@0: sl@0: TInt minimumGrab; sl@0: if (needed= minimumGrab) sl@0: { sl@0: TInt r; sl@0: r = iChunkInfo->ChunkAlloc(offset, grabSize); sl@0: if (r==KErrNone) sl@0: { sl@0: offset+=grabSize; sl@0: needed-=grabSize; sl@0: } sl@0: else sl@0: { sl@0: if (r==-KErrNoMemory) sl@0: { sl@0: grabSize>>=1; sl@0: } sl@0: if ((grabSizeiBufferOffset[(buffNum+2)*sizeof(TUsbcScBufferRecord)] sl@0: ))->Set(bufStart, offset); sl@0: sl@0: sl@0: // inc pointers for next buffer sl@0: buffNum++; sl@0: offset+=KGuardSize; sl@0: } // end if needed sl@0: sl@0: } // end for inout sl@0: } // end for each buffer sl@0: } // scope of bufNum sl@0: sl@0: #ifdef _DEBUG sl@0: RealizeInterface_Dump((TUint*) iChunkInfo->iChunkMem); // Debug only tracing sl@0: #endif sl@0: sl@0: realize_end: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: cleanup. Err=%d", errorOrChunk)); sl@0: // Here we clean up after either success, or after bailing out early. sl@0: sl@0: bufInfo.Free(); sl@0: sl@0: if (iChunkInfo) sl@0: { sl@0: if (errorOrChunk==KErrNone) sl@0: { sl@0: // Everything is looking good - create RChunk for Userside. sl@0: errorOrChunk = Kern::MakeHandleAndOpen(iClient, iChunkInfo->iChunk); sl@0: iRealizeCalled = (errorOrChunk>=0); sl@0: } // endif errorOrChunk sl@0: sl@0: if (errorOrChunk<0) // If error, destroy the chunk. sl@0: { sl@0: iChunkInfo->Close(); sl@0: // ChunkInfo will delete itself with DFC, but the pointer here is no longer needed. sl@0: iChunkInfo=NULL; sl@0: sl@0: // Destroy iBuffers sl@0: if (iBuffers) sl@0: { sl@0: TInt i; sl@0: for (i=0; i<(iNumBuffers+2); i++) sl@0: { sl@0: iBuffers[i].iStatusList.Destroy(); sl@0: } sl@0: Kern::Free(iBuffers); sl@0: iBuffers=NULL; sl@0: } sl@0: sl@0: } sl@0: else sl@0: { sl@0: iNumBuffers = bufInfo.iTotalBuffers; sl@0: iValidInterface = ETrue; // Let the games commence! sl@0: } sl@0: sl@0: } // endif iChunkInfo sl@0: if (openedCS) sl@0: NKern::ThreadLeaveCS(); sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Realize: returning %x (%d)", errorOrChunk, errorOrChunk)); sl@0: return errorOrChunk; sl@0: } // End RealizeInterface sl@0: sl@0: sl@0: // sl@0: // DestroyAllInterfaces sl@0: // sl@0: sl@0: void DLddUsbcScChannel::DestroyAllInterfaces() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DestroyAllInterfaces")); sl@0: // Removes all interfaces sl@0: if (iAlternateSettingList) sl@0: { sl@0: if (iAlternateSettingList->iHead != NULL) sl@0: { sl@0: TUsbcScAlternateSetting* alternateSettingListRec = iAlternateSettingList->iTail; sl@0: while (alternateSettingListRec) sl@0: { sl@0: iAlternateSettingList->iTail = alternateSettingListRec->iPrevious; sl@0: // If this contains NULL now that is only possible if the record to be deleted was at the head sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Release interface %d \n", alternateSettingListRec->iSetting)); sl@0: iController->ReleaseInterface(this, alternateSettingListRec->iSetting); sl@0: delete alternateSettingListRec; sl@0: if (iAlternateSettingList->iTail == NULL) //No more interfaces left sl@0: break; sl@0: else sl@0: { sl@0: iAlternateSettingList->iTail->iNext = NULL; sl@0: alternateSettingListRec = iAlternateSettingList->iTail; sl@0: } sl@0: } sl@0: } sl@0: delete iAlternateSettingList; sl@0: } sl@0: sl@0: iNumberOfEndpoints = 0; sl@0: iAlternateSettingList = NULL; sl@0: iValidInterface = EFalse; sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DestroyAllInterfaces done")); sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: sl@0: // sl@0: // DestroyInterface sl@0: // sl@0: sl@0: void DLddUsbcScChannel::DestroyInterface(TUint aInterfaceNumber) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DestroyInterface \n")); sl@0: sl@0: if (iAlternateSetting == aInterfaceNumber) sl@0: { sl@0: ResetInterface(KErrUsbInterfaceNotReady); sl@0: iValidInterface = EFalse; sl@0: iNumberOfEndpoints = 0; sl@0: } sl@0: if (iAlternateSettingList) sl@0: { sl@0: TUsbcScAlternateSetting* alternateSettingListRec = iAlternateSettingList->iTail; sl@0: TUsbcScAlternateSetting* alternateSettingListRecFound = NULL; sl@0: while (alternateSettingListRec) sl@0: { sl@0: if (alternateSettingListRec->iSetting == aInterfaceNumber) sl@0: { sl@0: alternateSettingListRecFound = alternateSettingListRec; sl@0: if (alternateSettingListRec->iPrevious == NULL) //Interface is at HEAD OF List, Should only be if Interface is also at Tail of list sl@0: { sl@0: iAlternateSettingList->iHead = alternateSettingListRec->iNext; // Should be NULL sl@0: if (alternateSettingListRec->iNext) sl@0: iAlternateSettingList->iHead->iPrevious = NULL; sl@0: } sl@0: else if (alternateSettingListRec->iNext == NULL) //Interface is at TAIL OF List sl@0: { sl@0: iAlternateSettingList->iTail = alternateSettingListRecFound->iPrevious; sl@0: iAlternateSettingList->iTail->iNext = NULL; sl@0: } sl@0: else //Somewhere in the middle (would not expect this in normal operation, but here for completeness) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DestroyInterface Middle interface!\n")); sl@0: alternateSettingListRec->iPrevious->iNext = alternateSettingListRec->iNext; sl@0: alternateSettingListRec->iNext->iPrevious = alternateSettingListRec->iPrevious; sl@0: } sl@0: sl@0: delete alternateSettingListRecFound; sl@0: break; sl@0: } sl@0: alternateSettingListRec = alternateSettingListRec->iPrevious; sl@0: } sl@0: } sl@0: } sl@0: sl@0: // sl@0: // SetupEp0 sl@0: // sl@0: sl@0: TInt DLddUsbcScChannel::SetupEp0() sl@0: { sl@0: __ASSERT_ALWAYS(iEp0Endpoint==NULL, Kern::Fault("DLddUsbcScChannel::SetupEp0", __LINE__)); sl@0: sl@0: TUsbcScEndpointInfo ep0Info = TUsbcScEndpointInfo(KUsbEpTypeControl, KUsbEpDirBidirect); sl@0: ep0Info.iSize = iController->Ep0PacketSize(); sl@0: sl@0: TUsbcScEndpoint* ep0 = new TUsbcScEndpoint(this, iController, &ep0Info, 0); sl@0: if (ep0 == NULL) sl@0: { sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: TInt r = ep0->Construct(); sl@0: if (r != KErrNone) sl@0: { sl@0: delete ep0; sl@0: return KErrNoMemory; sl@0: } sl@0: sl@0: ep0->SetRealEpNumber(0); sl@0: ep0->SetBuffer(NULL); // Cannot find it this way. sl@0: sl@0: iEp0Endpoint = ep0; sl@0: return KErrNone; sl@0: } sl@0: sl@0: // sl@0: // DestroyEp0 sl@0: // sl@0: sl@0: void DLddUsbcScChannel::DestroyEp0() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" DLddUsbcScChannel::DestroyEp0")); sl@0: delete iEp0Endpoint; sl@0: iEp0Endpoint = NULL; sl@0: } sl@0: sl@0: sl@0: void DLddUsbcScChannel::RequestCallbackEp0(TAny* aDLddUsbcScChannel) sl@0: { sl@0: DLddUsbcScChannel* channel = (DLddUsbcScChannel*) aDLddUsbcScChannel; sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::RequestCallbackEp0")); sl@0: sl@0: if (channel->ChannelClosing()) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Channel Closing: Completion not accepted!")); sl@0: return; sl@0: } sl@0: sl@0: switch (channel->iEp0Endpoint->iRequestCallbackInfo->iTransferDir) sl@0: { sl@0: case EControllerWrite: sl@0: channel->iBuffers[channel->iEP0InBuff].CompleteWrite(); sl@0: return; sl@0: case EControllerRead: sl@0: channel->iBuffers[channel->iEP0OutBuff].CompleteRead(); sl@0: return; sl@0: default: sl@0: Kern::Printf("DLddUsbcScChannel::RequestCallbackEp0 - Unexpected completion direction %d",channel->iEp0Endpoint->iRequestCallbackInfo->iTransferDir); sl@0: Kern::Fault("DLddUsbcScChannel::RequestCallbackEp0", __LINE__); sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: sl@0: sl@0: sl@0: // sl@0: // EndpointStatusChangeCallback sl@0: // sl@0: sl@0: void DLddUsbcScChannel::EndpointStatusChangeCallback(TAny* aDLddUsbcScChannel) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EndpointStatusChangeCallback")); sl@0: DLddUsbcScChannel* dUsbc = (DLddUsbcScChannel*) aDLddUsbcScChannel; sl@0: if (dUsbc->iChannelClosing) sl@0: return; sl@0: TUint endpointState = dUsbc->iEndpointStatusCallbackInfo.State(); sl@0: const TInt reqNo = (TInt) RDevUsbcScClient::ERequestEndpointStatusNotify; sl@0: if (dUsbc->iRequestStatus[reqNo]) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("EndpointStatusChangeCallback Notify status")); sl@0: DThread* client = dUsbc->iClient; sl@0: // set client descriptor length to zero sl@0: TInt r = Kern::ThreadRawWrite(client, dUsbc->iEndpointStatusChangePtr, &endpointState, sl@0: sizeof(TUint), client); sl@0: if (r != KErrNone) sl@0: dUsbc->PanicClientThread(r); sl@0: Kern::RequestComplete(dUsbc->iClient, dUsbc->iRequestStatus[reqNo], r); sl@0: dUsbc->iEndpointStatusChangePtr = NULL; sl@0: } sl@0: } sl@0: sl@0: sl@0: // sl@0: // StatusChangeCallback sl@0: // sl@0: sl@0: void DLddUsbcScChannel::StatusChangeCallback(TAny* aDLddUsbcScChannel) sl@0: { sl@0: DLddUsbcScChannel* dUsbc = (DLddUsbcScChannel*) aDLddUsbcScChannel; sl@0: if (dUsbc->iChannelClosing) sl@0: return; sl@0: sl@0: TUsbcDeviceState deviceState; sl@0: TInt i; sl@0: for (i = 0; sl@0: (i < KUsbcDeviceStateRequests) && ((deviceState = dUsbc->iStatusCallbackInfo.State(i)) != EUsbcNoState); sl@0: ++i) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("StatusChangeCallBack status=%d", deviceState)); sl@0: if (deviceState & KUsbAlternateSetting) sl@0: { sl@0: dUsbc->ProcessAlternateSetting(deviceState); sl@0: } sl@0: else sl@0: { sl@0: dUsbc->ProcessDeviceState(deviceState); sl@0: // Send Status to EP0 buffer. sl@0: dUsbc->iBuffers[dUsbc->iEP0OutBuff].SendEp0StatusPacket(deviceState); sl@0: } sl@0: sl@0: // Only queue if userside is interested sl@0: if (dUsbc->iDeviceStatusNeeded) sl@0: { sl@0: dUsbc->iStatusFifo->AddStatusToQueue(deviceState); sl@0: const TInt reqNo = (TInt) RDevUsbcScClient::ERequestAlternateDeviceStatusNotify; sl@0: if (dUsbc->AlternateDeviceStateTestComplete()) sl@0: Kern::RequestComplete(dUsbc->iClient, dUsbc->iRequestStatus[reqNo], KErrNone); sl@0: } sl@0: } sl@0: // We don't want to be interrupted in the middle of this: sl@0: const TInt irqs = NKern::DisableInterrupts(2); sl@0: dUsbc->iStatusCallbackInfo.ResetState(); sl@0: NKern::RestoreInterrupts(irqs); sl@0: } sl@0: sl@0: sl@0: void DLddUsbcScChannel::OtgFeatureChangeCallback(TAny* aDLddUsbcScChannel) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("OtgFeatureChangeCallback")); sl@0: DLddUsbcScChannel* dUsbc = (DLddUsbcScChannel*) aDLddUsbcScChannel; sl@0: if (dUsbc->iChannelClosing) sl@0: return; sl@0: sl@0: TUint8 features; sl@0: // No return value check. Assume OTG always supported here sl@0: dUsbc->iController->GetCurrentOtgFeatures(features); sl@0: sl@0: const TInt reqNo = (TInt) RDevUsbcScClient::ERequestOtgFeaturesNotify; sl@0: if (dUsbc->iRequestStatus[reqNo]) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("OtgFeatureChangeCallback Notify status")); sl@0: TInt r = Kern::ThreadRawWrite(dUsbc->iClient, dUsbc->iOtgFeatureChangePtr, sl@0: &features, sizeof(TUint8), dUsbc->iClient); sl@0: if (r != KErrNone) sl@0: dUsbc->PanicClientThread(r); sl@0: Kern::RequestComplete(dUsbc->iClient, dUsbc->iRequestStatus[reqNo], r); sl@0: dUsbc->iOtgFeatureChangePtr = NULL; sl@0: } sl@0: } sl@0: sl@0: sl@0: // sl@0: // SelectAlternateSetting sl@0: // sl@0: sl@0: TInt DLddUsbcScChannel::SelectAlternateSetting(TUint aAlternateSetting) sl@0: { sl@0: TUsbcScEndpoint* ep; sl@0: sl@0: // First, find the alt setting record, which corresponds to the alt setting number. sl@0: TUsbcScAlternateSetting* alternateSettingListRec; sl@0: if(iAlternateSettingList) sl@0: { sl@0: for (alternateSettingListRec = iAlternateSettingList->iHead; alternateSettingListRec; alternateSettingListRec = alternateSettingListRec->iNext) sl@0: if (alternateSettingListRec->iSetting == aAlternateSetting) sl@0: { sl@0: // Record has been located. sl@0: sl@0: // Update current ep setting vars sl@0: iEndpoint = alternateSettingListRec->iEndpoint; sl@0: iNumberOfEndpoints = alternateSettingListRec->iNumberOfEndpoints; sl@0: sl@0: sl@0: sl@0: // Reset buffers for new ep set sl@0: for (TInt i = 1; i <= KMaxEndpointsPerClient; i++) sl@0: { sl@0: ep = alternateSettingListRec->iEndpoint[i]; sl@0: if (ep!=NULL) sl@0: ep->StartBuffer(); // Buffer::StartEndpoint(...) sets the necessary parameters to the buffer, for use for a perticular endpoint. sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: } sl@0: return KErrGeneral; sl@0: } sl@0: sl@0: /* The user calls this to move into the next alternate setting. After this call, it is assumed the user wants to sl@0: Transmit using endpoints belonging to this alternate Setting. Writes to the IN endpoints will be allowed until sl@0: the host changed the alternate setting again sl@0: Returns a 32 int with the top 16 bits represents the sequance, and the botten, the alternatre setting no. sl@0: */ sl@0: TInt32 DLddUsbcScChannel::StartNextInAlternateSetting() sl@0: { sl@0: iUserKnowsAltSetting = ETrue; sl@0: return iAsSeq<<16 | iAlternateSetting; sl@0: } sl@0: sl@0: sl@0: // sl@0: // EpFromAlternateSetting sl@0: // sl@0: sl@0: TInt DLddUsbcScChannel::EpFromAlternateSetting(TUint aAlternateSetting, TInt aEndpoint) sl@0: { sl@0: TUsbcScAlternateSetting* alternateSettingListRec = iAlternateSettingList->iHead; sl@0: while (alternateSettingListRec) sl@0: { sl@0: if (alternateSettingListRec->iSetting == aAlternateSetting) sl@0: { sl@0: if ((aEndpoint <= alternateSettingListRec->iNumberOfEndpoints) && sl@0: (aEndpoint > 0)) sl@0: { sl@0: return alternateSettingListRec->iEndpoint[aEndpoint]->RealEpNumber(); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: aEndpoint %d wrong for aAlternateSetting %d", sl@0: aEndpoint, aAlternateSetting)); sl@0: return KErrNotFound; sl@0: } sl@0: } sl@0: alternateSettingListRec = alternateSettingListRec->iNext; sl@0: } sl@0: __KTRACE_OPT(KPANIC, Kern::Printf(" Error: no aAlternateSetting %d found", aAlternateSetting)); sl@0: return KErrNotFound; sl@0: } sl@0: sl@0: // sl@0: // ProcessAlternateSetting sl@0: // sl@0: sl@0: TInt DLddUsbcScChannel::ProcessAlternateSetting(TUint aAlternateSetting) sl@0: { sl@0: sl@0: TUint newSetting = aAlternateSetting&(~KUsbAlternateSetting); sl@0: __KTRACE_OPT(KUSB, Kern::Printf("ProcessAlternateSetting 0x%08x selecting alternate setting 0x%08x", aAlternateSetting, newSetting)); sl@0: iUserKnowsAltSetting=EFalse; sl@0: iAlternateSetting = newSetting; sl@0: iAsSeq++; sl@0: sl@0: ResetInterface(KErrUsbInterfaceChange); // kill any outstanding IN transfers sl@0: sl@0: TInt r = SelectAlternateSetting(newSetting); sl@0: if (r != KErrNone) sl@0: return r; sl@0: sl@0: sl@0: StartEpReads(); sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: // sl@0: // ProcessDeviceState sl@0: // sl@0: // Called from StatusChangeCallback. sl@0: sl@0: TInt DLddUsbcScChannel::ProcessDeviceState(TUsbcDeviceState aDeviceState) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::ProcessDeviceState(%d -> %d)", iDeviceState, aDeviceState)); sl@0: if (iDeviceState == aDeviceState) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" No state change => nothing to be done.")); sl@0: return KErrNone; sl@0: } sl@0: if (iDeviceState == EUsbcDeviceStateSuspended) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Coming out of Suspend: old state = %d", iOldDeviceState)); sl@0: iDeviceState = iOldDeviceState; sl@0: if (iDeviceState == aDeviceState) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" New state same as before Suspend => nothing to be done.")); sl@0: return KErrNone; sl@0: } sl@0: } sl@0: TBool renumerateState = (aDeviceState == EUsbcDeviceStateConfigured); sl@0: TBool deconfigured = EFalse; sl@0: TInt cancellationCode = KErrNone; sl@0: if (aDeviceState == EUsbcDeviceStateSuspended) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf(" Suspending...")); sl@0: iOldDeviceState = iDeviceState; sl@0: // Put PSL into low power mode here sl@0: } sl@0: else sl@0: { sl@0: deconfigured = (iDeviceState == EUsbcDeviceStateConfigured && sl@0: aDeviceState != EUsbcDeviceStateConfigured); sl@0: if (iDeviceState == EUsbcDeviceStateConfigured) sl@0: { sl@0: if (aDeviceState == EUsbcDeviceStateUndefined) sl@0: cancellationCode = KErrUsbCableDetached; sl@0: else if (aDeviceState == EUsbcDeviceStateAddress) sl@0: cancellationCode = KErrUsbDeviceNotConfigured; sl@0: else if (aDeviceState == EUsbcDeviceStateDefault) sl@0: cancellationCode = KErrUsbDeviceBusReset; sl@0: else sl@0: cancellationCode = KErrUsbDeviceNotConfigured; sl@0: } sl@0: } sl@0: iDeviceState = aDeviceState; sl@0: if (iValidInterface || iOwnsDeviceControl) sl@0: { sl@0: sl@0: // This LDD may not own an interface. It could be some manager reenumerating sl@0: // after its subordinate LDDs have setup their interfaces. sl@0: if (deconfigured) sl@0: { sl@0: DeConfigure(cancellationCode); sl@0: } sl@0: else if (renumerateState) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChannel:: Reumerated!")); sl@0: // Select main interface & latch in new endpoint set sl@0: SelectAlternateSetting(0); sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScChannel:: StartReads!")); sl@0: StartEpReads(); sl@0: } sl@0: } sl@0: sl@0: const TInt reqNo = (TInt) RDevUsbcScClient::ERequestReEnumerate; sl@0: if (renumerateState && iRequestStatus[reqNo]) sl@0: { sl@0: // This lot must be done if we are reenumerated sl@0: Kern::RequestComplete(iClient, iRequestStatus[reqNo], KErrNone); sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: TBool DLddUsbcScChannel::AlternateDeviceStateTestComplete() sl@0: { sl@0: TBool completeNow = EFalse; sl@0: const TInt reqNo = (TInt) RDevUsbcScClient::ERequestAlternateDeviceStatusNotify; sl@0: if (iRequestStatus[reqNo]) sl@0: { sl@0: // User req is outstanding sl@0: TUint32 deviceState; sl@0: if (iStatusFifo->GetDeviceQueuedStatus(deviceState) == KErrNone) sl@0: { sl@0: // Device state waiting to be sent userside sl@0: completeNow = ETrue; sl@0: __KTRACE_OPT(KUSB, Kern::Printf("StatusChangeCallback Notify status")); sl@0: // set client descriptor length to zero sl@0: TInt r = Kern::ThreadRawWrite(iClient, iStatusChangePtr, &deviceState, sl@0: sizeof(TUint32), iClient); sl@0: if (r != KErrNone) sl@0: PanicClientThread(r); sl@0: iStatusChangePtr = NULL; sl@0: } sl@0: } sl@0: return completeNow; sl@0: } sl@0: sl@0: sl@0: void DLddUsbcScChannel::DeConfigure(TInt aErrorCode) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DeConfigure()")); sl@0: // Called after deconfiguration. Cancels transfers on all endpoints. sl@0: ResetInterface(aErrorCode); sl@0: // Cancel the endpoint status notify request if it is outstanding. sl@0: const TInt KEpNotReq = RDevUsbcScClient::ERequestEndpointStatusNotify; sl@0: if (iRequestStatus[KEpNotReq]) sl@0: { sl@0: CancelNotifyEndpointStatus(); sl@0: Kern::RequestComplete(iClient, iRequestStatus[KEpNotReq], aErrorCode); sl@0: } sl@0: // We have to reset the alternate setting number when the config goes away. sl@0: SelectAlternateSetting(0); sl@0: iAlternateSetting = 0; sl@0: } sl@0: sl@0: sl@0: void DLddUsbcScChannel::StartEpReads() sl@0: { sl@0: // Queued after enumeration. Starts reads on all endpoints. sl@0: // The endpoint itself decides if it can do a read sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::StartEpReads - 1")); sl@0: sl@0: TInt i; sl@0: TInt8 needsPacket; sl@0: sl@0: for (i=0; iAbortTransfer(); sl@0: sl@0: // All OUT endpoints need a packet sent, to indicate the termination of the current ep 'pipe'. sl@0: // This will complete any current read, or will be read later. sl@0: // All IN endpoints must be simply cancelled, including anything queued. sl@0: // Ep0 operates outside alt settings, and so we don't cancel anything. sl@0: sl@0: buffer=iEndpoint[i]->GetBuffer(); sl@0: if (buffer->iDirection==KUsbcScIn) sl@0: { sl@0: buffer->iStatusList.Complete(KErrCancel); //aErrorCode sl@0: buffer->iStatusList.CancelQueued(); //aErrorCode sl@0: } sl@0: else sl@0: buffer->iNeedsPacket=TUsbcScBuffer::KEpIsEnding; // We will send a packet on re-start, which doubles as a 'cancel' sl@0: // for the old alt setting. sl@0: } sl@0: } sl@0: sl@0: sl@0: sl@0: void DLddUsbcScChannel::EmergencyCompleteDfc(TAny* aDLddUsbcScChannel) sl@0: { sl@0: ((DLddUsbcScChannel*) aDLddUsbcScChannel)->DoEmergencyComplete(); sl@0: } sl@0: sl@0: TInt DLddUsbcScChannel::DoEmergencyComplete() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("DLddUsbcScChannel::DoEmergencyComplete")); sl@0: // cancel any pending DFCs sl@0: // complete all client requests sl@0: sl@0: TUsbcScBuffer* buffer; sl@0: TInt i; sl@0: // Complete EP0 request sl@0: sl@0: TInt direction=iEp0Endpoint->iRequestCallbackInfo->iTransferDir; sl@0: if (direction==EControllerWrite) sl@0: { sl@0: iBuffers[iEP0InBuff].iStatusList.CancelQueued(); sl@0: iBuffers[iEP0InBuff].iStatusList.Complete(KErrDisconnected); sl@0: } sl@0: else if (direction==EControllerRead) sl@0: { sl@0: iBuffers[iEP0OutBuff].iStatusList.CancelQueued(); sl@0: iBuffers[iEP0OutBuff].iStatusList.Complete(KErrDisconnected); sl@0: } sl@0: sl@0: // Complete other Eps request sl@0: for (i = 1; i <= iNumberOfEndpoints; i++) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Cancelling transfer ep=%d", i)); sl@0: buffer=iEndpoint[i]->GetBuffer(); sl@0: buffer->iStatusList.CancelQueued(); sl@0: buffer->iStatusList.Complete(KErrDisconnected); sl@0: } sl@0: sl@0: // Complete remaining requests sl@0: sl@0: for (TInt i = 0; i < KUsbcMaxRequests; i++) sl@0: { sl@0: if (iRequestStatus[i]) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Complete request 0x%x", iRequestStatus[i])); sl@0: Kern::RequestComplete(iClient, iRequestStatus[i], KErrDisconnected); sl@0: } sl@0: } sl@0: iStatusCallbackInfo.Cancel(); sl@0: iEndpointStatusCallbackInfo.Cancel(); sl@0: iOtgFeatureCallbackInfo.Cancel(); sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: void DLddUsbcScChannel::PanicClientThread(TInt aReason) sl@0: { sl@0: Kern::ThreadKill(iClient, EExitPanic, aReason, KUsbLDDKillCat); sl@0: } sl@0: sl@0: // End DLddUsbcScChannel sl@0: sl@0: /*****************************************************************************\ sl@0: * TUsbcScEndpoint * sl@0: * * sl@0: * * sl@0: * * sl@0: \*****************************************************************************/ sl@0: sl@0: sl@0: // Constructor sl@0: TUsbcScEndpoint::TUsbcScEndpoint(DLddUsbcScChannel* aLDD, DUsbClientController* aController, sl@0: const TUsbcScEndpointInfo* aEndpointInfo, TInt aEndpointNum sl@0: ) sl@0: : iRequestCallbackInfo(NULL), sl@0: iController(aController), sl@0: iEndpointInfo(*aEndpointInfo), sl@0: iClientReadPending(EFalse), sl@0: iClientWritePending(EFalse), sl@0: iEndpointNumber(aEndpointNum), sl@0: iRealEpNumber(-1), sl@0: iLdd(aLDD), sl@0: iError(KErrNone), sl@0: iBytesTransferred(0), sl@0: iBuffer(NULL) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::TUsbcScEndpoint")); sl@0: } sl@0: sl@0: sl@0: TInt TUsbcScEndpoint::Construct() sl@0: { sl@0: __KTRACE_OPT(KUSB,Kern::Printf("TUsbcScEndpoint::TUsbcScEndpoint iEndpointNumber %d\n",iEndpointNumber)); sl@0: sl@0: iRequestCallbackInfo = new TUsbcRequestCallback(iLdd, sl@0: iEndpointNumber, sl@0: (iEndpointNumber==0)?DLddUsbcScChannel::RequestCallbackEp0:TUsbcScEndpoint::RequestCallback, sl@0: (iEndpointNumber==0)? (TAny*) iLdd: (TAny*) this, sl@0: iLdd->iDfcQ, sl@0: KUsbRequestCallbackPriority); sl@0: sl@0: return (iRequestCallbackInfo == NULL)?KErrNoMemory:KErrNone; sl@0: } sl@0: sl@0: sl@0: TUsbcScEndpoint::~TUsbcScEndpoint() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::~TUsbcScEndpoint(%d)", iEndpointNumber)); sl@0: AbortTransfer(); sl@0: delete iRequestCallbackInfo; sl@0: } sl@0: sl@0: // This is called by the PIL, on return from a read or write. sl@0: // Inturn it calls either the read or write function for that buffer. sl@0: sl@0: void TUsbcScEndpoint::RequestCallback(TAny* aTUsbcScEndpoint) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::RequestCallback")); sl@0: sl@0: if (((TUsbcScEndpoint*)aTUsbcScEndpoint)->iLdd->ChannelClosing()) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("Channel Closing: Completion not accepted!")); sl@0: return; sl@0: } sl@0: sl@0: switch (((TUsbcScEndpoint*) aTUsbcScEndpoint)->iRequestCallbackInfo->iTransferDir) sl@0: { sl@0: case EControllerWrite: sl@0: ((TUsbcScEndpoint*) aTUsbcScEndpoint)->iBuffer->CompleteWrite(); sl@0: return; sl@0: case EControllerRead: sl@0: ((TUsbcScEndpoint*) aTUsbcScEndpoint)->iBuffer->CompleteRead(); sl@0: return; sl@0: default: sl@0: Kern::Printf("TUsbcScEndpoint::RequestCallback - Unexpected compleation direction %d",((TUsbcScEndpoint*) aTUsbcScEndpoint)->iRequestCallbackInfo->iTransferDir); sl@0: Kern::Fault("TUsbcScEndpoint::RequestCallback", __LINE__); sl@0: } sl@0: } sl@0: sl@0: sl@0: /* sl@0: sl@0: This is used to tidy up cancel calls into the PIL, regardless of them being reads or writes sl@0: sl@0: */ sl@0: sl@0: void TUsbcScEndpoint::AbortTransfer() sl@0: { sl@0: if (!iLdd->iRealizeCalled) sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::AbortTransfer Ep# %d Real Ep # %d - N.R.",iEndpointNumber, iRealEpNumber)); sl@0: return; sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint::AbortTransfer Ep# %d Real Ep # %d",iEndpointNumber, iRealEpNumber)); sl@0: } sl@0: sl@0: sl@0: if (iBuffer && (iBuffer->iStatusList.iState) || (!iRealEpNumber)) sl@0: { sl@0: if (iRequestCallbackInfo->iTransferDir==EControllerWrite) sl@0: iController->CancelWriteBuffer(iLdd, iRealEpNumber); sl@0: else if (iRequestCallbackInfo->iTransferDir==EControllerRead) sl@0: iController->CancelReadBuffer(iLdd, iRealEpNumber); sl@0: else sl@0: { sl@0: if (iEndpointNumber!=0) // endpoint zero starts off not sent in any direction, then keeps changing. sl@0: { sl@0: __KTRACE_OPT(KUSB,Kern::Printf("\nTUsbcScEndpoint::AbortTransfer WARNING: Invalid Direction %d on (%d,%d)!\n",iRequestCallbackInfo->iTransferDir,iEndpointNumber, iRealEpNumber)); sl@0: } sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("\nTUsbcScEndpoint::AbortTransfer Can't stop direction %d on (%d,%d)!\n",iRequestCallbackInfo->iTransferDir,iEndpointNumber, iRealEpNumber)); sl@0: } sl@0: } sl@0: } sl@0: else if (!iBuffer) sl@0: { sl@0: __KTRACE_OPT(KUSB,Kern::Printf("\nTUsbcScEndpoint::AbortTransfer WARNING: iBuffer is NULL on (%d,%d)\n",iEndpointNumber, iRealEpNumber)); sl@0: return; sl@0: } sl@0: sl@0: if (iRequestCallbackInfo) sl@0: iRequestCallbackInfo->iDfc.Cancel(); sl@0: else sl@0: { sl@0: __KTRACE_OPT(KUSB,Kern::Printf("\nTUsbcScEndpoint::AbortTransfer WARNING: iRequestCallbackInfo is NULL\n")); sl@0: } sl@0: sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScEndpoint Done.")); sl@0: } sl@0: sl@0: // End TUsbcScEndpoint sl@0: sl@0: sl@0: /*****************************************************************************\ sl@0: * TUsbcScAlternateSettingList * sl@0: * * sl@0: * * sl@0: * * sl@0: \*****************************************************************************/ sl@0: sl@0: sl@0: TUsbcScAlternateSetting::TUsbcScAlternateSetting() sl@0: : iNext(NULL), sl@0: iPrevious(NULL), sl@0: iNumberOfEndpoints(0), sl@0: iSetting(0) sl@0: { sl@0: for (TInt i = 0; i <= KMaxEndpointsPerClient; i++) sl@0: { sl@0: iEndpoint[i] = NULL; sl@0: } sl@0: } sl@0: sl@0: sl@0: TUsbcScAlternateSetting::~TUsbcScAlternateSetting() sl@0: { sl@0: __KTRACE_OPT(KUSB, Kern::Printf("TUsbcScAlternateSetting::~TUsbcScAlternateSetting()")); sl@0: for (TInt i = 0; i <= KMaxEndpointsPerClient; i++) sl@0: { sl@0: delete iEndpoint[i]; sl@0: } sl@0: } sl@0: sl@0: // End TUsbcScAlternateSettingList sl@0: sl@0: sl@0: sl@0: TUsbcScAlternateSettingList::TUsbcScAlternateSettingList() sl@0: : iHead(NULL), sl@0: iTail(NULL) sl@0: { sl@0: } sl@0: sl@0: TUsbcScAlternateSettingList::~TUsbcScAlternateSettingList() sl@0: { sl@0: } sl@0: sl@0: sl@0: sl@0: /*****************************************************************************\ sl@0: * TUsbcDeviceStatusQueue * sl@0: * * sl@0: * * sl@0: * * sl@0: \*****************************************************************************/ sl@0: sl@0: sl@0: TUsbcDeviceStatusQueue::TUsbcDeviceStatusQueue() sl@0: { sl@0: FlushQueue(); sl@0: } sl@0: sl@0: sl@0: void TUsbcDeviceStatusQueue::FlushQueue() sl@0: { sl@0: for (TInt i = 0; i < KUsbDeviceStatusQueueDepth; i++) sl@0: { sl@0: iDeviceStatusQueue[i] = KUsbDeviceStatusNull; sl@0: } sl@0: iStatusQueueHead = 0; sl@0: } sl@0: sl@0: sl@0: void TUsbcDeviceStatusQueue::AddStatusToQueue(TUint32 aDeviceStatus) sl@0: { sl@0: // Only add a new status if it is not a duplicate of the one at the head of the queue sl@0: if (!(iStatusQueueHead != 0 && sl@0: iDeviceStatusQueue[iStatusQueueHead - 1] == aDeviceStatus)) sl@0: { sl@0: if (iStatusQueueHead == KUsbDeviceStatusQueueDepth) sl@0: { sl@0: // Discard item at tail of queue sl@0: TUint32 status; sl@0: GetDeviceQueuedStatus(status); sl@0: } sl@0: iDeviceStatusQueue[iStatusQueueHead] = aDeviceStatus; sl@0: iStatusQueueHead++; sl@0: } sl@0: } sl@0: sl@0: sl@0: TInt TUsbcDeviceStatusQueue::GetDeviceQueuedStatus(TUint32& aDeviceStatus) sl@0: { sl@0: TInt r = KErrNone; sl@0: if (iStatusQueueHead <= 0) sl@0: { sl@0: r = KErrGeneral; sl@0: aDeviceStatus = KUsbDeviceStatusNull; sl@0: } sl@0: else sl@0: { sl@0: aDeviceStatus = iDeviceStatusQueue[0]; sl@0: for(TInt i = 1; i < KUsbDeviceStatusQueueDepth; i++) sl@0: { sl@0: TUint32 s = iDeviceStatusQueue[i]; sl@0: iDeviceStatusQueue[i - 1] = s; sl@0: } sl@0: iStatusQueueHead--; sl@0: iDeviceStatusQueue[KUsbDeviceStatusQueueDepth - 1] = KUsbDeviceStatusNull; sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: // End TUsbcDeviceStatusQueue sl@0: sl@0: //--- sl@0: