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