# HG changeset patch # User Dremov Kirill (Nokia-D-MSW/Tampere) # Date 1271254979 -10800 # Node ID 1df514389a47a51796dc3e628c081ec5a851b8fb # Parent 2f92ad2dc5db2071d84cadfefc69e052fa64f472 Revision: 201015 Kit: 201015 diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/debug/crashMonitor/inc/scmdatasave.h --- a/kernel/eka/debug/crashMonitor/inc/scmdatasave.h Wed Mar 31 23:38:45 2010 +0300 +++ b/kernel/eka/debug/crashMonitor/inc/scmdatasave.h Wed Apr 14 17:22:59 2010 +0300 @@ -43,6 +43,7 @@ _LIT8(KKernelHeapChunkName, "ekern.exe::SvHeap"); +_LIT8(KKernelProcessName, "ekern.exe"); /** diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/debug/crashMonitor/src/scmdatasave.cpp --- a/kernel/eka/debug/crashMonitor/src/scmdatasave.cpp Wed Mar 31 23:38:45 2010 +0300 +++ b/kernel/eka/debug/crashMonitor/src/scmdatasave.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -978,11 +978,11 @@ { LOG_CONTEXT - //Get Chunk object container - DObjectCon* objectContainer = Kern::Containers()[EChunk]; + //Get process object container + DObjectCon* objectContainer = Kern::Containers()[EProcess]; if(objectContainer == NULL) { - CLTRACE("\tFailed to get object container for the chunks"); + CLTRACE("\tFailed to get object container for the processes"); return KErrNotFound; } @@ -995,7 +995,39 @@ TInt numObjects = objectContainer->Count(); - for(TInt cnt = 0; cnt< numObjects; cnt ++) + DProcess* kernelProcess = NULL; + for(TInt cnt = 0; cnt < numObjects; cnt ++) + { + DProcess* candidateProcess = (DProcess*)(*objectContainer)[cnt]; + + //Get the objects name + TBuf8 name; + candidateProcess->TraceAppendFullName(name,EFalse); + if(name == KKernelProcessName) + { + kernelProcess = candidateProcess; + } + } + if (!kernelProcess) + return KErrNotFound; + + //Get chunk object container + objectContainer = Kern::Containers()[EChunk]; + if(objectContainer == NULL) + { + CLTRACE("\tFailed to get object container for the chunks"); + return KErrNotFound; + } + + //Must check the mutex on this is ok otherwise the data will be in an inconsistent state + if(objectContainer->Lock()->iHoldCount) + { + CLTRACE("\tChunk Container is in an inconsistant state"); + return KErrCorrupt; + } + + numObjects = objectContainer->Count(); + for(TInt cnt = 0; cnt < numObjects; cnt ++) { DChunk* candidateHeapChunk = (DChunk*)(*objectContainer)[cnt]; @@ -1005,14 +1037,8 @@ if(name == KKernelHeapChunkName) { - #ifndef __MEMMODEL_FLEXIBLE__ - aHeapLocation = (TInt32)candidateHeapChunk->iBase; - #else - aHeapLocation = (TInt32)candidateHeapChunk->iFixedBase; - #endif - - aHeapSize = candidateHeapChunk->iSize; - + aHeapLocation = (TInt32)candidateHeapChunk->Base(kernelProcess); + aHeapSize = candidateHeapChunk->iSize; return KErrNone; } } diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/dma/dmapil.cpp --- a/kernel/eka/drivers/dma/dmapil.cpp Wed Mar 31 23:38:45 2010 +0300 +++ b/kernel/eka/drivers/dma/dmapil.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -491,20 +491,20 @@ *iChannel.iNullPtr = iFirstHdr; iChannel.iNullPtr = &(iLastHdr->iNext); iChannel.DoQueue(*this); + __DMA_INVARIANT(); iChannel.Signal(); } else { // Someone is cancelling all requests... req_count = --iChannel.iQueuedRequests; + __DMA_INVARIANT(); iChannel.Signal(); if (req_count == 0) { iChannel.QueuedRequestCountChanged(); } } - - __DMA_INVARIANT(); } EXPORT_C TInt DDmaRequest::ExpandDesList(TInt aCount) @@ -574,7 +574,15 @@ void DDmaRequest::Invariant() { - iChannel.Wait(); + // This invariant may be called either with, + // or without the channel lock already held + TBool channelLockAquired=EFalse; + if(!iChannel.iLock.HeldByCurrentThread()) + { + iChannel.Wait(); + channelLockAquired = ETrue; + } + __DMA_ASSERTD(iChannel.IsOpened()); __DMA_ASSERTD(0 <= iMaxTransferSize); __DMA_ASSERTD(0 <= iDesCount && iDesCount <= iChannel.iMaxDesCount); @@ -588,7 +596,11 @@ __DMA_ASSERTD(iChannel.iController->IsValidHdr(iFirstHdr)); __DMA_ASSERTD(iChannel.iController->IsValidHdr(iLastHdr)); } - iChannel.Signal(); + + if(channelLockAquired) + { + iChannel.Signal(); + } } #endif diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdescriptors/base_drivers_usbdescriptors.mrp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/base_drivers_usbdescriptors.mrp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,12 @@ +# component name "USB Descriptors" + +component base_drivers_usbdescriptors + +source \sf\os\kernelhwsrv\kernel\eka\drivers\usbho\usbdescriptors + +binary \sf\os\kernelhwsrv\kernel\eka\drivers\usbho\usbdescriptors all + +notes_source \component_defs\release.src + +ipr E + diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdescriptors/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/bld.inf Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,46 @@ +// Copyright (c) 2010 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/usbho/usbdescriptors/bld.inf +// +// + +/** + @file +*/ + + +PRJ_PLATFORMS + +ARMV5 ARMV5SMP + + +PRJ_MMPFILES + +#ifndef GCCXML +#if defined(GENERIC_MARM) || !defined(WINS) || defined(GENERIC_X86) +#if !defined(MARM_THUMB) && !defined(MARM_ARMI) + +#if !defined(WINS) +#if !defined(X86) +#if defined(SYMBIAN_ENABLE_USB_OTG_HOST) + +usbdescriptors + +#endif +#endif +#endif + +#endif +#endif +#endif diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdescriptors/usbdescparser.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescparser.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,370 @@ +// Copyright (c) 2007-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. +// +// Description: +// Symbian USBDI Descriptor Parsing Framework. +// +// + +/** + @file + @internalComponent +*/ + +#include +#include "usbdescutils.h" + + +// --------------------- +// UsbDescriptorParser +// --------------------- + +/** +The main parsing function of the USB descriptor parsing framework. + +This will perform a best effort parse of a USB descriptor tree. It is best effort in the +fact that upon encountering a form of syntatic corruption in the source data it will error +the parse attempt, but also return the incomplete descriptor tree up to the parsing error. + +@param aUsbDes The source data that will be parsed. +@param aDesc The pointer that will be updated to the top-level descriptor. + +@return KErrNone if successful, a system-wide error code otherwise. + +@publishedPartner +@prototype +*/ +EXPORT_C /*static*/ TInt UsbDescriptorParser::Parse(const TDesC8& aUsbDes, TUsbGenericDescriptor*& aDesc) + { + TInt ret = KErrNone; + aDesc = NULL; + TPtrC8 des(aUsbDes); + + // First we must find the top level descriptor (the one we will return to the caller). + TRAP(ret, aDesc = FindParserAndParseAndCheckL(des, NULL)); + if(ret == KErrNone && !aDesc) + { + ret = KErrNotFound; + } + + if(ret == KErrNone) + { + // Now we have a top level descriptor - we now try to build up the descriptor + // tree if there are more descriptors available. + TRAP(ret, ParseDescriptorTreeL(des, *aDesc)); + } + + // Ensure that all the data has been parsed if successful. + if(ret == KErrNone && des.Length() > 0) + { + // If no parser was found for some data then we should have been errored with KErrNotFound. + __ASSERT_DEBUG(EFalse, UsbDescFault(UsbdiFaults::EUsbDescSuccessButDataLeftUnparsed)); + ret = KErrUnknown; + } + + return ret; + } + +/** +The function to register a custom parsing routine in the USB descriptor parser framework. + +The routine is registered locally to the current thread, and so if an application wishes +to perform the same custom parsing in multiple threads, it must call this function with +the appropriate routine in each thread context. + +If the custom routine becomes unapplicable after being registered, the application may +unregister it using the UsbDescriptorParser::UnregisterCustomParser function. +@see UsbDescriptorParser::UnregisterCustomParser + +@param aParserFunc The routine which will be added to the USB descriptor parsing framework. + +@publishedPartner +@prototype +*/ +EXPORT_C /*static*/ void UsbDescriptorParser::RegisterCustomParserL(TUsbDescriptorParserL aParserFunc) + { + TBool newlyCreatedList = EFalse; + CUsbCustomDescriptorParserList* parserList = static_cast(Dll::Tls()); + if(!parserList) + { + parserList = CUsbCustomDescriptorParserList::NewL(); + newlyCreatedList = ETrue; + CleanupStack::PushL(parserList); + } + + parserList->RegisterParserL(aParserFunc); + + if(newlyCreatedList) + { + Dll::SetTls(parserList); + CleanupStack::Pop(parserList); + } + } + +/** +The function to unregister a custom parsing routine in the USB descriptor parser framework. + +This routine will only unregister the routine from the current thread context. If the routine +is registered in multiple threads and it is no longer wanted in any thread, an application +must call this function in each thread context that the routine is registered. + +It is safe to call this function even if RegisterCustomParserL has never been called successfully. + +@see UsbDescriptorParser::RegisterCustomParserL + +@param aParserFunc The routine which will be removed from the USB descriptor parsing framework. + +@publishedPartner +@prototype +*/ +EXPORT_C /*static*/ void UsbDescriptorParser::UnregisterCustomParser(TUsbDescriptorParserL aParserFunc) + { + CUsbCustomDescriptorParserList* parserList = static_cast(Dll::Tls()); + if(parserList) + { + parserList->UnregisterParser(aParserFunc); + if(parserList->NumOfRegisteredParsers() <= 0) + { + Dll::FreeTls(); + delete parserList; + } + } + } + +/*static*/ TUsbGenericDescriptor* UsbDescriptorParser::FindParserAndParseAndCheckL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc) + { + TUsbGenericDescriptor* ret = FindParserAndParseL(aUsbDes, aPreviousDesc); + // We need to ensure that the parsers have correctly initialised the USB descriptor objects. + // It is important that we check as it is possible that a custom parser did the parsing. + __ASSERT_ALWAYS(!ret || (!ret->iParent && !ret->iFirstChild && !ret->iNextPeer), + UsbDescPanic(UsbdiPanics::EUsbDescNonNullPointersAfterParsing)); + return ret; + } + +// Utility macro to tidy up the parsing routine. +#define RETURN_IF_PARSEDL(aRet, aParserL, aUsbDes, aPreviousDesc)\ + {\ + aRet = aParserL(aUsbDes, aPreviousDesc);\ + if(aRet)\ + {\ + return aRet;\ + }\ + } + +/*static*/ TUsbGenericDescriptor* UsbDescriptorParser::FindParserAndParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc) + { + // Special termination case. + if(aUsbDes.Length() == 0) + { + return NULL; + } + + TUsbGenericDescriptor* des; + + // Try the default parsing routines. + RETURN_IF_PARSEDL(des, TUsbDeviceDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbDeviceQualifierDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbConfigurationDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbOtherSpeedDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbInterfaceAssociationDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbInterfaceDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbEndpointDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbOTGDescriptor::ParseL, aUsbDes, aPreviousDesc); + RETURN_IF_PARSEDL(des, TUsbStringDescriptor::ParseL, aUsbDes, aPreviousDesc); + + // Then we try the custom parsers that have been registered. + const CUsbCustomDescriptorParserList* parserList = static_cast(Dll::Tls()); + if(parserList) + { + TInt numOfParsers = parserList->NumOfRegisteredParsers()-1; + for(TInt index=0; indexRegisteredParser(index); + RETURN_IF_PARSEDL(des, parserL, aUsbDes, aPreviousDesc); + } + } + + // Then we try the unknown descriptor parser. + RETURN_IF_PARSEDL(des, UnknownUsbDescriptorParserL, aUsbDes, aPreviousDesc); + + // Otherwise we haven't found anybody to parse the binary data. + User::Leave(KErrNotFound); // inform caller that there is no parser for the data. + return NULL; + } + +/*static*/ void UsbDescriptorParser::ParseDescriptorTreeL(TPtrC8& aUsbDes, TUsbGenericDescriptor& aPreviousDesc) + { + TUsbGenericDescriptor* desc = &aPreviousDesc; + while(desc) + { + TUsbGenericDescriptor* preDesc = desc; + desc = FindParserAndParseAndCheckL(aUsbDes, desc); + if(desc) + { + CleanupStack::PushL(desc); + BuildTreeL(*desc, *preDesc); + CleanupStack::Pop(desc); + } + } + } + +/*static*/ void UsbDescriptorParser::BuildTreeL(TUsbGenericDescriptor& aNewDesc, TUsbGenericDescriptor& aPreviousDesc) + { + // We assume that the new descriptor has been properly initialised with NULL pointers. + __ASSERT_DEBUG(!aNewDesc.iFirstChild && !aNewDesc.iNextPeer && !aNewDesc.iParent, + UsbDescFault(UsbdiFaults::EUsbDescTreePointersAlreadySet)); + + // Find first "top" parent claiming this new descriptor as a child. + TUsbGenericDescriptor* parent = &aPreviousDesc; + TUsbGenericDescriptor* topLevel = &aPreviousDesc; + while(parent) + { + if(aNewDesc.IsParent(*parent) || parent->IsChild(aNewDesc)) + { + break; // we have found a parent. + } + topLevel = parent; // Save the current one for use if we cannot find a parent + parent = parent->iParent; // Scroll back up the tree. + } + __ASSERT_DEBUG(topLevel, UsbDescFault(UsbdiFaults::EUsbDescNoTopLevelDescriptorFound)); + + if(parent) + { + // We should be able to place the descriptor directly as a child of this descriptor, + // however it is not that simple because of IADs (Interface Association Descriptors). + // The ECN states "All of the interface numbers in the set of associated interfaces must be + // contiguous" meaning that if an IAD has two interfaces starting at 1 then the configuration + // bundle may have interface descriptors in '1 then 3 then 2' order. As such we need to be able + // to go backwards to find the most suitable binding. The general way for doing this is to + // find the right-most, lowest descriptor that descriptor considers a parent. + // Where the tree is arranged with peers horizontally linked left to + // right, with children linked vertically top to bottom. + TUsbGenericDescriptor& suitableParent = FindSuitableParentL(aNewDesc, *parent); + + TUsbGenericDescriptor* peer = suitableParent.iFirstChild; + if(peer) + { + TUsbGenericDescriptor* lastPeer; + do + { + lastPeer = peer; + peer = peer->iNextPeer; + } + while(peer); + lastPeer->iNextPeer = &aNewDesc; + } + else + { + // we are the first child so just update. + suitableParent.iFirstChild = &aNewDesc; + } + aNewDesc.iParent = &suitableParent; + } + else if(aNewDesc.IsPeer(*topLevel) || topLevel->IsPeer(aNewDesc)) + { + // There is no explicit parent in the tree so, we may just have a group of top-level peers + // in the bundle. If the previous descriptor is a peer then we shall just tag on its tier. + TUsbGenericDescriptor* lastPeer; + TUsbGenericDescriptor* peer = topLevel; + do + { + lastPeer = peer; + peer = peer->iNextPeer; + } + while(peer); + lastPeer->iNextPeer = &aNewDesc; + } + else + { + // The descriptor could not be bound into the tree, indicating that the bundle of descriptors + // is unvalid. + User::Leave(KErrUsbBadDescriptorTopology); + } + } + +/*static*/ TUsbGenericDescriptor& UsbDescriptorParser::FindSuitableParentL(TUsbGenericDescriptor& aNewDesc, TUsbGenericDescriptor& aTopParent) + { + // This implements the algorithm to search down from the top parent found in the tree to the right most, lowest descriptor + // that will accept the new descriptor as a child. + + TUsbGenericDescriptor* bestMatch = &aTopParent; + + TUsbGenericDescriptor* desc = aTopParent.iFirstChild; + if(desc) + { + // Do a depth first search. + FOREVER + { + // First see if the descriptor is suitable. + __ASSERT_DEBUG(desc, UsbDescFault(UsbdiFaults::EUsbDescRunOffTree)); + if(aNewDesc.IsParent(*desc) || desc->IsChild(aNewDesc)) + { + bestMatch = desc; + } + // Now walk to the next point in the tree. + if(desc->iFirstChild) + { + desc = desc->iFirstChild; + } + else if(desc->iNextPeer) + { + desc = desc->iNextPeer; + } + else + { + // We've run to the end of a bottom tier, so go back up. + do + { + __ASSERT_DEBUG(desc->iParent, UsbDescFault(UsbdiFaults::EUsbDescTreeMemberHasNoParent)); + desc = desc->iParent; + } + while(!desc->iNextPeer && desc != &aTopParent); + if(desc == &aTopParent) + { + // This means that we must have got back to the original + // parent. So we don't do any more. + break; + } + desc = desc->iNextPeer; + } + } + } + return *bestMatch; + } + +/*static*/ TUsbGenericDescriptor* UsbDescriptorParser::UnknownUsbDescriptorParserL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbGenericDescriptor* unknownDes = NULL; + + const TInt KMinUnknownDesLength = 2; // Length and type fields + if( aUsbDes.Length() >= KMinUnknownDesLength) + { + // We require unknown descriptors to have at least the length and type fields. + // Any more exotic descriptors should have a custom parser for the framework to use. + TUint8 unknownDesLen = aUsbDes[TUsbGenericDescriptor::KbLengthOffset]; + + // Robustness check - check the length field is valid. + if(aUsbDes.Length() < unknownDesLen || unknownDesLen < KMinUnknownDesLength) + { + User::Leave(KErrCorrupt); + } + + unknownDes = new(ELeave) TUsbGenericDescriptor; + // Set the standard fields + unknownDes->ibLength = unknownDesLen; + unknownDes->ibDescriptorType = aUsbDes[TUsbGenericDescriptor::KbDescriptorTypeOffset] ; + // Set the blob appropriately + unknownDes->iBlob.Set(aUsbDes.Left(unknownDesLen)); + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(unknownDesLen)); + } + + return unknownDes; + } diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,1356 @@ +// Copyright (c) 2007-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. +// +// Description: +// Symbian USBDI Descriptors Parsing Routines. +// +// + +/** + @file + @publishedPartner +*/ + +#include +#include "usbdescutils.h" + + +// ---------------- +// TUsbGenericDescriptor +// ---------------- + +EXPORT_C TUsbGenericDescriptor::TUsbGenericDescriptor() + : iRecognisedAndParsed(EUnrecognised) + , iNextPeer(NULL) + , iFirstChild(NULL) + , iParent(NULL) + { + } + +/** +Deletes all child and peer descriptors. Does not delete this descriptor, the caller is responsible for +doing this separately. +*/ +EXPORT_C void TUsbGenericDescriptor::DestroyTree() + { + // Store the tree pointers + TUsbGenericDescriptor* child = this->iFirstChild; + TUsbGenericDescriptor* peer = this->iNextPeer; + + // Now we chop off the tree from the root node, by doing this + // we don't need to NULL pointers as we go down (which makes + // the iterative algorithm more efficient). + this->iFirstChild = NULL; + this->iNextPeer = NULL; + + // Now we walk and destroy the tree from the two pointers + // we have + WalkAndDelete(child); + WalkAndDelete(peer); + } + +void TUsbGenericDescriptor::WalkAndDelete(TUsbGenericDescriptor* aDesc) + { + if(!aDesc) + { + return; + } + + TUsbGenericDescriptor* topLevel = aDesc->iParent; + do + { + if(aDesc->iFirstChild) + { + // walk down the tree depth first. + aDesc = aDesc->iFirstChild; + } + else if(aDesc->iNextPeer) + { + // Walk along each peer at the "bottom" + TUsbGenericDescriptor* peer = aDesc->iNextPeer; + delete aDesc; + aDesc = peer; + } + else + { + // End of bottom tier, so we go back up to the parent + // and null the first child pointer so we don't go back + // down again. + TUsbGenericDescriptor* parent = aDesc->iParent; + delete aDesc; + aDesc = parent; + if(aDesc) + { + aDesc->iFirstChild = NULL; + } + + // if we have gone up to the top level for destruction then we don't + // do anymore. + if(aDesc == topLevel) + { + break; + } + } + } + while(aDesc); + } + +/** +Utility method to retrieve a TUint8 value from a given offset in the descriptor. +@param aOffset The offset in the binary blob at which to retrieve the value. +@return The value from the descriptor. +*/ +EXPORT_C TUint8 TUsbGenericDescriptor::TUint8At(TInt aOffset) const + { + return ParseTUint8(iBlob, aOffset); + } + +/** +Utility method to retrieve a TUint16 value from a given offset in the descriptor. +@param aOffset The offset in the binary blob at which to retrieve the value. +@return The value from the descriptor. +*/ +EXPORT_C TUint16 TUsbGenericDescriptor::TUint16At(TInt aOffset) const + { + return ParseTUint16(iBlob, aOffset); + } + +/** +Utility method to retrieve a TUint32 value from a given offset in the descriptor. +@param aOffset The offset in the binary blob at which to retrieve the value. +@return The value from the descriptor. +*/ +EXPORT_C TUint32 TUsbGenericDescriptor::TUint32At(TInt aOffset) const + { + return ParseTUint32(iBlob, aOffset); + } + +/** +Assignment operator to fill in the TUsbGenericDescriptor fields from a TUsbGenericDescriptor. +Note that if a TUsbGenericDescriptor derived class has additional member fields then +they should define a specialised assignment overload for that type. +*/ +EXPORT_C TUsbGenericDescriptor& TUsbGenericDescriptor::operator=(const TUsbGenericDescriptor& aDescriptor) + { + ibLength = aDescriptor.ibLength; + ibDescriptorType = aDescriptor.ibDescriptorType; + iRecognisedAndParsed = aDescriptor.iRecognisedAndParsed; + iNextPeer = aDescriptor.iNextPeer; + iFirstChild = aDescriptor.iFirstChild; + iParent = aDescriptor.iParent; + iBlob.Set(aDescriptor.iBlob); + return *this; + } + +/** +This function determines whether the given USB descriptor is a parent +of the descriptor the method is called on. The implementation may be +specialised for each type of descriptor to ensure the tree is correctly +built up. +@param aPotentialRelative The USB descriptor that is being queried to see if it is a parent or peer. +@return TBool Efalse if the given USB descriptor is a parent of this USB descriptor, ETrue if a peer of this descriptor +*/ +/*virtual*/ TBool TUsbGenericDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent) + { + // As generic descriptors we consider all other "unknown" descriptors as peers, and + // all "known" descriptors as parents of the descriptor. + switch(aPotentialParent.ibDescriptorType) + { + case EDevice: + case EConfiguration: + case EString: + case EInterface: + case EEndpoint: + case EDeviceQualifier: + case EOtherSpeedConfiguration: + case EInterfacePower: + case EOTG: + case EDebug: + case EInterfaceAssociation: + return ETrue; + default: + return EFalse; + } + } + +/** +This function determines whether the given USB descriptor is a peer +of the descriptor the method is called on. The implementation may be +specialised for each type of descriptor to ensure the tree is correctly +built up. +@param aPotentialPeer The USB descriptor that is being queried to see if it is a peer. +@return TBool EFalse if the given USB descriptor is a parent of this USB descriptor, ETrue if a peer of this descriptor +*/ +/*virtual*/ TBool TUsbGenericDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/) + { + // As generic descriptors we are very permissive in binding peers. + return ETrue; + } + +/** +This function determines whether the given USB descriptor is a child +of the descriptor the method is called on. The implementation may be +specialised for each type of descriptor to ensure the tree is correctly +built up. +@param aPotentialChild The USB descriptor that is being queried to see if it is a child. +@return TBool ETrue if the given USB descriptor is a child of this USB descriptor, ETrue if a peer of this descriptor +*/ +/*virtual*/ TBool TUsbGenericDescriptor::IsChild(TUsbGenericDescriptor& /*aPotentialChild*/) + { + // We just use the logic in the IsParent. + return EFalse; + } + +/** +Ensures no memory is leaked if an owned TUsbGenericDescriptor is no longer needed. +@param aPtr The TUsbGenericDescriptor that is to be cleaned up. +@internalComponent +*/ +EXPORT_C /*static*/ void TUsbGenericDescriptor::Cleanup(TAny* aPtr) + { + TUsbGenericDescriptor* ptr = static_cast(aPtr); + ptr->DestroyTree(); // belt and braces really. + delete ptr; + } + + +// ---------------------- +// TUsbDeviceDescriptor +// See section 9.6.1 of the USB 2.0 specification. +// ---------------------- + +EXPORT_C TUsbDeviceDescriptor::TUsbDeviceDescriptor() + { + } + +EXPORT_C /*static*/ TUsbDeviceDescriptor* TUsbDeviceDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbDeviceDescriptor* ret = NULL; + // Only cast if correctly indentified as device descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EDevice && + aOriginal->ibLength == TUsbDeviceDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint16 TUsbDeviceDescriptor::USBBcd() const + { + return ParseTUint16(iBlob, EbcdUSB); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::DeviceClass() const + { + return ParseTUint8(iBlob, EbDeviceClass); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::DeviceSubClass() const + { + return ParseTUint8(iBlob, EbDeviceSubClass); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::DeviceProtocol() const + { + return ParseTUint8(iBlob, EbDeviceProtocol); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::MaxPacketSize0() const + { + return ParseTUint8(iBlob, EbMaxPacketSize0); + } + +EXPORT_C TUint16 TUsbDeviceDescriptor::VendorId() const + { + return ParseTUint16(iBlob, EidVendor); + } + +EXPORT_C TUint16 TUsbDeviceDescriptor::ProductId() const + { + return ParseTUint16(iBlob, EidProduct); + } + +EXPORT_C TUint16 TUsbDeviceDescriptor::DeviceBcd() const + { + return ParseTUint16(iBlob, EbcdDevice); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::ManufacturerIndex() const + { + return ParseTUint8(iBlob, EiManufacturer); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::ProductIndex() const + { + return ParseTUint8(iBlob, EiProduct); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::SerialNumberIndex() const + { + return ParseTUint8(iBlob, EiSerialNumber); + } + +EXPORT_C TUint8 TUsbDeviceDescriptor::NumConfigurations() const + { + return ParseTUint8(iBlob, EbNumConfigurations); + } + +/** +The parsing routine for device descriptors. +Here the previous descriptor parameter is ignored - because logically a device descriptor can be neither a peer +nor a child. + +@internalComponent +*/ +/*static*/ TUsbDeviceDescriptor* TUsbDeviceDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* aPreviousDesc) + { + TUsbDeviceDescriptor* devDes = NULL; + + const TInt KMinDeviceDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinDeviceDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EDevice && + aUsbDes[KbLengthOffset] == TUsbDeviceDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbDeviceDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Robustness check - check that the device descriptor is the first to be parsed. + if(aPreviousDesc) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be a device descriptor. + devDes = new(ELeave) TUsbDeviceDescriptor; + // Set the standard fields + devDes->ibLength = TUsbDeviceDescriptor::KSizeInOctets; + devDes->ibDescriptorType = EDevice; + // Set the blob appropriately + devDes->iBlob.Set(aUsbDes.Left(TUsbDeviceDescriptor::KSizeInOctets)); + + devDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbDeviceDescriptor::KSizeInOctets)); + } + + return devDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbDeviceDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/) + { + // The device descriptor should only come by itself in a bundle, so must be top-level. + return EFalse; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbDeviceDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/) + { + // The device descriptor should only come by itself in a bundle, so no other peers. + return EFalse; + } + + +// ------------------------------ +// TUsbDeviceQualifierDescriptor +// See section 9.6.2 of the USB 2.0 specification. +// ------------------------------ + +EXPORT_C TUsbDeviceQualifierDescriptor::TUsbDeviceQualifierDescriptor() + { + } + +EXPORT_C /*static*/ TUsbDeviceQualifierDescriptor* TUsbDeviceQualifierDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbDeviceQualifierDescriptor* ret = NULL; + // Only cast if correctly indentified as device qualifier descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EDeviceQualifier && + aOriginal->ibLength == TUsbDeviceQualifierDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint16 TUsbDeviceQualifierDescriptor::USBBcd() const + { + return ParseTUint16(iBlob, EbcdUSB); + } + +EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::DeviceClass() const + { + return ParseTUint8(iBlob, EbDeviceClass); + } + +EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::DeviceSubClass() const + { + return ParseTUint8(iBlob, EbDeviceSubClass); + } + +EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::DeviceProtocol() const + { + return ParseTUint8(iBlob, EbDeviceProtocol); + } + +EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::MaxPacketSize0() const + { + return ParseTUint8(iBlob, EbMaxPacketSize0); + } + +EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::NumConfigurations() const + { + return ParseTUint8(iBlob, EbNumConfigurations); + } + +EXPORT_C TUint8 TUsbDeviceQualifierDescriptor::Reserved() const + { + return ParseTUint8(iBlob, EbReserved); + } + +/** +The parsing routine for device qualifier descriptors. + +@internalComponent +*/ +/*static*/ TUsbDeviceQualifierDescriptor* TUsbDeviceQualifierDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbDeviceQualifierDescriptor* devQualDes = NULL; + + const TInt KMinDevQualDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinDevQualDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EDeviceQualifier && + aUsbDes[KbLengthOffset] == TUsbDeviceQualifierDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbDeviceQualifierDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be a device quialifier descriptor. + devQualDes = new(ELeave) TUsbDeviceQualifierDescriptor; + // Set the standard fields + devQualDes->ibLength = TUsbDeviceQualifierDescriptor::KSizeInOctets; + devQualDes->ibDescriptorType = EDeviceQualifier; + // Set the blob appropriately + devQualDes->iBlob.Set(aUsbDes.Left(TUsbDeviceQualifierDescriptor::KSizeInOctets)); + + devQualDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbDeviceQualifierDescriptor::KSizeInOctets)); + } + + return devQualDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbDeviceQualifierDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/) + { + // Like a device descriptor, they should be top-level. + return EFalse; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbDeviceQualifierDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/) + { + // Like a device descriptor, they should come by themselves. + return EFalse; + } + + +// ---------------------------- +// TUsbConfigurationDescriptor +// See section 9.6.3 of the USB 2.0 specification. +// ---------------------------- + +EXPORT_C TUsbConfigurationDescriptor::TUsbConfigurationDescriptor() + { + } + +EXPORT_C /*static*/ TUsbConfigurationDescriptor* TUsbConfigurationDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbConfigurationDescriptor* ret = NULL; + // Only cast if correctly indentified as configuration descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EConfiguration && + aOriginal->ibLength == TUsbConfigurationDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint16 TUsbConfigurationDescriptor::TotalLength() const + { + return ParseTUint16(iBlob, EwTotalLength); + } + +EXPORT_C TUint8 TUsbConfigurationDescriptor::NumInterfaces() const + { + return ParseTUint8(iBlob, EbNumInterfaces); + } + +EXPORT_C TUint8 TUsbConfigurationDescriptor::ConfigurationValue() const + { + return ParseTUint8(iBlob, EbConfigurationValue); + } + +EXPORT_C TUint8 TUsbConfigurationDescriptor::ConfigurationIndex() const + { + return ParseTUint8(iBlob, EiConfiguration); + } + +EXPORT_C TUint8 TUsbConfigurationDescriptor::Attributes() const + { + return ParseTUint8(iBlob, EbmAttributes); + } + +EXPORT_C TUint8 TUsbConfigurationDescriptor::MaxPower() const + { + return ParseTUint8(iBlob, EbMaxPower); + } + +/** +The parsing routine for configuration descriptors. + +@internalComponent +*/ +/*static*/ TUsbConfigurationDescriptor* TUsbConfigurationDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbConfigurationDescriptor* configDes = NULL; + + const TInt KMinConfigDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinConfigDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EConfiguration && + aUsbDes[KbLengthOffset] == TUsbConfigurationDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbConfigurationDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Robustness check - check that there is sufficient data for whole bundle (wTotalLength) + const TInt KwTotalLengthOffset = 2; + if(aUsbDes.Length() < ParseTUint16(aUsbDes, KwTotalLengthOffset)) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be a configuration descriptor. + configDes = new(ELeave) TUsbConfigurationDescriptor; + // Set the standard fields + configDes->ibLength = TUsbConfigurationDescriptor::KSizeInOctets; + configDes->ibDescriptorType = EConfiguration; + // Set the blob appropriately + configDes->iBlob.Set(aUsbDes.Left(TUsbConfigurationDescriptor::KSizeInOctets)); + + configDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbConfigurationDescriptor::KSizeInOctets)); + } + + return configDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbConfigurationDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/) + { + // A configuration descriptor should always be the top-level descriptor in a configuration + // bundle. + return EFalse; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbConfigurationDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/) + { + // There should only ever be one configuration descriptor in a bundle. + return EFalse; + } + + +// -------------------------- +// TUsbOtherSpeedDescriptor +// See section 9.6.4 of the USB 2.0 specification. +// -------------------------- + +EXPORT_C TUsbOtherSpeedDescriptor::TUsbOtherSpeedDescriptor() + { + } + +EXPORT_C /*static*/ TUsbOtherSpeedDescriptor* TUsbOtherSpeedDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbOtherSpeedDescriptor* ret = NULL; + // Only cast if correctly indentified as other speed descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EOtherSpeedConfiguration && + aOriginal->ibLength == TUsbOtherSpeedDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint16 TUsbOtherSpeedDescriptor::TotalLength() const + { + return ParseTUint16(iBlob, EwTotalLength); + } + +EXPORT_C TUint8 TUsbOtherSpeedDescriptor::NumInterfaces() const + { + return ParseTUint8(iBlob, EbNumInterfaces); + } + +EXPORT_C TUint8 TUsbOtherSpeedDescriptor::ConfigurationValue() const + { + return ParseTUint8(iBlob, EbConfigurationValue); + } + +EXPORT_C TUint8 TUsbOtherSpeedDescriptor::ConfigurationIndex() const + { + return ParseTUint8(iBlob, EiConfiguration); + } + +EXPORT_C TUint8 TUsbOtherSpeedDescriptor::Attributes() const + { + return ParseTUint8(iBlob, EbmAttributes); + } + +EXPORT_C TUint8 TUsbOtherSpeedDescriptor::MaxPower() const + { + return ParseTUint8(iBlob, EbMaxPower); + } + +/** +The parsing routine for other speed descriptors. + +@internalComponent +*/ +/*static*/ TUsbOtherSpeedDescriptor* TUsbOtherSpeedDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbOtherSpeedDescriptor* oSpeedDes = NULL; + + const TInt KMinOtherSpeedDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinOtherSpeedDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EOtherSpeedConfiguration && + aUsbDes[KbLengthOffset] == TUsbOtherSpeedDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbOtherSpeedDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Robustness check - check that there is sufficient data for whole bundle (wTotalLength) + const TInt KwTotalLengthOffset = 2; + if(aUsbDes.Length() < ParseTUint16(aUsbDes, KwTotalLengthOffset)) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be an other speed descriptor. + oSpeedDes = new(ELeave) TUsbOtherSpeedDescriptor; + // Set the standard fields + oSpeedDes->ibLength = TUsbOtherSpeedDescriptor::KSizeInOctets; + oSpeedDes->ibDescriptorType = EOtherSpeedConfiguration; + // Set the blob appropriately + oSpeedDes->iBlob.Set(aUsbDes.Left(TUsbOtherSpeedDescriptor::KSizeInOctets)); + + oSpeedDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbOtherSpeedDescriptor::KSizeInOctets)); + } + + return oSpeedDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbOtherSpeedDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/) + { + // Other speed descriptor is like a configuration descriptor, in that it should + // not have any parents in a bundle. + return EFalse; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbOtherSpeedDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/) + { + // There should only ever be one other speed descriptor in a bundle. + return EFalse; + } + + +// ------------------------------------ +// TUsbInterfaceAssociationDescriptor +// See the USB IAD ECN. +// ------------------------------------ + +EXPORT_C TUsbInterfaceAssociationDescriptor::TUsbInterfaceAssociationDescriptor() + { + } + +EXPORT_C /*static*/ TUsbInterfaceAssociationDescriptor* TUsbInterfaceAssociationDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbInterfaceAssociationDescriptor* ret = NULL; + // Only cast if correctly indentified as interface association descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EInterfaceAssociation && + aOriginal->ibLength == TUsbInterfaceAssociationDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FirstInterface() const + { + return ParseTUint8(iBlob, EbFirstInterface); + } + +EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::InterfaceCount() const + { + return ParseTUint8(iBlob, EbInterfaceCount); + } + +EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionClass() const + { + return ParseTUint8(iBlob, EbFunctionClass); + } + +EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionSubClass() const + { + return ParseTUint8(iBlob, EbFunctionSubClass); + } + +EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionProtocol() const + { + return ParseTUint8(iBlob, EbFunctionProtocol); + } + +EXPORT_C TUint8 TUsbInterfaceAssociationDescriptor::FunctionIndex() const + { + return ParseTUint8(iBlob, EiFunction); + } + +/*static*/ TUsbInterfaceAssociationDescriptor* TUsbInterfaceAssociationDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbInterfaceAssociationDescriptor* intAssocDes = NULL; + + const TInt KMinIntAssocDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinIntAssocDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EInterfaceAssociation && + aUsbDes[KbLengthOffset] == TUsbInterfaceAssociationDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbInterfaceAssociationDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be a interface association descriptor. + intAssocDes = new(ELeave) TUsbInterfaceAssociationDescriptor; + // Set the standard fields + intAssocDes->ibLength = TUsbInterfaceAssociationDescriptor::KSizeInOctets; + intAssocDes->ibDescriptorType = EInterfaceAssociation; + // Set the blob appropriately + intAssocDes->iBlob.Set(aUsbDes.Left(TUsbInterfaceAssociationDescriptor::KSizeInOctets)); + + intAssocDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbInterfaceAssociationDescriptor::KSizeInOctets)); + } + + return intAssocDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbInterfaceAssociationDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent) + { + switch(aPotentialParent.ibDescriptorType) + { + case EConfiguration: + return ETrue; + case EOtherSpeedConfiguration: + return ETrue; // I think this should be EFalse by my reading of the USB spec - however + // it is not explicitly clear, so play it safe. + default: + return EFalse; + } + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbInterfaceAssociationDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer) + { + switch(aPotentialPeer.ibDescriptorType) + { + case EInterfaceAssociation: + return ETrue; + case EInterface: + // Only interfaces are peers of IADs. + { + TUsbInterfaceDescriptor* intDesc = TUsbInterfaceDescriptor::Cast(&aPotentialPeer); + if(intDesc) + { + TInt intNum = intDesc->InterfaceNumber(); + intNum -= FirstInterface(); + if(intNum < 0 || intNum >= InterfaceCount()) + { + // The interface number is outside the IAD region. + return ETrue; + } + } + return EFalse; + } + default: + return EFalse; + } + } + +/*virtual*/ TBool TUsbInterfaceAssociationDescriptor::IsChild(TUsbGenericDescriptor& aPotentialChild) + { + switch(aPotentialChild.ibDescriptorType) + { + case EInterface: + // Only interfaces are children of IADs. And only if they are special. + { + TUsbInterfaceDescriptor* intDesc = TUsbInterfaceDescriptor::Cast(&aPotentialChild); + if(intDesc) + { + TInt intNum = intDesc->InterfaceNumber(); + intNum -= FirstInterface(); + if(intNum >= 0 && intNum < InterfaceCount()) + { + // The interface number is within the IAD region required. + return ETrue; + } + } + return EFalse; + } + default: + return EFalse; + } + } + + +// ------------------------- +// TUsbInterfaceDescriptor +// See section 9.6.5 of the USB 2.0 specification. +// ------------------------- + +EXPORT_C TUsbInterfaceDescriptor::TUsbInterfaceDescriptor() + { + } + +EXPORT_C /*static*/ TUsbInterfaceDescriptor* TUsbInterfaceDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbInterfaceDescriptor* ret = NULL; + // Only cast if correctly indentified as interface descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EInterface && + aOriginal->ibLength == TUsbInterfaceDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceNumber() const + { + return ParseTUint8(iBlob, EbInterfaceNumber); + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::AlternateSetting() const + { + return ParseTUint8(iBlob, EbAlternateSetting); + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::NumEndpoints() const + { + return ParseTUint8(iBlob, EbNumEndpoints); + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceClass() const + { + return ParseTUint8(iBlob, EbInterfaceClass); + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceSubClass() const + { + return ParseTUint8(iBlob, EbInterfaceSubClass); + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::InterfaceProtocol() const + { + return ParseTUint8(iBlob, EbInterfaceProtocol); + } + +EXPORT_C TUint8 TUsbInterfaceDescriptor::Interface() const + { + return ParseTUint8(iBlob, EiInterface); + } + +/** +The parsing routine for interface descriptors. + +@internalComponent +*/ +/*static*/ TUsbInterfaceDescriptor* TUsbInterfaceDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbInterfaceDescriptor* intDes = NULL; + + const TInt KMinInterfaceDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinInterfaceDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EInterface && + aUsbDes[KbLengthOffset] == TUsbInterfaceDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbInterfaceDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be an interface descriptor. + intDes = new(ELeave) TUsbInterfaceDescriptor; + // Set the standard fields + intDes->ibLength = TUsbInterfaceDescriptor::KSizeInOctets; + intDes->ibDescriptorType = EInterface; + // Set the blob appropriately + intDes->iBlob.Set(aUsbDes.Left(TUsbInterfaceDescriptor::KSizeInOctets)); + + intDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbInterfaceDescriptor::KSizeInOctets)); + } + + return intDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbInterfaceDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent) + { + switch(aPotentialParent.ibDescriptorType) + { + case EConfiguration: + return ETrue; + case EOtherSpeedConfiguration: + return ETrue; // I think this should be EFalse by my reading of the USB spec - however + // it is not explicitly clear, so play it safe. + // case EInterfaceAssociation: + // We let the IAD descriptor handle the logic of how we bind to it. + default: + return EFalse; + } + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbInterfaceDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer) + { + switch(aPotentialPeer.ibDescriptorType) + { + //case EInterfaceAssociation: + // We let the IAD descriptor handle the logic of how we bind to it. + case EInterface: + // If another interface descriptor then it is a peer not child. + return ETrue; + default: + // Any other descriptors are ignored. + return EFalse; + } + } + + +// ------------------------ +// TUsbEndpointDescriptor +// See section 9.6.6 of the USB 2.0 specification. +// ------------------------ + +EXPORT_C TUsbEndpointDescriptor::TUsbEndpointDescriptor() + { + } + +EXPORT_C /*static*/ TUsbEndpointDescriptor* TUsbEndpointDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbEndpointDescriptor* ret = NULL; + // Only cast if correctly indentified as endpoint descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EEndpoint && + aOriginal->ibLength == TUsbEndpointDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint8 TUsbEndpointDescriptor::EndpointAddress() const + { + return ParseTUint8(iBlob, EbEndpointAddress); + } + +EXPORT_C TUint8 TUsbEndpointDescriptor::Attributes() const + { + return ParseTUint8(iBlob, EbmAttributes); + } + +EXPORT_C TUint16 TUsbEndpointDescriptor::MaxPacketSize() const + { + return ParseTUint16(iBlob, EwMaxPacketSize); + } + +EXPORT_C TUint8 TUsbEndpointDescriptor::Interval() const + { + return ParseTUint8(iBlob, EbInterval); + } + +/** +The parsing routine for endpoint descriptors. + +@internalComponent +*/ +/*static*/ TUsbEndpointDescriptor* TUsbEndpointDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbEndpointDescriptor* endDes = NULL; + + const TInt KMinEndpointDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinEndpointDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EEndpoint && + aUsbDes[KbLengthOffset] == TUsbEndpointDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbEndpointDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be an endpoint descriptor. + endDes = new(ELeave) TUsbEndpointDescriptor; + // Set the standard fields + endDes->ibLength = TUsbEndpointDescriptor::KSizeInOctets; + endDes->ibDescriptorType = EEndpoint; + // Set the blob appropriately + endDes->iBlob.Set(aUsbDes.Left(TUsbEndpointDescriptor::KSizeInOctets)); + + endDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbEndpointDescriptor::KSizeInOctets)); + } + + return endDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbEndpointDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent) + { + switch(aPotentialParent.ibDescriptorType) + { + case EInterface: + return ETrue; + default: + return EFalse; + } + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbEndpointDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer) + { + switch(aPotentialPeer.ibDescriptorType) + { + case EEndpoint: + return ETrue; + default: + return EFalse; + } + } + +// ------------------------ +// TUsbOTGDescriptor +// See section 6.4 of the USB 2.0 On-The-Go Supplement Revision 1.3 +// ------------------------ + +EXPORT_C TUsbOTGDescriptor::TUsbOTGDescriptor() + { + } + +EXPORT_C /*static*/ TUsbOTGDescriptor* TUsbOTGDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbOTGDescriptor* ret = NULL; + // Only cast if correctly indentified as otg descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EOTG && + aOriginal->ibLength == TUsbOTGDescriptor::KSizeInOctets && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +EXPORT_C TUint8 TUsbOTGDescriptor::Attributes() const + { + return ParseTUint8(iBlob, EbmAttributes); + } + +EXPORT_C TBool TUsbOTGDescriptor::HNPSupported() const + { + return (ParseTUint8(iBlob, EbmAttributes) & 0x02) == 0x02; + } + +EXPORT_C TBool TUsbOTGDescriptor::SRPSupported() const + { + // Note: an illegal device (see 6.4.2 of the OTG specification) could + // incorrectly return False for SRP and True for HNP + // However this function just extracts the bit rather than attempting to + // fix up a broken device. Devices broken in this way wouldn't be expected on + // the TPL. + return (ParseTUint8(iBlob, EbmAttributes) & 0x01) == 0x01; + } + +/** +The parsing routine for OTG descriptors. + +@internalComponent +*/ +/*static*/ TUsbOTGDescriptor* TUsbOTGDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbOTGDescriptor* endDes = NULL; + + const TInt KMinOTGDesDecisionLength = 2; + if( aUsbDes.Length() >= KMinOTGDesDecisionLength && + aUsbDes[KbDescriptorTypeOffset] == EOTG && + aUsbDes[KbLengthOffset] == TUsbOTGDescriptor::KSizeInOctets) + { + // Robustness check - check the length field is valid, and that we have enough data. + if(aUsbDes.Length() < TUsbOTGDescriptor::KSizeInOctets) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be an OTG descriptor. + endDes = new(ELeave) TUsbOTGDescriptor; + // Set the standard fields + endDes->ibLength = TUsbOTGDescriptor::KSizeInOctets; + endDes->ibDescriptorType = EOTG; + // Set the blob appropriately + endDes->iBlob.Set(aUsbDes.Left(TUsbOTGDescriptor::KSizeInOctets)); + + // Null the pointers + endDes->iFirstChild = NULL; + endDes->iNextPeer = NULL; + endDes->iParent = NULL; + + endDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(TUsbOTGDescriptor::KSizeInOctets)); + } + + return endDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbOTGDescriptor::IsParent(TUsbGenericDescriptor& aPotentialParent) + { + switch(aPotentialParent.ibDescriptorType) + { + case EConfiguration: // we are part of a configuration descriptor, or standalone + return ETrue; + default: + return EFalse; + } + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbOTGDescriptor::IsPeer(TUsbGenericDescriptor& aPotentialPeer) + { + switch(aPotentialPeer.ibDescriptorType) + { + //case EInterfaceAssociation: + // We let the IAD descriptor handle the logic of how we bind to it. + case EInterface: + // If another interface descriptor then it is a peer not child. + return ETrue; + default: + // Any other descriptors are ignored. + return EFalse; + } + } + + +// ---------------------- +// TUsbStringDescriptor +// See section 9.6.7 of the USB 2.0 specification. +// ---------------------- + +// The length of the header in a string descriptor (i.e. the same as every other standard USB descriptor). +static const TInt KStringDescriptorHeaderFieldLength = 2; + +EXPORT_C TUsbStringDescriptor::TUsbStringDescriptor() + { + } + +EXPORT_C /*static*/ TUsbStringDescriptor* TUsbStringDescriptor::Cast(TUsbGenericDescriptor* aOriginal) + { + TUsbStringDescriptor* ret = NULL; + // Only cast if correctly indentified as string descriptor + if( aOriginal && + aOriginal->ibDescriptorType == EString && + aOriginal->ibLength >= KStringDescriptorHeaderFieldLength && + aOriginal->iRecognisedAndParsed == ERecognised) + { + ret = static_cast(aOriginal); + } + return ret; + } + +/** +For string descriptor zero, this function allows a means to iterate through the list of supported languages +for strings on this device. + +@param aIndex Index into language ID table. +@return The language ID at the requested index, or KErrNotFound if the end of the list has been reached. +Note that the language IDs are unsigned 16-bit numbers, while the return from this function is signed 32-bit. +*/ +EXPORT_C TInt TUsbStringDescriptor::GetLangId(TInt aIndex) const + { + __ASSERT_ALWAYS(aIndex >= 0, UsbDescPanic(UsbdiPanics::EUsbDescNegativeIndexToLangId)); + const TUint8 KSizeOfLangIdField = 2; + + TInt offset = KStringDescriptorHeaderFieldLength + KSizeOfLangIdField * aIndex; + if(offset >= ibLength) + { + return KErrNotFound; + } + return ParseTUint16(iBlob, offset); + } + +/** +Writes the string data into a Symbian descriptor of sufficient size. + +@param aString The Symbian descriptor that will have the string data written into it. +*/ +EXPORT_C void TUsbStringDescriptor::StringData(TDes16& aString) const + { + const TUint8 KUnicodeCharacterWidth = 2; + aString.Zero(); + + TInt index = KStringDescriptorHeaderFieldLength; + while(index+KUnicodeCharacterWidth <= ibLength) + { + aString.Append(ParseTUint16(iBlob, index)); + index += KUnicodeCharacterWidth; + } + } + + +/*static*/ TUsbStringDescriptor* TUsbStringDescriptor::ParseL(TPtrC8& aUsbDes, TUsbGenericDescriptor* /*aPreviousDesc*/) + { + TUsbStringDescriptor* stringDes = NULL; + + if( aUsbDes.Length() >= KStringDescriptorHeaderFieldLength && + aUsbDes[KbDescriptorTypeOffset] == EString) + { + TUint8 stringDesLen = aUsbDes[KbLengthOffset]; + + // Robustness check - check the length field is valid + if(aUsbDes.Length() < stringDesLen || stringDesLen < KStringDescriptorHeaderFieldLength) + { + User::Leave(KErrCorrupt); + } + // Robustness check - check the length is a multiple of two. + if(stringDesLen % 2 != 0) + { + User::Leave(KErrCorrupt); + } + + // Looks ok to be a string descriptor. + stringDes = new(ELeave) TUsbStringDescriptor; + // Set the standard fields + stringDes->ibLength = stringDesLen; + stringDes->ibDescriptorType = EString; + // Set the blob appropriately + stringDes->iBlob.Set(aUsbDes.Left(stringDesLen)); + + stringDes->iRecognisedAndParsed = ERecognised; + + // Update the data-left-to-parse Symbian descriptor + aUsbDes.Set(aUsbDes.Mid(stringDesLen)); + } + + return stringDes; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbStringDescriptor::IsParent(TUsbGenericDescriptor& /*aPotentialParent*/) + { + // String descriptors have no parents - they are standalone. + return EFalse; + } + +/** +@internalComponent +*/ +/*virtual*/ TBool TUsbStringDescriptor::IsPeer(TUsbGenericDescriptor& /*aPotentialPeer*/) + { + // String descriptors have no peers - they are standalone. + return EFalse; + } + diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.mmp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,31 @@ +// Copyright (c) 2007-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. +// +// Description: +// + +TARGET usbdescriptors.dll +TARGETTYPE dll +CAPABILITY All -Tcb +VENDORID 0x70000001 + +DEFFILE ../../../~/usbdescriptors.def + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +USERINCLUDE . + +SOURCEPATH . +SOURCE usbdescriptors.cpp +SOURCE usbdescparser.cpp +SOURCE usbdescutils.cpp + +LIBRARY euser.lib + +SMPSAFE \ No newline at end of file diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,55 @@ +// Copyright (c) 2007-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. +// +// Description: +// + +#include "usbdescutils.h" + +/** +@file +@internalComponent +*/ + +/*static*/ CUsbCustomDescriptorParserList* CUsbCustomDescriptorParserList::NewL() + { + CUsbCustomDescriptorParserList* self = new(ELeave) CUsbCustomDescriptorParserList; + return self; + } + +CUsbCustomDescriptorParserList::~CUsbCustomDescriptorParserList() + { + iParserList.Close(); + } + +void CUsbCustomDescriptorParserList::RegisterParserL(UsbDescriptorParser::TUsbDescriptorParserL aParserFunc) + { + iParserList.AppendL(aParserFunc); + } + +void CUsbCustomDescriptorParserList::UnregisterParser(UsbDescriptorParser::TUsbDescriptorParserL aParserFunc) + { + TInt res = iParserList.Find(aParserFunc); + if(res != KErrNotFound) + { + iParserList.Remove(res); + } + } + +TInt CUsbCustomDescriptorParserList::NumOfRegisteredParsers() const + { + return iParserList.Count(); + } + +UsbDescriptorParser::TUsbDescriptorParserL CUsbCustomDescriptorParserList::RegisteredParser(TInt aIndex) const + { + return iParserList[aIndex]; + } + diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.h Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,94 @@ +// Copyright (c) 2007-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. +// +// Description: +// + +/** + @file + @internalComponent +*/ + +#ifndef USBDESCUTILS_H +#define USBDESCUTILS_H + +#include +#include + +inline void UsbDescFault(UsbdiFaults::TUsbDescFaults aFault) + { + User::Panic(UsbdiFaults::KUsbDescFaultCat, aFault); + } + +inline void UsbDescPanic(UsbdiPanics::TUsbDescPanics aPanic) + { + User::Panic(UsbdiPanics::KUsbDescPanicCat, aPanic); + } + +/** +Utility function for retrieving a TUint8 from a Little Endian USB descriptor. +@param aDes The descriptor to parse. +@param aOffset The offset in the descriptor where to parse. +@return The TUint8 value parsed. +*/ +inline TUint8 ParseTUint8(TPtrC8 aDes, TInt aOffset) + { + return aDes[aOffset]; + } + +/** +Utility function for retrieving a TUint16 from a Little Endian USB descriptor. +@param aDes The descriptor to parse. +@param aOffset The offset in the descriptor where to parse. +@return The TUint16 value parsed. +*/ +inline TUint16 ParseTUint16(TPtrC8 aDes, TInt aOffset) + { + return ((TUint16)aDes[aOffset]) | ( ((TUint16)aDes[aOffset+1]) << 8 ); + } + +/** +Utility function for retrieving a TUint32 from a Little Endian USB descriptor. +@param aDes The descriptor to parse. +@param aOffset The offset in the descriptor where to parse. +@return The TUint32 value parsed. +*/ +inline TUint32 ParseTUint32(TPtrC8 aDes, TInt aOffset) + { + // Put enough brackets to ensure that all casting is correct + // and the expression looks symmetrical + return ( ((TUint32)(aDes[aOffset])) ) | + ( ((TUint32)(aDes[aOffset + 1])) << 8 ) | + ( ((TUint32)(aDes[aOffset + 2])) << 16 ) | + ( ((TUint32)(aDes[aOffset + 3])) << 24 ); + } + +/** +A utility class to store the custom descriptor parsers. +The USBDI descriptor parsing framework creates and stores an instance +of this class in TLS when a custom parse is registered. +*/ +NONSHARABLE_CLASS(CUsbCustomDescriptorParserList) : public CBase + { +public: + static CUsbCustomDescriptorParserList* NewL(); + ~CUsbCustomDescriptorParserList(); + + void RegisterParserL(UsbDescriptorParser::TUsbDescriptorParserL aParserFunc); + void UnregisterParser(UsbDescriptorParser::TUsbDescriptorParserL aParserFunc); + TInt NumOfRegisteredParsers() const; + UsbDescriptorParser::TUsbDescriptorParserL RegisteredParser(TInt aIndex) const; + +private: + RArray iParserList; + }; + + +#endif // USBDESCUTILS_H diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/base_drivers_usbdi_utils.mrp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/base_drivers_usbdi_utils.mrp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,12 @@ +# component name "USB DI Utils" + +component base_drivers_usbdi_utils + +source \sf\os\kernelhwsrv\kernel\eka\drivers\usbho\usbdi_utils + +binary \sf\os\kernelhwsrv\kernel\eka\drivers\usbho\usbdi_utils all + +notes_source \component_defs\release.src + +ipr E + diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/bld.inf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/bld.inf Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,46 @@ +// Copyright (c) 2010 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/usbho/usbdi_utils/bld.inf +// +// + +/** + @file +*/ + + +PRJ_PLATFORMS + +ARMV5 ARMV5SMP + + +PRJ_MMPFILES + +#ifndef GCCXML +#if defined(GENERIC_MARM) || !defined(WINS) || defined(GENERIC_X86) +#if !defined(MARM_THUMB) && !defined(MARM_ARMI) + +#if !defined(WINS) +#if !defined(X86) +#if defined(SYMBIAN_ENABLE_USB_OTG_HOST) + +usbdi_utils + +#endif +#endif +#endif + +#endif +#endif +#endif diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/usbdi_utils.mmp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbdi_utils.mmp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,37 @@ +// Copyright (c) 2007-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: +// + +target usbdi_utils.dll +targettype dll +capability All -Tcb +vendorid 0x70000001 + +deffile ../../../~/usbdi_utils.def + +OS_LAYER_SYSTEMINCLUDE_SYMBIAN +userinclude . + +sourcepath . +source usbtransfers.cpp +source usbtransferstrategy.cpp +source usbinterface.cpp +source usbpipe.cpp +source usbdiutils.cpp +source zerocopytransferstrategy.cpp + +library euser.lib +library usbdescriptors.lib + +SMPSAFE \ No newline at end of file diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,28 @@ +// Copyright (c) 2007-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: +// + +#include "usbdiutils.h" + + +void UsbdiUtils::Panic(UsbdiPanics::TUsbdiPanics aPanic) + { + User::Panic(UsbdiPanics::KUsbdiPanicCat, aPanic); + } + + +void UsbdiUtils::Fault(UsbdiFaults::TUsbdiFaults aFault) + { + User::Panic(UsbdiFaults::KUsbdiFaultCat, aFault); + } diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.h Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,34 @@ +// Copyright (c) 2007-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: +// + +/** + @file + @internalComponent +*/ + +#ifndef USBDIUTILS_H +#define USBDIUTILS_H + +#include + + +NONSHARABLE_CLASS(UsbdiUtils) + { +public: + static void Panic(UsbdiPanics::TUsbdiPanics aPanic); + static void Fault(UsbdiFaults::TUsbdiFaults aFault); + }; + +#endif // USBDIUTILS_H diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/usbinterface.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbinterface.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,154 @@ +// Copyright (c) 2007-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: +// + +#include + +#include +#include "usbtransferstrategy.h" +#include "zerocopytransferstrategy.h" + + +/** +Opens an interface identified by a token. When the hub driver loads a driver (via function driver +framework), this token is generated to allow the driver to open the interface. + +This also causes the interface's descriptors to be parsed for future reference. + +@param[in] aToken The token for the interface to open. +@return System-wide error code. +*/ +EXPORT_C TInt RUsbInterface::Open(TUint32 aToken, TOwnerType aType) + { + TPckgC token(aToken); + TInt err = DoCreate(Name(), VersionRequired(), KNullUnit, NULL, &token, aType); + if(err == KErrNone) + { + // Create a transfer strategy + iTransferStrategy = new RUsbZeroCopyTransferStrategy; + if(!iTransferStrategy) + { + Close(); + return KErrNoMemory; + } + + // Get descriptor size + TInt interfaceDescSize = 0; + err = DoControl(EGetInterfaceDescriptorSize, &interfaceDescSize); + if(err != KErrNone) + { + Close(); + return err; + } + iInterfaceDescriptorData = HBufC8::New(interfaceDescSize); + + if(!iInterfaceDescriptorData) + { + Close(); + return KErrNoMemory; + } + + // Get descriptor data + TPtr8 interfaceDesc = iInterfaceDescriptorData->Des(); + err = DoControl(EGetInterfaceDescriptor, &interfaceDesc); + if(err != KErrNone) + { + Close(); + return err; + } + + // Parse descriptor + TUsbGenericDescriptor* parsed = NULL; + err = UsbDescriptorParser::Parse(*iInterfaceDescriptorData, parsed); + if(err != KErrNone) + { + if(parsed) + { + parsed->DestroyTree(); //or however much has been completed + delete parsed; + } + Close(); + return err; + } + + iHeadInterfaceDescriptor = TUsbInterfaceDescriptor::Cast(parsed); + if(!iHeadInterfaceDescriptor) + { + if(parsed) + { + parsed->DestroyTree(); + delete parsed; + } + Close(); + return KErrCorrupt; + } + } + + return err; + } + +/** +Close handle to interface. + +Closes any pipe handles still open. +*/ +EXPORT_C void RUsbInterface::Close() + { + iAlternateSetting = 0; + if(iHeadInterfaceDescriptor) + { + iHeadInterfaceDescriptor->DestroyTree(); + delete iHeadInterfaceDescriptor; + iHeadInterfaceDescriptor = NULL; + } + if(iInterfaceDescriptorData) + { + delete iInterfaceDescriptorData; + iInterfaceDescriptorData = NULL; + } + if(iTransferStrategy) + { + iTransferStrategy->Close(); + delete iTransferStrategy; + iTransferStrategy = NULL; + } + RBusLogicalChannel::Close(); + } + + +EXPORT_C TInt RUsbInterface::RegisterTransferDescriptor(RUsbTransferDescriptor& aTransfer) + { + TTransferMemoryDetails details; + details.iType = aTransfer.iType; + details.iSize = aTransfer.iMaxSize; + details.iMaxPackets = aTransfer.iMaxNumPackets; + TInt err = DoControl(EGetSizeAndAlignment, &details); + if(err != KErrNone) + { + return err; + } + return iTransferStrategy->RegisterTransferDescriptor(aTransfer, details.iSize, details.iAlignment, details.iMaxPackets); + } + +EXPORT_C void RUsbInterface::ResetTransferDescriptors() + { + iTransferStrategy->ResetTransferDescriptors(); + } + +EXPORT_C TInt RUsbInterface::InitialiseTransferDescriptors() + { + return iTransferStrategy->InitialiseTransferDescriptors(*this); + } + + diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/usbpipe.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbpipe.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,31 @@ +// Copyright (c) 2007-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: +// + +#include +#include + +#include "usbtransferstrategy.h" + + +/** +Queue a transfer. +@param[in] aTransfer The transfer descriptor to execute. +@param[out] aRequest Holds completion status of the transfer. +*/ +EXPORT_C void RUsbPipe::Transfer(RUsbTransferDescriptor& aTransfer, TRequestStatus& aRequest) + { + IssueTransfer(aTransfer.iHandle, aRequest); + } + diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/usbtransfers.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbtransfers.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,205 @@ +// Copyright (c) 2007-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: +// + +#include + +#include +#include "usbtransferstrategy.h" +#include "usbdiutils.h" + + +// ======================== +// RUsbTransferDescriptor +// ======================== + +/** +Constructor protected to as this class is only intended as a base class. +*/ +RUsbTransferDescriptor::RUsbTransferDescriptor(TTransferType aType, TInt aMaxSize, TInt aMaxNumPackets) + : iHandle(KInvalidHandle) + , iType(aType) + , iMaxSize(aMaxSize) + , iMaxNumPackets(aMaxNumPackets) + { + } + +/** +Releases resources allocated to this transfer descriptor. +*/ +void RUsbTransferDescriptor::Close() + { + // Do nothing - the buffer is owned by the {R,D}UsbInterface. + // This is provided in case the descriptor owns resources in future. + } + + +// ============================ +// RUsbIsocTransferDescriptor +// ============================ + +EXPORT_C RUsbIsocTransferDescriptor::RUsbIsocTransferDescriptor(TInt aMaxSize, TInt aMaxNumPackets) + : RUsbTransferDescriptor(EIsochronous, aMaxSize, aMaxNumPackets) + , iWriteHandle(KInvalidHandle) + { + } + +EXPORT_C void RUsbIsocTransferDescriptor::Reset() + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + iWriteHandle = iHandle; + iTransferStrategy->IsocReset(iHandle); + } + +EXPORT_C TPacketLengths RUsbIsocTransferDescriptor::Lengths() + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + return iTransferStrategy->IsocLengths(iHandle); + } + +EXPORT_C TPacketResults RUsbIsocTransferDescriptor::Results() + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + return iTransferStrategy->IsocResults(iHandle); + } + +EXPORT_C TInt RUsbIsocTransferDescriptor::MaxPacketSize() + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + return iTransferStrategy->IsocMaxPacketSize(iHandle); + } + +EXPORT_C TPtr8 RUsbIsocTransferDescriptor::WritablePackets(TInt aNumPacketsRequested, TInt& aMaxNumOfPacketsAbleToWrite) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + if(iWriteHandle == KInvalidHandle) + { + return TPtr8(NULL, 0); + } + return iTransferStrategy->IsocWritablePackets(iHandle, iWriteHandle, aNumPacketsRequested, aMaxNumOfPacketsAbleToWrite); + } + +EXPORT_C void RUsbIsocTransferDescriptor::SaveMultiple(TInt aNumOfPackets) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + __ASSERT_ALWAYS(iWriteHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorWriteHandle)); + TInt writeHandle = iTransferStrategy->IsocSaveMultiple(iHandle, iWriteHandle, aNumOfPackets); + iWriteHandle = (writeHandle < 0) ? KInvalidHandle : writeHandle; + } + +EXPORT_C TPtrC8 RUsbIsocTransferDescriptor::Packets(TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumOfPacketsReturned) const + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + return iTransferStrategy->IsocPackets(iHandle, aFirstPacketIndex, aNumPacketsRequested, aNumOfPacketsReturned); + } + +EXPORT_C void RUsbIsocTransferDescriptor::ReceivePackets(TInt aNumOfPackets) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIsocTransferDescriptorHandle)); + iTransferStrategy->IsocReceivePackets(iHandle, aNumOfPackets); + } + + +// ============================ +// RUsbBulkTransferDescriptor +// ============================ + +EXPORT_C RUsbBulkTransferDescriptor::RUsbBulkTransferDescriptor(TInt aMaxSize) + : RUsbTransferDescriptor(EBulk, aMaxSize, 0) + { + } + +/** +@return A modifiable pointer to the entire data buffer. +*/ +EXPORT_C TPtr8 RUsbBulkTransferDescriptor::WritableBuffer() + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadBulkTransferDescriptorHandle)); + return iTransferStrategy->BulkWritableBuffer(iHandle); + } + +/** +Update the transfer descriptor given the length of data supplied. +@param[in] aLength Length of data to write or expect. +*/ +EXPORT_C void RUsbBulkTransferDescriptor::SaveData(TInt aLength) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadBulkTransferDescriptorHandle)); + iTransferStrategy->BulkSaveData(iHandle, aLength); + } + +/** +@return A non-modifiable pointer to the entire data buffer. +*/ +EXPORT_C TPtrC8 RUsbBulkTransferDescriptor::Buffer() const + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadBulkTransferDescriptorHandle)); + return iTransferStrategy->BulkBuffer(iHandle); + } + +/** +@param aZlpStatus the ZLP type to use for the transfer +*/ +EXPORT_C void RUsbBulkTransferDescriptor::SetZlpStatus(TZlpStatus aZlpStatus) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadBulkTransferDescriptorHandle)); + iTransferStrategy->BulkSetZlpStatus(iHandle, aZlpStatus); + } + + +// ============================ +// RUsbIntrTransferDescriptor +// ============================ + +EXPORT_C RUsbIntrTransferDescriptor::RUsbIntrTransferDescriptor(TInt aMaxSize) + : RUsbTransferDescriptor(EInterrupt, aMaxSize, 0) + { + } + +/** +@return A modifiable pointer to the entire data buffer. +*/ +EXPORT_C TPtr8 RUsbIntrTransferDescriptor::WritableBuffer() + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIntrTransferDescriptorHandle)); + return iTransferStrategy->IntrWritableBuffer(iHandle); + } + +/** +Update the transfer descriptor given the length of data supplied. +@param[in] aLength Length of data to write or expect. +*/ +EXPORT_C void RUsbIntrTransferDescriptor::SaveData(TInt aLength) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIntrTransferDescriptorHandle)); + iTransferStrategy->IntrSaveData(iHandle, aLength); + } + +/** +@return A non-modifiable pointer to the entire data buffer. +*/ +EXPORT_C TPtrC8 RUsbIntrTransferDescriptor::Buffer() const + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIntrTransferDescriptorHandle)); + return iTransferStrategy->IntrBuffer(iHandle); + } + +/** +@param aZlpStatus the ZLP type to use for the transfer +*/ +EXPORT_C void RUsbIntrTransferDescriptor::SetZlpStatus(TZlpStatus aZlpStatus) + { + __ASSERT_ALWAYS(iHandle != KInvalidHandle, UsbdiUtils::Panic(UsbdiPanics::EBadIntrTransferDescriptorHandle)); + return iTransferStrategy->IntrSetZlpStatus(iHandle, aZlpStatus); + } diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,114 @@ +// Copyright (c) 2007-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: +// + +#include "usbtransferstrategy.h" + +#include +#include +#include "usbdiutils.h" + + +TPacketLengths::TPacketLengths(TUint16* aRecvPtr, TUint16* aReqPtr, TInt& aMaxNumPackets) + : iRecvPtr(aRecvPtr) + , iReqPtr(aReqPtr) + , iMaxNumPackets(aMaxNumPackets) + {} + +EXPORT_C TPacketLengths::TLength TPacketLengths::At(TInt aIndex) + { + __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMaxNumPackets, UsbdiUtils::Panic(UsbdiPanics::EOutOfBoundsOfLengthArray)); + return TPacketLengths::TLength(*(iRecvPtr + aIndex), *(iReqPtr + aIndex)); + } + +EXPORT_C const TPacketLengths::TLength TPacketLengths::At(TInt aIndex) const + { + __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMaxNumPackets, UsbdiUtils::Panic(UsbdiPanics::EOutOfBoundsOfLengthArray)); + return TPacketLengths::TLength(*(iRecvPtr + aIndex), *(iReqPtr + aIndex)); + } + +EXPORT_C TPacketLengths::TLength TPacketLengths::operator[](TInt aIndex) + { + return At(aIndex); + } + +EXPORT_C const TPacketLengths::TLength TPacketLengths::operator[](TInt aIndex) const + { + return At(aIndex); + } + +EXPORT_C TInt TPacketLengths::MaxNumPackets() + { + return iMaxNumPackets; + } + +EXPORT_C TUint16 TPacketLengths::TLength::operator=(TUint16 aValue) + { + iRecv = aValue; + iReq = aValue; + return aValue; + } + +EXPORT_C TPacketLengths::TLength::operator TUint16() const + { + return iRecv; + } + +TPacketLengths::TLength::TLength(TUint16& aRecv, TUint16& aReq) + : iRecv(aRecv) + , iReq(aReq) + { + } + + +TPacketResults::TPacketResults(TInt* aResPtr, TInt& aMaxNumPackets) + : iResPtr(aResPtr) + , iMaxNumPackets(aMaxNumPackets) + { + } + +EXPORT_C TInt TPacketResults::At(TInt aIndex) const + { + __ASSERT_ALWAYS(aIndex >= 0 && aIndex < iMaxNumPackets, UsbdiUtils::Panic(UsbdiPanics::EOutOfBoundsOfResultArray)); + return *(iResPtr + aIndex); + } + +EXPORT_C TInt TPacketResults::operator[](TInt aIndex) const + { + return At(aIndex); + } + +EXPORT_C TInt TPacketResults::MaxNumPackets() + { + return iMaxNumPackets; + } + + + +void RUsbTransferStrategy::Close() + { + // Doesn't currently own any resources. + } + +void RUsbTransferStrategy::SetTransferHandle(RUsbTransferDescriptor& aTransfer, TInt aHandle) const + { + aTransfer.iHandle = aHandle; + aTransfer.iTransferStrategy = const_cast(this); + if(aTransfer.iType == RUsbTransferDescriptor::EIsochronous) + { + static_cast(aTransfer).iWriteHandle = aHandle; + } + } + + diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.h Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,64 @@ +// Copyright (c) 2007-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: +// + +/** + @file + @internalComponent +*/ + +#ifndef USBTRANSFERSTRATEGY_H +#define USBTRANSFERSTRATEGY_H + +#include +#include + + +NONSHARABLE_CLASS(RUsbTransferStrategy) + { +public: + virtual void Close(); + + virtual TInt RegisterTransferDescriptor(RUsbTransferDescriptor& aTransferDesc, TInt aRequiredSize, TUint aStartAlignment, TInt aRequiredMaxPackets) =0; + virtual void ResetTransferDescriptors() =0; + virtual TInt InitialiseTransferDescriptors(RUsbInterface& aInterface) =0; + +public: // Interrupt transfer descriptor methods + virtual TPtr8 IntrWritableBuffer(TInt aHandle) =0; + virtual void IntrSaveData(TInt aHandle, TInt aLength) =0; + virtual void IntrSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus) =0; + virtual TPtrC8 IntrBuffer(TInt aHandle) const =0; + +public: // Bulk transfer descriptor methods + virtual TPtr8 BulkWritableBuffer(TInt aHandle) =0; + virtual void BulkSaveData(TInt aHandle, TInt aLength) =0; + virtual void BulkSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus) =0; + virtual TPtrC8 BulkBuffer(TInt aHandle) const =0; + +public: // Isochronous transfer descriptor methods + virtual void IsocReset(TInt aHandle) =0; + virtual TPacketLengths IsocLengths(TInt aHandle) =0; + virtual TPacketResults IsocResults(TInt aHandle) =0; + virtual TInt IsocMaxPacketSize(TInt aHandle) =0; + virtual TPtr8 IsocWritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite) =0; + virtual TInt IsocSaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumOfPackets) =0; + virtual TPtrC8 IsocPackets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const =0; + virtual void IsocReceivePackets(TInt aHandle, TInt aNumOfPackets) =0; + +protected: + void SetTransferHandle(RUsbTransferDescriptor& aTransfer, TInt aHandle) const; + }; + + +#endif // USBTRANSFERSTRATEGY_H diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.h Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,152 @@ +// Copyright (c) 2007-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. +// +// Description: +// + +/** + @file + @internalComponent +*/ + +#ifndef ZEROCOPYMETADATA_H +#define ZEROCOPYMETADATA_H + +#include + +// The type used to represent an address various betwen user and kernel +// mode. To aid us we use a macro to produce only one definition. +#ifndef __KERNEL_MODE__ +#define TAddrType TUint8* +#else // __KERNEL_MODE__ +#define TAddrType TLinAddr +#endif // __KERNEL_MODE__ + + +NONSHARABLE_CLASS(UsbZeroCopyChunkHeaderBase) + { +public: + static inline RUsbTransferDescriptor::TTransferType& TransferType(TAddrType aBase, TInt aHeaderOffset); +protected: + enum THeaderBaseSizes + { + ETransferTypeSize = sizeof(RUsbTransferDescriptor::TTransferType) + }; + enum THeaderBaseLayout + { + ETransferType = 0, + // End of fields + EHeaderBaseSize = ETransferType + ETransferTypeSize + }; + }; + + +NONSHARABLE_CLASS(UsbZeroCopyBulkIntrChunkHeader) : public UsbZeroCopyChunkHeaderBase + { +public: + static inline TInt HeaderSize(); + + static inline TInt& DataOffset(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& DataLength(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& DataMaxLength(TAddrType aBase, TInt aHeaderOffset); + static inline RUsbTransferDescriptor::TZlpStatus& ZlpStatus(TAddrType aBase, TInt aHeaderOffset); +private: + enum THeaderSizes + { + EDataOffsetSize = sizeof(TInt), + EDataLengthSize = sizeof(TInt), + EDataMaxLengthSize = sizeof(TInt), + EZlpStatusSize = sizeof(RUsbTransferDescriptor::TZlpStatus) + }; + enum THeaderLayout + { + EDataOffset = EHeaderBaseSize, + EDataLength = EDataOffset + EDataOffsetSize, + EDataMaxLength = EDataLength + EDataLengthSize, + EZlpStatus = EDataMaxLength + EDataMaxLengthSize, + // End of fields + EHeaderSize = EZlpStatus + EZlpStatusSize + }; + }; + + +NONSHARABLE_CLASS(UsbZeroCopyIsocChunkHeader) : public UsbZeroCopyChunkHeaderBase + { +public: // Lengths Array constants + static const TInt KLengthsElementSize = sizeof(TUint16); + static const TInt KResultsElementSize = sizeof(TInt); +public: + static inline TInt HeaderSize(); + + static inline TInt& FirstElementOffset(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& MaxNumPackets(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& MaxPacketSize(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& LengthsOffset(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& ReqLenOffset(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& ResultsOffset(TAddrType aBase, TInt aHeaderOffset); +private: + enum THeaderSizes + { + EFirstElementOffsetSize = sizeof(TInt), + EMaxNumPacketsSize = sizeof(TInt), + EMaxPacketSizeSize = sizeof(TInt), + ELengthsOffsetSize = sizeof(TInt), + EReqLenOffsetSize = sizeof(TInt), + EResultsOffsetSize = sizeof(TInt) + }; + enum THeaderLayout + { + EFirstElementOffset = EHeaderBaseSize, + EMaxNumPackets = EFirstElementOffset + EFirstElementOffsetSize, + EMaxPacketSize = EMaxNumPackets + EMaxNumPacketsSize, + ELengthsOffset = EMaxPacketSize + EMaxPacketSizeSize, + EReqLenOffset = ELengthsOffset + ELengthsOffsetSize, + EResultsOffset = EReqLenOffset + EReqLenOffsetSize, + // End of fields + EHeaderSize = EResultsOffset + EResultsOffsetSize + }; + }; + + +NONSHARABLE_CLASS(UsbZeroCopyIsocChunkElement) + { +public: + // NumOfPackets constants + static const TInt KInvalidElement = -1; + // NextElementOffset constants + static const TInt KEndOfList = -1; +public: + static inline TInt ElementSize(); + + static inline TInt& DataOffset(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& NumPackets(TAddrType aBase, TInt aHeaderOffset); + static inline TInt& NextElementOffset(TAddrType aBase, TInt aHeaderOffset); +private: + enum THeaderSizes + { + EDataOffsetSize = sizeof(TInt), + ENumPacketsSize = sizeof(TInt), + ENextElementOffsetSize = sizeof(TInt), + }; + enum THeaderLayout + { + EDataOffset = 0, + ENumPackets = EDataOffset + EDataOffsetSize, + ENextElementOffset = ENumPackets + ENumPacketsSize, + // End of fields + EElementSize = ENextElementOffset + ENextElementOffsetSize + }; + }; + +#include "zerocopymetadata.inl" + +#undef TAddrType // Prevent the macro from leaking outside this header + +#endif // ZEROCOPYMETADATA_H diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.inl --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.inl Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,141 @@ +// Copyright (c) 2007-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. +// +// Description: +// + +/** + @file + @internalComponent +*/ + + +template +inline XReturnType& Field(TAddrType aBase, TInt aHeaderOffset) + { + TInt offset = aHeaderOffset + XFieldOffset; + return *reinterpret_cast(aBase + offset); + } + + +// +// UsbZeroCopyChunkHeaderBase +// + +inline RUsbTransferDescriptor::TTransferType& UsbZeroCopyChunkHeaderBase::TransferType(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + + + +// +// UsbZeroCopyBulkIntrChunkHeader +// + +inline TInt UsbZeroCopyBulkIntrChunkHeader::HeaderSize() + { + __ASSERT_COMPILE(EHeaderSize % sizeof(TInt) == 0); + return EHeaderSize; + } + + +inline TInt& UsbZeroCopyBulkIntrChunkHeader::DataOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyBulkIntrChunkHeader::DataLength(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline RUsbTransferDescriptor::TZlpStatus& UsbZeroCopyBulkIntrChunkHeader::ZlpStatus(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + + + +// +// UsbZeroCopyIsocChunkHeader +// + +inline TInt UsbZeroCopyIsocChunkHeader::HeaderSize() + { + __ASSERT_COMPILE(EHeaderSize % sizeof(TInt) == 0); + return EHeaderSize; + } + + +inline TInt& UsbZeroCopyIsocChunkHeader::FirstElementOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkHeader::MaxNumPackets(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkHeader::MaxPacketSize(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkHeader::LengthsOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkHeader::ReqLenOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkHeader::ResultsOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + + + +// +// UsbZeroCopyIsocChunkHeader +// + +inline TInt UsbZeroCopyIsocChunkElement::ElementSize() + { + __ASSERT_COMPILE(EElementSize % sizeof(TInt) == 0); + return EElementSize; + } + + +inline TInt& UsbZeroCopyIsocChunkElement::DataOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkElement::NumPackets(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + +inline TInt& UsbZeroCopyIsocChunkElement::NextElementOffset(TAddrType aBase, TInt aHeaderOffset) + { + return Field(aBase, aHeaderOffset); + } + + diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,982 @@ +// Copyright (c) 2007-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: +// + +#include "zerocopytransferstrategy.h" + +#include +#include +#include +#include "zerocopymetadata.h" +#include "usbdiutils.h" + + +RUsbZeroCopyTransferStrategy::TUsbTransferDescriptorDetails::TUsbTransferDescriptorDetails(RUsbTransferDescriptor& aTransferDesc, TInt aRequiredSize, TUint aRequiredAlignment, TInt aRequiredMaxPackets) + : iTransferDesc(aTransferDesc) + , iRequiredSize(aRequiredSize) + , iRequiredAlignment(aRequiredAlignment) + , iRequiredMaxPackets(aRequiredMaxPackets) + { + } + +RUsbZeroCopyTransferStrategy::RUsbZeroCopyTransferStrategy() + : iInterfaceHandle(NULL) + { + } + + +void RUsbZeroCopyTransferStrategy::Close() + { + iInterfaceHandle = NULL; + iChunk.Close(); + iRegisteredTransfers.Close(); + RUsbTransferStrategy::Close(); + } + + +TInt RUsbZeroCopyTransferStrategy::RegisterTransferDescriptor(RUsbTransferDescriptor& aTransferDesc, TInt aRequiredSize, TUint aStartAlignment, TInt aRequiredMaxPackets) + { + __ASSERT_ALWAYS(!iInterfaceHandle, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorsAlreadyRegistered)); + if (iRegisteredTransfers.Find(aTransferDesc, CompareTransferDescriptor) != KErrNotFound) + { + return KErrAlreadyExists; + } + return iRegisteredTransfers.Append(TUsbTransferDescriptorDetails(aTransferDesc, aRequiredSize, aStartAlignment, aRequiredMaxPackets)); + } + +TBool RUsbZeroCopyTransferStrategy::CompareTransferDescriptor(const RUsbTransferDescriptor* aTransferDesc, const TUsbTransferDescriptorDetails& aDetails) + { + return aTransferDesc == &aDetails.iTransferDesc; + } + + +void RUsbZeroCopyTransferStrategy::ResetTransferDescriptors() + { + __ASSERT_ALWAYS(!iInterfaceHandle, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorsAlreadyRegistered)); + iRegisteredTransfers.Reset(); + } + + +TInt RUsbZeroCopyTransferStrategy::InitialiseTransferDescriptors(RUsbInterface& aInterface) + { + __ASSERT_ALWAYS(!iInterfaceHandle, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorsAlreadyRegistered)); + + // This is the equivilent of a standard R-class Open() method, so initialise the references + // we are going to use. + iInterfaceHandle = &aInterface; + + // First get the page-size as we will need this for isoc transfer calculations. + TInt hcdPageSize = 0; + TInt err = aInterface.GetHcdPageSize(hcdPageSize); + if (err != KErrNone) + { + Close(); // roll back + return err; + } + iPageSize = hcdPageSize; + + TInt currentOffset = 0; + TInt numStandardTransfers = 0; + TInt numIsocTransfers = 0; + TInt numIsocElements = 0; + err = CalculateDataLayout(currentOffset, numStandardTransfers, numIsocTransfers, numIsocElements); + if (err != KErrNone) + { + Close(); // roll back + return err; + } + + TInt metaDataStart = 0; + CalculateMetaDataLayout(currentOffset, metaDataStart, numStandardTransfers, numIsocTransfers, numIsocElements); + + // currentOffset should now be just past the region required for all the data and meta data. + // Therefore it equals the total size of the buffer we need to hold them all. + err = iInterfaceHandle->AllocateSharedChunk(iChunk, currentOffset, iBaseOffset); + if (err != KErrNone) + { + Close(); // roll back + return err; + } + + InitialiseMetaData(metaDataStart, numStandardTransfers, numIsocTransfers, numIsocElements); + + return KErrNone; + } + +TInt RUsbZeroCopyTransferStrategy::CalculateDataLayout(TInt& aCurrentOffset, TInt& aNumStandardTransfers, TInt& aNumIsocTransfers, TInt& aNumIsocElements) + { + const TUint32 pageAddrBits = iPageSize-1; + const TUint32 pageTableMask = ~pageAddrBits; + + //Get the maximum wMaxPacketSize of the associated interface for Bulk/Interrupt EPs + TInt maxMaxBulk = 0; + TInt maxMaxInterrupt = 0; + TInt err = GetMaximumMaxPacketSize(maxMaxBulk, maxMaxInterrupt); + if (err != KErrNone) + { + return err; + } + + // Work out where to place the transfers, and how much space is needed. + TInt numTransfers = iRegisteredTransfers.Count(); + for (TInt i=0; i < numTransfers; ++i) + { + TUsbTransferDescriptorDetails& details = iRegisteredTransfers[i]; + + err = CaculateAdditionalAlignment(aCurrentOffset, maxMaxBulk, maxMaxInterrupt, details); + if (err != KErrNone) + { + return err; + } + + // only allow intra-page alignment requests that are powers of 2 (so offset agnostic). + __ASSERT_ALWAYS(details.iRequiredAlignment <= iPageSize, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorAlignmentOverPageBoundary)); + __ASSERT_ALWAYS(IsPowerOfTwo(details.iRequiredAlignment), UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorAlignmentNotPowerOfTwo)); + + TInt alignPad = IncNeededToAlign(aCurrentOffset, details.iRequiredAlignment); + __ASSERT_DEBUG(alignPad < iPageSize, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadAlignment)); // just re-asserting what should be guarded above + aCurrentOffset += alignPad; // Align to the start of transfer buffer + + // There are stark differences between isoc transfers and transfer of other types. + if (details.iTransferDesc.iType == RUsbTransferDescriptor::EIsochronous) + { + // First do some Isoc specific checks + __ASSERT_ALWAYS(details.iRequiredMaxPackets > 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorNoPacketsRequested)); + + // For the allocation we have to consider the worse case - that is that the max + // number of packets at the max packet size. + // We are constrained by the USB stack to not allow transfers across page boundaries. + + // As such we calculate how many packets we can fit into a page to determine the + // number of pages for data we need. + const TInt packetsPerPage = iPageSize/details.iRequiredSize; + + // Assign the start to an appropriate point. + details.iAssignedOffset = aCurrentOffset; + TInt packetsToStore = details.iRequiredMaxPackets; + TInt numElements = 0; // for counting up the number of pages we need meta-data for. + + // The size requried to hold a length array for the descriptor + const TInt lengthsArrayLength = UsbZeroCopyIsocChunkHeader::KLengthsElementSize * details.iRequiredMaxPackets; + // The size required to hold a result array for the descriptor + const TInt resultsArrayLength = UsbZeroCopyIsocChunkHeader::KResultsElementSize * details.iRequiredMaxPackets; + + // Determine how much we can fit into the remaining space of the current page. + TBool samePage = (pageTableMask & aCurrentOffset) == (pageTableMask & (aCurrentOffset - alignPad)); + if (samePage) + { + TInt remainingSpace = iPageSize - (pageAddrBits & aCurrentOffset); + TInt packetsThatFit = remainingSpace / details.iRequiredSize; + if (packetsThatFit >= packetsToStore) + { + // We can fit it in this page so we finish here - this is the special case. + aCurrentOffset += packetsToStore * details.iRequiredSize; + ++aNumIsocElements; + ++aNumIsocTransfers; + details.iNumElements = 1; + // Do the lengths array + aCurrentOffset += IncNeededToAlign(aCurrentOffset, UsbZeroCopyIsocChunkHeader::KLengthsElementSize); + details.iLengthsOffset = aCurrentOffset; + aCurrentOffset += lengthsArrayLength; + // The dual lengths array should be implicitly alligned + details.iReqLenOffset = aCurrentOffset; + aCurrentOffset += lengthsArrayLength; + // Now handle the results array + aCurrentOffset += IncNeededToAlign(aCurrentOffset, UsbZeroCopyIsocChunkHeader::KResultsElementSize); + details.iResultsOffset = aCurrentOffset; + aCurrentOffset += resultsArrayLength; + continue; + } + aCurrentOffset = (pageTableMask & aCurrentOffset) + iPageSize; // Advance to next page + packetsToStore -= packetsThatFit; + ++numElements; + } + __ASSERT_DEBUG(packetsToStore > 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorNoPacketsLeftToStore)); + + // Determine the number of pages extra that are needed (minus one) + TInt pagesRequired = packetsToStore / packetsPerPage; + + // Determine how much of the last page is actually needed. + TInt trailingPackets = packetsToStore % packetsPerPage; + TInt usedSpace = trailingPackets * details.iRequiredSize; + + // Commit the amount for the buffers. + aCurrentOffset += usedSpace + pagesRequired*iPageSize; + numElements += pagesRequired + /*the final page*/1; // We have already included the first page (if already partially used) + aNumIsocElements += numElements; + ++aNumIsocTransfers; + + // Used to ensure only allocate an appropriate number per-descriptor. + details.iNumElements = numElements; + + // We also need an array of lengths for each packet that we use (need to align to even bytes). + aCurrentOffset += IncNeededToAlign(aCurrentOffset, UsbZeroCopyIsocChunkHeader::KLengthsElementSize); + details.iLengthsOffset = aCurrentOffset; + aCurrentOffset += lengthsArrayLength; + // Dual length array should be implicitly aligned + details.iReqLenOffset = aCurrentOffset; + aCurrentOffset += lengthsArrayLength; + // Now handle the results array + aCurrentOffset += IncNeededToAlign(aCurrentOffset, UsbZeroCopyIsocChunkHeader::KResultsElementSize); + details.iResultsOffset = aCurrentOffset; + aCurrentOffset += resultsArrayLength; + } + else + { + details.iAssignedOffset = aCurrentOffset; + aCurrentOffset += details.iRequiredSize; + ++aNumStandardTransfers; + } + } + + return KErrNone; + } + + +void RUsbZeroCopyTransferStrategy::CalculateMetaDataLayout(TInt& aCurrentOffset, TInt& aMetaDataStart, TInt aNumStandardTransfers, TInt aNumIsocTransfers, TInt aNumIsocElements) + { + // Round up to 4 byte alignment for handling the meta-data correctly. + aCurrentOffset += IncNeededToAlign(aCurrentOffset, sizeof(TInt)); + + aMetaDataStart = aCurrentOffset; + + // Now calculate the size required for the transfer meta-data. + aCurrentOffset += aNumStandardTransfers * UsbZeroCopyBulkIntrChunkHeader::HeaderSize(); + aCurrentOffset += aNumIsocTransfers * UsbZeroCopyIsocChunkHeader::HeaderSize(); + aCurrentOffset += aNumIsocElements * UsbZeroCopyIsocChunkElement::ElementSize(); + } + +void RUsbZeroCopyTransferStrategy::InitialiseMetaData(TInt aMetaDataOffset, TInt aNumStandardTransfers, TInt aNumIsocTransfers, TInt aNumIsocElements) + { + const TUint32 pageAddrBits = iPageSize-1; + const TUint32 pageTableMask = ~pageAddrBits; + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TInt numTransfers = iRegisteredTransfers.Count(); + for (TInt i=0; i < numTransfers; ++i) + { + TUsbTransferDescriptorDetails details = iRegisteredTransfers[i]; + + if (details.iTransferDesc.iType == RUsbTransferDescriptor::EIsochronous) + { + // Initialise Meta-data (minus elements). + UsbZeroCopyIsocChunkHeader::TransferType(chunkBase, aMetaDataOffset) = details.iTransferDesc.iType; + UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aMetaDataOffset) = details.iRequiredMaxPackets; + UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aMetaDataOffset) = details.iRequiredSize; + // Double check that the length array is aligned correctly. + __ASSERT_DEBUG(details.iLengthsOffset % UsbZeroCopyIsocChunkHeader::KLengthsElementSize == 0, + UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorLengthsArrayBadAlignment)); + UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aMetaDataOffset) = details.iLengthsOffset; + UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aMetaDataOffset) = details.iReqLenOffset; + // Double check that the result array is aligned correctly. + __ASSERT_DEBUG(details.iResultsOffset % UsbZeroCopyIsocChunkHeader::KResultsElementSize == 0, + UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorResultsArrayBadAlignment)); + UsbZeroCopyIsocChunkHeader::ResultsOffset(chunkBase, aMetaDataOffset) = details.iResultsOffset; + // Initialise transfer descriptor + SetTransferHandle(details.iTransferDesc, aMetaDataOffset); + // Move on to next meta-data slot + TInt prevMetaOffset = aMetaDataOffset; + aMetaDataOffset += UsbZeroCopyIsocChunkHeader::HeaderSize(); + + // Initialise elements for transfers + UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, prevMetaOffset) = aMetaDataOffset; + + TInt isocElementsUnmapped = details.iNumElements; + // First element could be anywhere, the others are at the start of (virtually) contiguous pages + TInt offset = details.iAssignedOffset; + while (isocElementsUnmapped > 0) + { + // Update the data references + UsbZeroCopyIsocChunkElement::DataOffset(chunkBase, aMetaDataOffset) = offset; + UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, aMetaDataOffset) = 0; // Default value. + // Move on to the next element and bind it to the chain. + prevMetaOffset = aMetaDataOffset; + aMetaDataOffset += UsbZeroCopyIsocChunkElement::ElementSize(); + UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, prevMetaOffset) = aMetaDataOffset; + // Move to the next page + offset = (pageTableMask&offset)+iPageSize; + --isocElementsUnmapped; + --aNumIsocElements; + } + // We have reached the end of the list so we should update the next element offset for the + // last element to indicate that it is the terminator. + UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, prevMetaOffset) = UsbZeroCopyIsocChunkElement::KEndOfList; + --aNumIsocTransfers; + } + else + { + // Initialise Meta-data. + UsbZeroCopyBulkIntrChunkHeader::TransferType(chunkBase, aMetaDataOffset) = details.iTransferDesc.iType; + UsbZeroCopyBulkIntrChunkHeader::DataOffset(chunkBase, aMetaDataOffset) = details.iAssignedOffset; + UsbZeroCopyBulkIntrChunkHeader::DataLength(chunkBase, aMetaDataOffset) = 0; + UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(chunkBase, aMetaDataOffset) = details.iRequiredSize; + UsbZeroCopyBulkIntrChunkHeader::ZlpStatus(chunkBase, aMetaDataOffset) = RUsbTransferDescriptor::ESendZlpIfRequired; + // Initialise transfer descriptor + SetTransferHandle(details.iTransferDesc, aMetaDataOffset); + // Move on to next meta-data slot + aMetaDataOffset += UsbZeroCopyBulkIntrChunkHeader::HeaderSize(); + --aNumStandardTransfers; + } + } + + __ASSERT_DEBUG(aNumStandardTransfers == 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorIncompleteInitialisation)); + __ASSERT_DEBUG(aNumIsocTransfers == 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorIncompleteInitialisation)); + __ASSERT_DEBUG(aNumIsocElements == 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorIncompleteInitialisation)); + } + + +TBool RUsbZeroCopyTransferStrategy::IsPowerOfTwo(TUint aNumber) + { + return aNumber && !(aNumber & (aNumber - 1)); //this returns true if the integer is a power of two + } + + +TInt RUsbZeroCopyTransferStrategy::IncNeededToAlign(TInt aOffset, TUint aAlignment) + { + if (aAlignment == 0) + { + return 0; + } + TInt remain = aOffset % aAlignment; + return (aAlignment - remain) % aAlignment; + } + + +// Standard Methods + +TPtr8 RUsbZeroCopyTransferStrategy::WritableBuffer(TInt aHandle) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TUint8* dataPtr = chunkBase + UsbZeroCopyBulkIntrChunkHeader::DataOffset(chunkBase, aHandle); + TInt maxLength = UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(chunkBase, aHandle); + + return TPtr8(dataPtr, 0, maxLength); + } + +void RUsbZeroCopyTransferStrategy::SaveData(TInt aHandle, TInt aLength) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TInt maxLength = UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(chunkBase, aHandle); + __ASSERT_ALWAYS(aLength <= maxLength, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorSavedToMuchData)); + + UsbZeroCopyBulkIntrChunkHeader::DataLength(chunkBase, aHandle) = aLength; + } + +void RUsbZeroCopyTransferStrategy::SetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + UsbZeroCopyBulkIntrChunkHeader::ZlpStatus(chunkBase, aHandle) = aZlpStatus; + } + +TPtrC8 RUsbZeroCopyTransferStrategy::Buffer(TInt aHandle) const + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TUint8* dataPtr = chunkBase + UsbZeroCopyBulkIntrChunkHeader::DataOffset(chunkBase, aHandle); + TInt length = UsbZeroCopyBulkIntrChunkHeader::DataLength(chunkBase, aHandle); + + return TPtrC8(dataPtr, length); + } + + + + +// Isochronous Methods + +void RUsbZeroCopyTransferStrategy::Reset(TInt aHandle) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + // Loop through and reset number of packets in each element as 0 + TInt elementOffset = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle); + while (elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList) + { + UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset) = 0; + elementOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, elementOffset); + } + } + +TPacketLengths RUsbZeroCopyTransferStrategy::Lengths(TInt aHandle) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TInt lengthsOffset = UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aHandle); + TUint16* lengthsPtr = reinterpret_cast(chunkBase + lengthsOffset); + + TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle); + TUint16* reqLenPtr = reinterpret_cast(chunkBase + reqLenOffset); + + TInt& maxNumPackets = UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle); + + return TPacketLengths(lengthsPtr, reqLenPtr, maxNumPackets); + } + +TPacketResults RUsbZeroCopyTransferStrategy::Results(TInt aHandle) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TInt resultsOffset = UsbZeroCopyIsocChunkHeader::ResultsOffset(chunkBase, aHandle); + TInt* resultsPtr = reinterpret_cast(chunkBase + resultsOffset); + + TInt& maxNumPackets = UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle); + + return TPacketResults(resultsPtr, maxNumPackets); + } + +TInt RUsbZeroCopyTransferStrategy::MaxPacketSize(TInt aHandle) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + TInt maxPacketSize = UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle); + + return maxPacketSize; + } + +TPtr8 RUsbZeroCopyTransferStrategy::WritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + __ASSERT_DEBUG(aWriteHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadWriteHandle)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + const TUint32 pageAddrBits = iPageSize-1; + const TUint32 pageTableMask = ~pageAddrBits; + + if (aHandle == aWriteHandle) + { + // The initial write handle will be the same as the standard handle so we need to find the actual + // element to work correctly. + aWriteHandle = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle); + } + + // Now we have two cases - the number of packets requested is contained in one page, or it crosses the page. + // 1) If we cross the page then we get the buffer for upto the end of the page, and inform the user of the number + // of packets they are able to write into it (normally this will be quite high as we can consider 0 length + // packets.) + // 2) If we are on one page then we provide a buffer to the end of the page and return the number of packets + // the requested as the max they can write. However we also now mark it so that an attempt to get a subsequent + // writable buffer will return a 0 max length TPtr8 and 0 max number of packets to write. If they want write + // more they need to reset the descriptor and start again. + + if (UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, aWriteHandle) == UsbZeroCopyIsocChunkElement::KInvalidElement) + { + // Here we are testing the second case, if we previously marked an element as invalid then we must not + // return a valid buffer. + aMaxNumPacketsAbleToWrite = 0; + return TPtr8(NULL, 0); + } + + TInt dataOffset = UsbZeroCopyIsocChunkElement::DataOffset(chunkBase, aWriteHandle); + + TUint8* dataPtr = chunkBase + dataOffset; + TInt totalMaxSize = aNumPacketsRequested * UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle); + // The USB stack requires isoc transfer to be limited to a page (not allowed to cross the boundary). + TUint32 dataAddr = reinterpret_cast(dataPtr); + TBool samePage = (pageTableMask & dataAddr) == (pageTableMask & (dataAddr + totalMaxSize)); + TInt allowableSize = samePage ? totalMaxSize : iPageSize - (pageAddrBits & dataAddr); + + TInt numPacketsRemaining = UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle) - UsedPackets(aHandle); + + if (aNumPacketsRequested < numPacketsRemaining) + { + // This is the 2nd case as documented in the comment. So we mark the next packet as invalid. + aMaxNumPacketsAbleToWrite = aNumPacketsRequested; + TInt nextElement = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, aWriteHandle); + if (nextElement != UsbZeroCopyIsocChunkElement::KEndOfList) + { + UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, nextElement) = UsbZeroCopyIsocChunkElement::KInvalidElement; // Mark as invalid. + } + // else we are at the end of the list anyway + } + else + { + aMaxNumPacketsAbleToWrite = numPacketsRemaining; + } + + return TPtr8(dataPtr, allowableSize); + } + +TInt RUsbZeroCopyTransferStrategy::SaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumPackets) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + __ASSERT_DEBUG(aWriteHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadWriteHandle)); + __ASSERT_ALWAYS(aNumPackets > 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorNoPacketsToSave)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + if (aHandle == aWriteHandle) + { + aWriteHandle = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle); + } + + // if marked invalid then they shouldn't try to save it (they haven't been able to write anything into the data anyway). + __ASSERT_ALWAYS(UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, aWriteHandle) != UsbZeroCopyIsocChunkElement::KInvalidElement, + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorInvalidSaveCall)); + + // Ensure they've not tried to write in too many packets + TInt usedPackets = UsedPackets(aHandle); + __ASSERT_ALWAYS(aNumPackets + usedPackets <= UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle), + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorSavedTooManyPackets)); + + // Check that the length values have not exceeded the maximum. + TInt maxPacketSize = UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle); + TInt lengthsOffset = UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aHandle); + TUint16* lengthsPtr = reinterpret_cast(chunkBase + lengthsOffset); +#ifdef _DEBUG + // The requested length is only functionally needed for IN transfers, but it provides an + // extra check that the length values that were requested by the user are those that are + // been requested on the USB stack. + TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle); + TUint16* reqLenPtr = reinterpret_cast(chunkBase + reqLenOffset); +#endif // _DEBUG + for (TInt i=0; i < aNumPackets; ++i) + { + __ASSERT_ALWAYS(lengthsPtr[usedPackets + i] <= maxPacketSize, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorSavingTooLargeAPacket)); + __ASSERT_DEBUG(lengthsPtr[usedPackets + i] == reqLenPtr[usedPackets + i], UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorRequestedLengthDiffers)); // Belt 'n' Braces + } + + // Commit the packets to the transfer descriptor. + UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, aWriteHandle) = aNumPackets; + TInt headerOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, aWriteHandle); + + // Return the handle to the next region for writing. + return (headerOffset == UsbZeroCopyIsocChunkElement::KEndOfList) ? KErrEof : headerOffset; + } + +/** +Used to walk the elements to total up the number of packets that have been saved in the transfer descriptor. +*/ +TInt RUsbZeroCopyTransferStrategy::UsedPackets(TInt aHeaderOffset) + { + __ASSERT_DEBUG(aHeaderOffset >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorInvalidHeaderOffset)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + TInt elementOffset = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHeaderOffset); + TInt totalNumPackets = 0; + while (elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList) + { + TInt numPackets = UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset); + if (numPackets == 0 || numPackets == UsbZeroCopyIsocChunkElement::KInvalidElement) + { + break; + } + totalNumPackets += numPackets; + elementOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, elementOffset); + } + return totalNumPackets; + } + +/** +Used to read packets out from the transfer descriptor. +Note that some of the panics are belt'n'braces, and are used to sanity test result that has been +provided. These should be correct (as the results are set by the kernel), however because the user +has access to length array (for writing out packets) it is possible for them to 'corrupt' the result. +We panic explicitly in UDEB builds, in UREL the guards are not present and the user may get returned +a bad descriptor. +*/ +TPtrC8 RUsbZeroCopyTransferStrategy::Packets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + __ASSERT_ALWAYS(aFirstPacketIndex >= 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorPacketNotInBounds)); + __ASSERT_ALWAYS(aNumPacketsRequested > 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorTooFewPacketsRequested)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + __ASSERT_ALWAYS(aNumPacketsRequested <= UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle), + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorTooManyPacketsRequested)); + +#ifdef _DEBUG + const TUint32 pageAddrBits = iPageSize-1; + const TUint32 pageTableMask = ~pageAddrBits; +#endif // _DEBUG + const TInt maxPacketSize = UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle); + + TInt elementOffset = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle); + TInt packetCount = 0; + while (elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList) + { + TInt numPackets = UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset); + if (numPackets == 0 || numPackets == UsbZeroCopyIsocChunkElement::KInvalidElement) + { + // We've got to the end of the elements and not found the packets we are after. + break; + } + TInt previousPacketCount = packetCount; + packetCount += numPackets; + if (aFirstPacketIndex < packetCount) // If true then start packet must be in this element + { + TInt intraElementIndex = aFirstPacketIndex - previousPacketCount; + TInt maxPacketsForReturn = packetCount - aFirstPacketIndex; + + TInt lengthsOffset = UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aHandle); + TUint16* lengthsPtr = reinterpret_cast(chunkBase + lengthsOffset + previousPacketCount * sizeof(TUint16)); + TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle); + TUint16* reqLenPtr = reinterpret_cast(chunkBase + reqLenOffset + previousPacketCount * sizeof(TUint16)); + + aNumPacketsReturned = (aNumPacketsRequested < maxPacketsForReturn) ? aNumPacketsRequested : maxPacketsForReturn; + + TInt distanceToReqPacket = 0; + for (TInt i=0; i < intraElementIndex; ++i) + { + TUint16 reqLen = reqLenPtr[i]; + __ASSERT_DEBUG(reqLen <= maxPacketSize, + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorReceivedTooLargeAPacket)); // Belt'n'Braces + distanceToReqPacket += reqLen; + } + TInt dataOffset = UsbZeroCopyIsocChunkElement::DataOffset(chunkBase, elementOffset); + TUint8* dataPtr = chunkBase + dataOffset + distanceToReqPacket; + + TInt totalLengthPackets = 0; + for (TInt i=0; i < aNumPacketsReturned; ++i) + { + TUint16 len = lengthsPtr[intraElementIndex + i]; + TUint16 reqLen = reqLenPtr[intraElementIndex + i]; + __ASSERT_DEBUG(len <= maxPacketSize, + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorReceivedTooLargeAPacket)); // Belt'n'Braces + + totalLengthPackets += len; + + // Here we handle the potential gaps that may appear in the data stream if a short + // packet is received. + if (len < reqLen) + { + // if here then we received a short packet, as such we can only return up to here + aNumPacketsReturned = i+1; + break; + } + // Otherwise we expect them to be equal (if we got more than requested then something odd has happened. + __ASSERT_DEBUG(len == reqLen, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorRequestedLengthDiffers)); // Belt 'n' Braces + } + + // The USB stack requires isoc transfer to be limited to a page (not allowed to cross the boundary). + // Therefore one of our elements must have data only on one page. +#ifdef _DEBUG + TUint32 dataAddr = reinterpret_cast(dataPtr); + TBool samePage = (totalLengthPackets == 0) || (pageTableMask & dataAddr) == (pageTableMask & (dataAddr + totalLengthPackets - 1)); + __ASSERT_DEBUG(samePage, UsbdiUtils::Panic(UsbdiPanics::EIsocTransferResultCrossesPageBoundary)); // Belt'n'Braces +#endif // _DEBUG + + return TPtrC8(dataPtr, totalLengthPackets); + } + + // No luck so far, move on to try the next element + elementOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, elementOffset); + } + + // No suitable packet range found. + aNumPacketsReturned = 0; + return TPtrC8(NULL, 0); + } + +void RUsbZeroCopyTransferStrategy::ReceivePackets(TInt aHandle, TInt aNumPackets) + { + __ASSERT_DEBUG(aHandle >= 0, UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorBadHandle)); + __ASSERT_ALWAYS(aNumPackets > 0, UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorTooFewPacketsRequested)); + + TUint8* chunkBase = iChunk.Base() + iBaseOffset; + + __ASSERT_ALWAYS(aNumPackets <= UsbZeroCopyIsocChunkHeader::MaxNumPackets(chunkBase, aHandle), + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorTooManyPacketsRequested)); + + const TUint32 pageAddrBits = iPageSize-1; + const TUint32 pageTableMask = ~pageAddrBits; + const TInt maxPacketSize = UsbZeroCopyIsocChunkHeader::MaxPacketSize(chunkBase, aHandle); + +#ifdef _DEBUG + // Here we make the best check we can that the user has set-up the requested lengths they require. + // If there is a difference, they have either a corrupted metadata chunk, or they are reusing a + // previous buffer without setting the lengths requested. + TInt lengthsOffset = UsbZeroCopyIsocChunkHeader::LengthsOffset(chunkBase, aHandle); + TUint16* lengthsPtr = reinterpret_cast(chunkBase + lengthsOffset); + TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle); + TUint16* reqLenPtr = reinterpret_cast(chunkBase + reqLenOffset); + for (TInt i=0; i < aNumPackets; ++i) + { + __ASSERT_DEBUG(lengthsPtr[i] == reqLenPtr[i], + UsbdiUtils::Panic(UsbdiPanics::ETransferDescriptorRequestedLengthDiffers)); // Belt 'n' Braces + } +#endif // _DEBUG + + TInt elementOffset = UsbZeroCopyIsocChunkHeader::FirstElementOffset(chunkBase, aHandle); + while (aNumPackets) + { + __ASSERT_DEBUG(elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList, + UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorUnexpectedEndOfIsocList)); + + TInt totalMaxSize = aNumPackets * maxPacketSize; + + TInt dataOffset = UsbZeroCopyIsocChunkElement::DataOffset(chunkBase, elementOffset); + TUint8* dataPtr = chunkBase + dataOffset; + TUint32 dataAddr = reinterpret_cast(dataPtr); + TBool samePage = (pageTableMask & dataAddr) == (pageTableMask & (dataAddr + totalMaxSize)); + TInt allowableSize = samePage ? totalMaxSize : iPageSize - (pageAddrBits & dataAddr); + TInt numPackets = allowableSize / maxPacketSize; + + // TODO We could assert here in debug as a double check using UsedPackets() + + __ASSERT_DEBUG(numPackets > 0, + UsbdiUtils::Fault(UsbdiFaults::EUsbTransferDescriptorUnfillableElement)); + + UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset) = numPackets; + aNumPackets -= numPackets; + + elementOffset = UsbZeroCopyIsocChunkElement::NextElementOffset(chunkBase, elementOffset); + } + + if (elementOffset != UsbZeroCopyIsocChunkElement::KEndOfList) + { + UsbZeroCopyIsocChunkElement::NumPackets(chunkBase, elementOffset) = UsbZeroCopyIsocChunkElement::KInvalidElement; // Mark as invalid. + } + } + + + + + +TPtr8 RUsbZeroCopyTransferStrategy::IntrWritableBuffer(TInt aHandle) + { + return WritableBuffer(aHandle); + } + +void RUsbZeroCopyTransferStrategy::IntrSaveData(TInt aHandle, TInt aLength) + { + SaveData(aHandle, aLength); + } + +void RUsbZeroCopyTransferStrategy::IntrSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus) + { + SetZlpStatus(aHandle, aZlpStatus); + } + +TPtrC8 RUsbZeroCopyTransferStrategy::IntrBuffer(TInt aHandle) const + { + return Buffer(aHandle); + } + +TPtr8 RUsbZeroCopyTransferStrategy::BulkWritableBuffer(TInt aHandle) + { + return WritableBuffer(aHandle); + } + +void RUsbZeroCopyTransferStrategy::BulkSaveData(TInt aHandle, TInt aLength) + { + SaveData(aHandle, aLength); + } + +void RUsbZeroCopyTransferStrategy::BulkSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus) + { + SetZlpStatus(aHandle, aZlpStatus); + } + +TPtrC8 RUsbZeroCopyTransferStrategy::BulkBuffer(TInt aHandle) const + { + return Buffer(aHandle); + } + +void RUsbZeroCopyTransferStrategy::IsocReset(TInt aHandle) + { + Reset(aHandle); + } + +TPacketLengths RUsbZeroCopyTransferStrategy::IsocLengths(TInt aHandle) + { + return Lengths(aHandle); + } + +TPacketResults RUsbZeroCopyTransferStrategy::IsocResults(TInt aHandle) + { + return Results(aHandle); + } + +TInt RUsbZeroCopyTransferStrategy::IsocMaxPacketSize(TInt aHandle) + { + return MaxPacketSize(aHandle); + } + +TPtr8 RUsbZeroCopyTransferStrategy::IsocWritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite) + { + return WritablePackets(aHandle, aWriteHandle, aNumPacketsRequested, aMaxNumPacketsAbleToWrite); + } + +TInt RUsbZeroCopyTransferStrategy::IsocSaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumOfPackets) + { + return SaveMultiple(aHandle, aWriteHandle, aNumOfPackets); + } + +TPtrC8 RUsbZeroCopyTransferStrategy::IsocPackets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const + { + return Packets(aHandle, aFirstPacketIndex, aNumPacketsRequested, aNumPacketsReturned); + } + +void RUsbZeroCopyTransferStrategy::IsocReceivePackets(TInt aHandle, TInt aNumOfPackets) + { + ReceivePackets(aHandle, aNumOfPackets); + } + + +//Calculate-alignment related methods + +/** + Scan through all the bulk/interrupt endpoints associated with the particular interface + (and all its alternate settings) to find the maximum bMaxPacketSize across all of these. + For Interrupt, if there is EP of which the maxPacketSize is not power of 2, + the maxmaxpaceketsize will be assigned the first maxPacketSize which is not power of 2. +*/ +TInt RUsbZeroCopyTransferStrategy::GetMaximumMaxPacketSize(TInt& aMaxMaxBulk, TInt& aMaxMaxInterrupt) + { + TUsbInterfaceDescriptor interfaceDesc; + TInt err = iInterfaceHandle->GetInterfaceDescriptor(interfaceDesc); + if (KErrNone != err) + { + return err; + } + + const TUint8 KEPTransferTypeBulk = 0x02; + const TUint8 KEPTransferTypeInterrupt = 0x03; + const TUint8 KEPTransferTypeMask = 0x03; + + TBool ignoreInterruptEP = EFalse; + //Traverse all related interface alternate settings + TUsbGenericDescriptor* descriptor = &interfaceDesc; + while (descriptor) + { + TUsbInterfaceDescriptor* interface = TUsbInterfaceDescriptor::Cast(descriptor); + + if (interface) + { + //Traverse all endpoint descriptor in the interface + TUsbGenericDescriptor* subDescriptor = interface->iFirstChild; + + while (subDescriptor) + { + TUsbEndpointDescriptor* endpoint = TUsbEndpointDescriptor::Cast(subDescriptor); + + if (endpoint) + { + TBool isBulkEP = ((endpoint->Attributes() & KEPTransferTypeMask) == KEPTransferTypeBulk); + TBool isInterruptEP = ((endpoint->Attributes() & KEPTransferTypeMask) == KEPTransferTypeInterrupt); + TUint maxPacketSize = endpoint->MaxPacketSize(); + + //Caculate the maximum maxPacketSize + if (isBulkEP) + { + if (maxPacketSize > aMaxMaxBulk) + { + aMaxMaxBulk = maxPacketSize; + } + } + else if(isInterruptEP && !ignoreInterruptEP) + { + if (!IsPowerOfTwo(maxPacketSize)) + { + aMaxMaxInterrupt = maxPacketSize; + ignoreInterruptEP = ETrue; + } + + if (maxPacketSize > aMaxMaxInterrupt) + { + aMaxMaxInterrupt = maxPacketSize; + } + } + } + + subDescriptor = subDescriptor->iNextPeer; + } + } + + descriptor = descriptor->iNextPeer; + } + + return KErrNone; + } + +/** +Calculate the additional alignment requirement on bulk and interrupt transfer. +For Bulk transfer, + Scan through all the bulk/interrupt endpoints associated with the particular interface + to find the maximum wMaxPacketSize across all of these. The new alignment for the transfer + is the maximum between the maximum bMaxPacketSize and the original alignment +For Interrupt transfer, + Check if there is endpoints of which the wMaxPacketSize is not power of 2, + if no, do the same as bulk; + if yes, the size of transfer data is limited to one page size, and the additional alignment + calcualted to make the transfer data not to span page boundary + +*/ +TInt RUsbZeroCopyTransferStrategy::CaculateAdditionalAlignment(TInt aCurrentOffset, TInt aMaxMaxBulk, TInt aMaxMaxInterrupt, TUsbTransferDescriptorDetails& aTransferDetails) + { + RUsbTransferDescriptor::TTransferType transferType = aTransferDetails.iTransferDesc.iType; + TBool isBulkTransfer = (transferType == RUsbTransferDescriptor::EBulk); + TBool isInterruptTransfer = (transferType == RUsbTransferDescriptor::EInterrupt); + + if (isBulkTransfer) + { + if (aMaxMaxBulk > aTransferDetails.iRequiredAlignment) + { + aTransferDetails.iRequiredAlignment = aMaxMaxBulk; + } + } + else if (isInterruptTransfer) + { + if (IsPowerOfTwo(aMaxMaxInterrupt)) + { + if (aMaxMaxInterrupt > aTransferDetails.iRequiredAlignment) + { + aTransferDetails.iRequiredAlignment = aMaxMaxInterrupt; + } + } + else + { + if (aTransferDetails.iRequiredSize > iPageSize) + { + //The transfer data can not span the page boundary + //if there is EP of which wMaxPacketSize is not power-of-2, + return KErrNotSupported; + } + else + { + TInt sizeLeftOfCurrentPage = IncNeededToAlign(aCurrentOffset,iPageSize); + TInt alignPad = IncNeededToAlign(aCurrentOffset, aTransferDetails.iRequiredAlignment); + + //The transfer data can't fit into the current page + //Align the trasfer data to the next page + if ( sizeLeftOfCurrentPage < (alignPad + aTransferDetails.iRequiredSize) ) + { + aTransferDetails.iRequiredAlignment = iPageSize; + } + } + } + } + return KErrNone; + } diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.h Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,112 @@ +// Copyright (c) 2007-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: +// + +/** + @file + @internalComponent +*/ + +#ifndef ZEROCOPYTRANSFERSTRATEGY_H +#define ZEROCOPYTRANSFERSTRATEGY_H + +#include "usbtransferstrategy.h" + + +NONSHARABLE_CLASS(RUsbZeroCopyTransferStrategy) : public RUsbTransferStrategy + { +public: + RUsbZeroCopyTransferStrategy(); + virtual TInt RegisterTransferDescriptor(RUsbTransferDescriptor& aTransferDesc, TInt aRequiredSize, TUint aStartAlignment, TInt aRequiredMaxPackets); + virtual void ResetTransferDescriptors(); + virtual TInt InitialiseTransferDescriptors(RUsbInterface& aInterface); + + virtual void Close(); + +public: // Interrupt transfer descriptor methods + virtual TPtr8 IntrWritableBuffer(TInt aHandle); + virtual void IntrSaveData(TInt aHandle, TInt aLength); + virtual void IntrSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus); + virtual TPtrC8 IntrBuffer(TInt aHandle) const; +public: // Bulk transfer descriptor methods + virtual TPtr8 BulkWritableBuffer(TInt aHandle); + virtual void BulkSaveData(TInt aHandle, TInt aLength); + virtual void BulkSetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus); + virtual TPtrC8 BulkBuffer(TInt aHandle) const; +public: // Isochronous transfer descriptor methods + virtual void IsocReset(TInt aHandle); + virtual TPacketLengths IsocLengths(TInt aHandle); + virtual TPacketResults IsocResults(TInt aHandle); + virtual TInt IsocMaxPacketSize(TInt aHandle); + virtual TPtr8 IsocWritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite); + virtual TInt IsocSaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumOfPackets); + virtual TPtrC8 IsocPackets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const; + virtual void IsocReceivePackets(TInt aHandle, TInt aNumOfPackets); + + +private: // Standard (Bulk, Ctrl and Intr) Buffer methods + TPtr8 WritableBuffer(TInt aHandle); + void SaveData(TInt aHandle, TInt aLength); + void SetZlpStatus(TInt aHandle, RUsbTransferDescriptor::TZlpStatus aZlpStatus); + TPtrC8 Buffer(TInt aHandle) const; + +private: // Isoc Buffer methods + void Reset(TInt aHandle); + TPacketLengths Lengths(TInt aHandle); + TPacketResults Results(TInt aHandle); + TInt MaxPacketSize(TInt aHandle); + TPtr8 WritablePackets(TInt aHandle, TInt aWriteHandle, TInt aNumPacketsRequested, TInt& aMaxNumPacketsAbleToWrite); + TInt SaveMultiple(TInt aHandle, TInt aWriteHandle, TInt aNumOfPackets); + TPtrC8 Packets(TInt aHandle, TInt aFirstPacketIndex, TInt aNumPacketsRequested, TInt& aNumPacketsReturned) const; + void ReceivePackets(TInt aHandle, TInt aNumOfPackets); + +private: + NONSHARABLE_STRUCT(TUsbTransferDescriptorDetails) + { + TUsbTransferDescriptorDetails(RUsbTransferDescriptor&, TInt, TUint, TInt); + RUsbTransferDescriptor& iTransferDesc; + const TInt iRequiredSize; + TUint iRequiredAlignment; + const TInt iRequiredMaxPackets; + // Members to aid internal logic + TInt iAssignedOffset; + TInt iLengthsOffset; // Only applicable to isoc + TInt iReqLenOffset; // Only applicable to isoc + TInt iResultsOffset; // Only applicable to isoc + TInt iNumElements; // Only applicable to isoc + }; + +private: + TInt CalculateDataLayout(TInt& aCurrentOffset, TInt& aNumStandardTransfers, TInt& aNumIsocTransfers, TInt& aNumIsocElements); + void CalculateMetaDataLayout(TInt& aCurrentOffset, TInt& aMetaDataStart, TInt aNumStandardTransfers, TInt aNumIsocTransfers, TInt aNumIsocElements); + void InitialiseMetaData(TInt aMetaDataOffset, TInt aNumStandardTransfers, TInt aNumIsocTransfers, TInt aNumIsocElements); + TInt UsedPackets(TInt aHeaderOffset); + TBool IsPowerOfTwo(TUint aNumber); + TInt IncNeededToAlign(TInt aOffset, TUint aAlignment); + static TBool CompareTransferDescriptor(const RUsbTransferDescriptor* aTransferDesc, const TUsbTransferDescriptorDetails& aDetails); + +private: //Calculate additional alignment related methods + TInt GetMaximumMaxPacketSize(TInt& aMaxMaxBulk, TInt& aMaxMaxInterrupt); + TInt CaculateAdditionalAlignment(TInt aCurrentOffset, TInt aMaxMaxBulk, TInt aMaxMaxInterrupt, TUsbTransferDescriptorDetails& aTransferDetails); +private: + RArray iRegisteredTransfers; + +private: + RUsbInterface* iInterfaceHandle; + RChunk iChunk; + TInt iBaseOffset; + TInt iPageSize; + }; + +#endif // ZEROCOPYTRANSFERSTRATEGY_H diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/include/d32otgdi_errors.h --- a/kernel/eka/include/d32otgdi_errors.h Wed Mar 31 23:38:45 2010 +0300 +++ b/kernel/eka/include/d32otgdi_errors.h Wed Apr 14 17:22:59 2010 +0300 @@ -41,6 +41,8 @@ const TInt KErrUsbOtgBadState = -6675; +const TInt KErrUsbOtgInOPTTestingMode = -6676; + const TInt KErrUsbOtgStackNotStarted = -6680; const TInt KErrUsbOtgVbusAlreadyRaised = -6681; const TInt KErrUsbOtgSrpForbidden = -6682; diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/include/drivers/locmedia.h --- a/kernel/eka/include/drivers/locmedia.h Wed Mar 31 23:38:45 2010 +0300 +++ b/kernel/eka/include/drivers/locmedia.h Wed Apr 14 17:22:59 2010 +0300 @@ -23,7 +23,7 @@ #if defined(_DEBUG) && defined(__DEMAND_PAGING__) #define __CONCURRENT_PAGING_INSTRUMENTATION__ #endif -#if defined(_DEBUG) && defined(__DEMAND_PAGING__) +#ifdef __DEMAND_PAGING__ #define __DEMAND_PAGING_BENCHMARKS__ #endif diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/include/e32ver.h --- a/kernel/eka/include/e32ver.h Wed Mar 31 23:38:45 2010 +0300 +++ b/kernel/eka/include/e32ver.h Wed Apr 14 17:22:59 2010 +0300 @@ -28,7 +28,7 @@ const TInt KE32MajorVersionNumber=2; const TInt KE32MinorVersionNumber=0; -const TInt KE32BuildVersionNumber=2102; +const TInt KE32BuildVersionNumber=2109; const TInt KMachineConfigurationMajorVersionNumber=1; const TInt KMachineConfigurationMinorVersionNumber=0; diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/kernel/ekern.mmp --- a/kernel/eka/kernel/ekern.mmp Wed Mar 31 23:38:45 2010 +0300 +++ b/kernel/eka/kernel/ekern.mmp Wed Apr 14 17:22:59 2010 +0300 @@ -50,6 +50,7 @@ // we have to keep this here, and not in kern_int.mmh, because media drivers // use the same macro name for different puposes... macro __DEMAND_PAGING__ +macro __DEMAND_PAGING_BENCHMARKS__ #endif diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/kernel/kern_int.mmh --- a/kernel/eka/kernel/kern_int.mmh Wed Mar 31 23:38:45 2010 +0300 +++ b/kernel/eka/kernel/kern_int.mmh Wed Apr 14 17:22:59 2010 +0300 @@ -61,10 +61,6 @@ macro __SUPPORT_DEMAND_PAGING_EMULATION__ #endif -#if defined(DEMAND_PAGING) && defined(DEMAND_PAGING_BENCHMARKS) -macro __DEMAND_PAGING_BENCHMARKS__ -#endif - #ifdef SYMBIAN_OLD_EXPORT_LOCATION systeminclude ../include/kernel #endif diff -r 2f92ad2dc5db -r 1df514389a47 kernel/eka/release.txt --- a/kernel/eka/release.txt Wed Mar 31 23:38:45 2010 +0300 +++ b/kernel/eka/release.txt Wed Apr 14 17:22:59 2010 +0300 @@ -1,3 +1,69 @@ +Version 2.00.2109 +================= +(Made by vfebvre 29/03/2010) + +1. mmoate + 1. DEF145151 \e32utils\nistsecurerng\* has incorrect distribution.policy.s60 ID + + +Version 2.00.2108 +================= +(Made by vfebvre 26/03/2010) + +1. seolney + 1. DEF144784 Fault possible if client deletes DMA request in callback + +2. jimmzhou + 1. ou1cimx1#320637[kernel92]Phone Crash when USB MobileTV device CU-14A is connected + +3. gcochran + 1. DEF145128 TRLM-83EGSL Paging HAL stats not visible in TB92 + + +Version 2.00.2107 +================= +(Made by vfebvre 24/03/2010) + +1. lanerobe + 1. DEF144929 KHS Documentation is not contributed to the Symbian Foundation + + +Version 2.00.2106 +================= +(Made by vfebvre 23/03/2010) + +1. lanerobe + 1. DEF144874 Intermittent E32TEST T_MSTIM test failures on the H4 (line 371) + + +Version 2.00.2105 +================= +(Made by vfebvre 22/03/2010) + +1. josezhou + 1. ou1cimx1#312934 : RUsbHubDriver interface can only be called by FDF, but multiple clients might have conflict requests to the interfaces + +2. ferporta + 1. PDEF145131 System Crash Monitor contains memory model dependent #defines + 2. DEF144875 E32TEST T_RMDEBUG2_OEM failing on UREL SMP configurations + + +Version 2.00.2104 +================= +(Made by vfebvre 19/03/2010) + +1. lanerobe + 1. DEF144712 Symbian Foundation build error due to missing usb components + + +Version 2.00.2103 +================= +(Made by vfebvre 18/03/2010) + +1. genwei + 1. ou1cimx1#301151: The device under test exits the high-speed host electrical test mode without operator action + + Version 2.00.2102 ================= (Made by vfebvre 17/03/2010) diff -r 2f92ad2dc5db -r 1df514389a47 kernelhwsrv_info/doc_pub/kernelhwsrv_doc_pub.mrp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kernelhwsrv_info/doc_pub/kernelhwsrv_doc_pub.mrp Wed Apr 14 17:22:59 2010 +0300 @@ -0,0 +1,11 @@ +# component name "Kernel and Hardware Services Documentation" + +component kernelhwsrv_doc_pub + +source \sf\os\kernelhwsrv\kernelhwsrv_info\doc_pub\ + +notes_source \component_defs\release.src + + +ipr E + diff -r 2f92ad2dc5db -r 1df514389a47 kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.cpp --- a/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.cpp Wed Mar 31 23:38:45 2010 +0300 +++ b/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -400,28 +400,49 @@ test(KErrNone == iServSession.AttachExecutable(iFileName, EFalse)); test(KErrNone == iServSession.SuspendThread(iThreadID)); - //test getting the global list, ETrue as should find the target debug thread - DoTestGetThreadList(ETrue, EScopeGlobal); - - //test getting this thread's thread list, ETrue as should find the target debug thread - DoTestGetThreadList(ETrue, EScopeThreadSpecific, RThread().Id().Id()); - - //test getting this process's thread list, ETrue as should find the target debug thread - DoTestGetThreadList(ETrue, EScopeProcessSpecific, RProcess().Id().Id()); + TBool found = EFalse; + + /* We need these loops because on some system the kernel run mode debugger does not + immediately present the thread in the thread list. + */ + + for(TInt retryCount = 0; retryCount < 10 && !found; retryCount++ ) + { + //test getting this process's thread list, ETrue as should find the target debug thread + User::After(50000); + found = DoTestGetThreadList(ETrue, EScopeProcessSpecific, RProcess().Id().Id()); + } + test( found ); + found = EFalse; + + for(TInt retryCount = 0; retryCount < 10 && !found; retryCount++ ) + { + //test getting the global list, ETrue as should find the target debug thread + User::After(50000); + found = DoTestGetThreadList(ETrue, EScopeGlobal); + } + test( found ); + + found = EFalse; + for(TInt retryCount = 0; retryCount < 10 && !found; retryCount++ ) + { + //test getting this thread's thread list, ETrue as should find the target debug thread + User::After(50000); + found = DoTestGetThreadList(ETrue, EScopeThreadSpecific, RThread().Id().Id()); + } + test( found ); test(KErrNone == iServSession.ResumeThread(iThreadID)); test(KErrNone == iServSession.DetachExecutable(iFileName)); } - -void CRunModeAgent::DoTestGetThreadList(const TBool aShouldPass, const TListScope aListScope, const TUint64 aTargetId) + +TBool CRunModeAgent::DoTestGetThreadList(const TBool aShouldPass, const TListScope aListScope, const TUint64 aTargetId) { - test.Next(_L("DoTestGetThreadList\n")); - //create data to pass RBuf8 buffer; TUint32 size = 0; - //perform the call to get the Code segs + //perform the call to get the thread list DoGetList(EThreads, aListScope, buffer, size, aTargetId); //initialise data about the target debug thread to compare the kernel's data against @@ -438,22 +459,22 @@ { TThreadListEntry* entry = (TThreadListEntry*)ptr; TPtr entryName(&(entry->iName[0]), entry->iNameLength, entry->iNameLength); + if( (threadId == entry->iThreadId) && (processId == entry->iProcessId) && (0 == name.CompareF(entryName)) ) { test(entry->iSupervisorStackBaseValid); test(entry->iSupervisorStackSizeValid); //if all match then we've found it found = ETrue; + break; } ptr += Align4(entry->GetSize()); } - //check whether the expected result happened - test(found == aShouldPass); - //clean up buffer.Close(); + return found; } @@ -582,6 +603,12 @@ } + +/** + * Get a list from the run mode debug system. Most list calls will initially return KErrTooBig, + * since the initial size of the buffer is 0. However it is sometimes valid for a list to be empty + * given its filtering and scope. These calls should return KErrNone. + */ void CRunModeAgent::DoGetList(const TListId aListId, const TListScope aListScope, RBuf8& aBuffer, TUint32& aSize, const TUint64 aTargetId) { //close the buffer in case there's stuff allocated in it @@ -589,19 +616,20 @@ //initialise it to be one byte big, which will guarantee data won't fit in it test(KErrNone == aBuffer.Create(1)); aSize = 0; - + + TInt ret = KErrNone; //should pass this test (assuming we've passed in sensible arguments above...) if(EScopeGlobal == aListScope) { - test(KErrTooBig == iServSession.GetList(aListId, aBuffer, aSize)); + ret = iServSession.GetList(aListId, aBuffer, aSize); } else if(EScopeThreadSpecific == aListScope) { - test(KErrTooBig == iServSession.GetList((TThreadId)aTargetId, aListId, aBuffer, aSize)); + ret = iServSession.GetList((TThreadId)aTargetId, aListId, aBuffer, aSize); } else if(EScopeProcessSpecific == aListScope) { - test(KErrTooBig == iServSession.GetList((TProcessId)aTargetId, aListId, aBuffer, aSize)); + ret = iServSession.GetList((TProcessId)aTargetId, aListId, aBuffer, aSize); } else { @@ -609,6 +637,17 @@ test(0); } + if( KErrNone == ret ) + { + /* In the case that there is no data, just return and let the caller check + the buffer. It is valid for a caller to not expect any data to be returned. + */ + return; + } + + // The only other allowed return is KErrTooBig + test( ret == KErrTooBig ); + //keep allocating larger buffers, beginning with the aSize returned by the above call, //and hopefully we'll eventually make a large enough one test(KErrNone == aBuffer.ReAlloc(aSize)); @@ -2727,9 +2766,9 @@ /* Wait a little while and try again, just in case the process is still being removed. This can happen on a very busy system or when a popup for the events is still active */ - RDebug::Printf("CRunModeAgent::TestEventsWithExtraThreads. ProcessExists(id=%d), waiting for it to exit %d", + RDebug::Printf("CRunModeAgent::TestEventsWithExtraThreads. ProcessExists(id=%d), waiting count exit=%d", I64LOW(processId), waitCount); - User::After(500); + User::After(50000); } test(!ProcessExists(processId)); } @@ -2738,34 +2777,37 @@ // helper function to check whether a thread with id aThreadId exists in the process with id aProcessId TBool CRunModeAgent::ThreadExistsForProcess(const TThreadId aThreadId, const TProcessId aProcessId) { - TUint32 size; - RBuf8 buffer; - test(KErrNone == buffer.Create(1024)); - TInt err = iServSession.GetList(aProcessId, EThreads, buffer, size); - while(KErrTooBig == err) + RThread lThread; + TInt ret = lThread.Open( aThreadId.Id() ); + + if( ret != KErrNone ) { - size*=2; - test(size<=16*1024); - test(KErrNone == buffer.ReAlloc(size)); - err = iServSession.GetList(aProcessId, EThreads, buffer, size); + RDebug::Printf("ThreadExistsForProcess: thread id=%d opening returned %d", + I64LOW( aThreadId.Id() ), ret ); + lThread.Close(); + return EFalse; } - test(KErrNone == err); - - //look through the buffer and check if the target debug thread is there - TUint8* ptr = (TUint8*)buffer.Ptr(); - const TUint8* ptrEnd = ptr + size; - while(ptr < ptrEnd) + + RProcess lProcess; + ret = lThread.Process( lProcess ); + + lThread.Close(); + + if( ret != KErrNone ) { - TThreadListEntry& entry = *(TThreadListEntry*)ptr; - if(aThreadId.Id() == entry.iThreadId) - { - buffer.Close(); - return ETrue; - } - ptr += Align4(entry.GetSize()); + RDebug::Printf("ThreadExistsForProcess: proc opening returned %d", ret ); + ret = KErrNotFound; } - buffer.Close(); - return EFalse; + else if( lProcess.Id() != aProcessId ) + { + RDebug::Printf("ThreadExistsForProcess: lProcess.Id()(%d)!= aProcessId(%d)", + I64LOW(lProcess.Id().Id()), I64LOW(aProcessId.Id())); + ret = KErrNotFound; + } + + lProcess.Close(); + + return ( ret == KErrNone ); } // helper function to check whether a process with id aProcessId exists diff -r 2f92ad2dc5db -r 1df514389a47 kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.h --- a/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.h Wed Mar 31 23:38:45 2010 +0300 +++ b/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.h Wed Apr 14 17:22:59 2010 +0300 @@ -71,7 +71,7 @@ void TestGetXipLibrariesList(); void TestGetListInvalidData(); - void DoTestGetThreadList(const TBool aShouldPass, const Debug::TListScope aListScope, const TUint64 aTargetId=0); + TBool DoTestGetThreadList(const TBool aShouldPass, const Debug::TListScope aListScope, const TUint64 aTargetId=0); void DoTestGetCodeSegsList(const TBool aShouldPass, const Debug::TListScope aListScope, const TUint64 aTargetId=0); void DoGetList(const Debug::TListId aListId, const Debug::TListScope aListScope, RBuf8& aBuffer, TUint32& aSize, const TUint64 aTargetId=0); diff -r 2f92ad2dc5db -r 1df514389a47 kerneltest/e32test/rm_debug/common/t_target_launcher.cpp --- a/kerneltest/e32test/rm_debug/common/t_target_launcher.cpp Wed Mar 31 23:38:45 2010 +0300 +++ b/kerneltest/e32test/rm_debug/common/t_target_launcher.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -192,6 +192,8 @@ } } + launchMutex.Wait( 500000 ); + CleanupStack::PopAndDestroy( &launchMutex ); if( commandLine ) @@ -202,6 +204,8 @@ GLDEF_C TInt E32Main() { + RProcess thisProcess; + thisProcess.Rendezvous(KErrNone); RDebug::Printf( ">Launcher Process()" ); CTrapCleanup* trap = CTrapCleanup::New(); diff -r 2f92ad2dc5db -r 1df514389a47 kerneltest/e32test/rm_debug/debug_targets/t_rmdebug_app.cpp --- a/kerneltest/e32test/rm_debug/debug_targets/t_rmdebug_app.cpp Wed Mar 31 23:38:45 2010 +0300 +++ b/kerneltest/e32test/rm_debug/debug_targets/t_rmdebug_app.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2007-2010 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" @@ -352,6 +352,8 @@ TInt E32Main() { + + RDebug::Printf("t_rmdebug_app tid=%d,pid=%d", I64LOW(RThread().Id().Id()), I64LOW(RProcess().Id().Id()) ) ; // setup heap checking and clean up trap __UHEAP_MARK; CTrapCleanup* cleanup=CTrapCleanup::New(); diff -r 2f92ad2dc5db -r 1df514389a47 kerneltest/e32test/rm_debug/multi_target_tests/t_multi_target.cpp --- a/kerneltest/e32test/rm_debug/multi_target_tests/t_multi_target.cpp Wed Mar 31 23:38:45 2010 +0300 +++ b/kerneltest/e32test/rm_debug/multi_target_tests/t_multi_target.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -110,14 +110,16 @@ // Performs each test in turn // { + test.Start(_L("ClientAppL")); TInt err = iServSession.Connect(securityServerVersion); if (err != KErrNone) { User::Panic(_L("Can't open server session"), err); } - + SetupDebugServerL(); LaunchTargetsInOrderL(); RDebug::Printf( "returning from CMultiTargetAgent::ClientAppL" ); + test.End(); } /** @@ -158,7 +160,7 @@ void CMultiTargetAgent::SetupDebugServerL() { RDebug::Printf( "CMultiTargetAgent::SetupDebugServerL" ); - + test.Next(_L("SetupDebugServerL\n")); iTargets.ReserveL( KNumApps ); RBuf targetName; @@ -235,8 +237,7 @@ TBool thisLaunchCompleted; - SetupDebugServerL(); - + test.Next(_L("LaunchTargetsInOrderL\n")); for( TInt numLaunches = KNumLaunches; numLaunches > 0; numLaunches-- ) { for( TInt numApps = KNumApps; numApps > 0; numApps-- ) @@ -362,17 +363,19 @@ } } - CleanupStack::PopAndDestroy( &launchSemaphore ); // launchSemaphore - - for( TInt i = iTargets.Count()-1; i>=0; i-- ) - { - RDebug::Printf( "Closing target %d", i ); - iTargets[ i ].Close(); - } + launchSemaphore.Signal(); + + CleanupStack::PopAndDestroy( &launchSemaphore ); // launchSemaphore + + for( TInt i = iTargets.Count()-1; i>=0; i-- ) + { + RDebug::Printf( "Closing target %d", i ); + iTargets[ i ].Close(); + } - iTargets.Close(); - - return KErrNone; + iTargets.Close(); + + return KErrNone; } diff -r 2f92ad2dc5db -r 1df514389a47 kerneltest/e32test/system/t_mstim.cpp --- a/kerneltest/e32test/system/t_mstim.cpp Wed Mar 31 23:38:45 2010 +0300 +++ b/kerneltest/e32test/system/t_mstim.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -84,7 +84,7 @@ TInt r=mstim.GetInfo(aId,info); CHECK(r); TEST(info.iCount==1); - return info.iMin/1000; + return (info.iMin+500)/1000; } GLDEF_C TInt E32Main() diff -r 2f92ad2dc5db -r 1df514389a47 package_definition.xml --- a/package_definition.xml Wed Mar 31 23:38:45 2010 +0300 +++ b/package_definition.xml Wed Apr 14 17:22:59 2010 +0300 @@ -61,6 +61,14 @@ + + + + + + + + @@ -133,6 +141,9 @@ + + + diff -r 2f92ad2dc5db -r 1df514389a47 userlibandfileserver/fileserver/group/release.txt --- a/userlibandfileserver/fileserver/group/release.txt Wed Mar 31 23:38:45 2010 +0300 +++ b/userlibandfileserver/fileserver/group/release.txt Wed Apr 14 17:22:59 2010 +0300 @@ -1,3 +1,19 @@ +Version 2.00.2050 +================= +(Made by vfebvre 24/03/2010) + +1. fagortz + 1. DEF145067: TTPA-83EAYU: Partition handling for USB drives with 4K block size is incorrect + + +Version 2.00.2049 +================= +(Made by vfebvre 22/03/2010) + +1. michcox + 1. DEF145080 SMAD-83NJMP: File server does not check return result of some User::ReAlloc()'s + + Version 2.00.2048 ================= (Made by vfebvre 15/03/2010) diff -r 2f92ad2dc5db -r 1df514389a47 userlibandfileserver/fileserver/inc/f32ver.h --- a/userlibandfileserver/fileserver/inc/f32ver.h Wed Mar 31 23:38:45 2010 +0300 +++ b/userlibandfileserver/fileserver/inc/f32ver.h Wed Apr 14 17:22:59 2010 +0300 @@ -58,6 +58,6 @@ @see TVersion */ -const TInt KF32BuildVersionNumber=2048; +const TInt KF32BuildVersionNumber=2050; // #endif diff -r 2f92ad2dc5db -r 1df514389a47 userlibandfileserver/fileserver/sfile/sf_cache.cpp --- a/userlibandfileserver/fileserver/sfile/sf_cache.cpp Wed Mar 31 23:38:45 2010 +0300 +++ b/userlibandfileserver/fileserver/sfile/sf_cache.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -610,8 +610,11 @@ if(r==KErrNoMemory) return r; + iCache = (TFileCacheRecord**)User::ReAlloc(pIndexes,sizeof(TFileCacheRecord*)*currentIndex); + if(!iCache) + return KErrNoMemory; + iNotPresent = EFalse; - iCache = (TFileCacheRecord**)User::ReAlloc(pIndexes,sizeof(TFileCacheRecord*)*currentIndex); iRecordCount = currentIndex; if (currentIndex>1) { diff -r 2f92ad2dc5db -r 1df514389a47 userlibandfileserver/fileserver/sfile/sf_obj.cpp --- a/userlibandfileserver/fileserver/sfile/sf_obj.cpp Wed Mar 31 23:38:45 2010 +0300 +++ b/userlibandfileserver/fileserver/sfile/sf_obj.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -129,7 +129,10 @@ if (newAlloc!=iAllocated) { if (newAlloc) + { iContainers=(CFsObjectCon**)User::ReAlloc(iContainers,newAlloc*sizeof(CFsObjectCon*)); + __ASSERT_DEBUG(iContainers,User::Panic(_L("FS_LDR panic"),ELdrHeapCorruptionOnRemove)); + } else { delete iContainers; @@ -489,7 +492,10 @@ if (newAlloc!=iAllocated) { if (newAlloc) + { iObjects=(SFsObjectIxRec*)User::ReAlloc(iObjects,newAlloc*sizeof(SFsObjectIxRec)); + __ASSERT_DEBUG(iObjects,User::Panic(_L("FS_LDR panic"),ELdrHeapCorruptionOnRemove)); + } else { delete iObjects; @@ -679,7 +685,10 @@ if (newAlloc!=iAllocated) { if (newAlloc) + { iObjects=(CFsObject**)User::ReAlloc(iObjects,newAlloc*sizeof(CFsObject*)); + __ASSERT_DEBUG(iObjects,User::Panic(_L("FS_LDR panic"),ELdrHeapCorruptionOnRemove)); + } else { delete iObjects; diff -r 2f92ad2dc5db -r 1df514389a47 userlibandfileserver/fileserver/sfile/sf_std.h --- a/userlibandfileserver/fileserver/sfile/sf_std.h Wed Mar 31 23:38:45 2010 +0300 +++ b/userlibandfileserver/fileserver/sfile/sf_std.h Wed Apr 14 17:22:59 2010 +0300 @@ -235,7 +235,8 @@ enum TFsPanic { - ELdrImportedOrdinalDoesNotExist + ELdrImportedOrdinalDoesNotExist, + ELdrHeapCorruptionOnRemove }; // enum TFsFault diff -r 2f92ad2dc5db -r 1df514389a47 userlibandfileserver/fileserver/shostmassstorage/msproxy/debug.h --- a/userlibandfileserver/fileserver/shostmassstorage/msproxy/debug.h Wed Mar 31 23:38:45 2010 +0300 +++ b/userlibandfileserver/fileserver/shostmassstorage/msproxy/debug.h Wed Apr 14 17:22:59 2010 +0300 @@ -1,4 +1,4 @@ -// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2008-2010 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" @@ -22,7 +22,7 @@ #ifndef PXY_DEBUG_H #define PXY_DEBUG_H -// #define _HOST_DEBUG_TRACE_ +//#define _HOST_DEBUG_PRINT_ // #define _PROXY_DEBUG_PRINT_ // #define _PROXY_FN_TRACE_ diff -r 2f92ad2dc5db -r 1df514389a47 userlibandfileserver/fileserver/shostmassstorage/msproxy/hostusbmsproxy.cpp --- a/userlibandfileserver/fileserver/shostmassstorage/msproxy/hostusbmsproxy.cpp Wed Mar 31 23:38:45 2010 +0300 +++ b/userlibandfileserver/fileserver/shostmassstorage/msproxy/hostusbmsproxy.cpp Wed Apr 14 17:22:59 2010 +0300 @@ -40,14 +40,19 @@ TInt CUsbHostMsProxyDrive::InitialiseOffset(TCapsInfo& aCapsInfo) { __MSFNSLOG - const TInt KPartitionInfoSize = TMsDataMemMap::KSectorSize; - TBuf8 partitionInfo; - TInt r; + RBuf8 partitionInfo; + TInt r; + TRAP(r, partitionInfo.CreateL(aCapsInfo.iBlockLength)); + if (r != KErrNone) + { + return r; + } - r = iUsbHostMsLun.Read(0 , KPartitionInfoSize, (TDes8 &) partitionInfo); + r = iUsbHostMsLun.Read(0, aCapsInfo.iBlockLength, partitionInfo); if (r != KErrNone) { __PXYPRINT1(_L("!! Reading medium failed with %d !!"), r); + partitionInfo.Close(); return r; } TUint8 *iIntBuf = (TUint8 *) partitionInfo.Ptr(); @@ -104,21 +109,27 @@ TMBRPartitionEntry& partitionEntry = pe[partitionIndex]; iMsDataMemMap.InitDataArea(partitionEntry.iFirstSector, - partitionEntry.iNumSectors); + partitionEntry.iNumSectors, + aCapsInfo.iBlockLength); __PXYPRINT2(_L("paritioncount = %d defaultpartition = %d"), partitionCount, partitionIndex); - __PXYPRINT2(_L("iFirstSector = x%x iNumSectors = x%x"), + __PXYPRINT3(_L("iFirstSector = x%x iNumSectors = x%x iSectorSize = x%x"), partitionEntry.iFirstSector, - partitionEntry.iNumSectors); + partitionEntry.iNumSectors, + aCapsInfo.iBlockLength); } else { __PXYPRINT(_L("No partition found")); - iMsDataMemMap.InitDataArea(0, aCapsInfo.iNumberOfBlocks); - __PXYPRINT2(_L("iFirstSector = x%x iNumSectors = x%x"), - 0, aCapsInfo.iNumberOfBlocks); + iMsDataMemMap.InitDataArea(0, aCapsInfo.iNumberOfBlocks, aCapsInfo.iBlockLength); + __PXYPRINT3(_L("iFirstSector = x%x iNumSectors = x%x iSectorSize = x%x"), + 0, + aCapsInfo.iNumberOfBlocks, + aCapsInfo.iBlockLength); } } + + partitionInfo.Close(); return KErrNone; } @@ -558,6 +569,12 @@ { c.iMediaAtt |= KMediaAttWriteProtected; } + + static const TInt K512ByteSectorSize = 0x200; // 512 + if(K512ByteSectorSize != capsInfo.iBlockLength) + { + c.iMediaAtt &= ~KMediaAttFormattable; + } __HOSTPRINT4(_L("<<< HOST Caps Block[num=0x%x size=0x%x] Media[size=0x%lx WP=0x%x]"), capsInfo.iNumberOfBlocks, capsInfo.iBlockLength, caps().iSize, caps().iMediaAtt); @@ -571,6 +588,7 @@ else { __HOSTPRINT(_L("<<< HOST Caps Unknown Error")); + c.iType = EMediaUnknown; r = KErrUnknown; } anInfo = caps.Left(Min(caps.Length(),anInfo.MaxLength())); @@ -629,7 +647,7 @@ { __MSFNSLOG - const TInt KDefaultMaxBytesPerFormat = 0x100 * TMsDataMemMap::KSectorSize; // 128K + const TInt KDefaultMaxBytesPerFormat = 0x100 * iMsDataMemMap.BlockLength(); // 128K if (aInfo.i512ByteSectorsFormatted < 0) return KErrArgument; @@ -648,14 +666,14 @@ iMsDataMemMap.InitDataArea(caps().iSize); } - TInt64 pos = static_cast(aInfo.i512ByteSectorsFormatted) << TMsDataMemMap::KFormatSectorShift; + TInt64 pos = static_cast(aInfo.i512ByteSectorsFormatted) << iMsDataMemMap.FormatSectorShift(); TInt length = aInfo.iMaxBytesPerFormat; TInt r = Erase(pos, length); if (r == KErrNone) { - length += TMsDataMemMap::KSectorSize - 1; - length >>= TMsDataMemMap::KFormatSectorShift; + length += iMsDataMemMap.BlockLength() - 1; + length >>= iMsDataMemMap.FormatSectorShift(); aInfo.i512ByteSectorsFormatted += length; } diff -r 2f92ad2dc5db -r 1df514389a47 userlibandfileserver/fileserver/shostmassstorage/msproxy/tmsmemmap.h --- a/userlibandfileserver/fileserver/shostmassstorage/msproxy/tmsmemmap.h Wed Mar 31 23:38:45 2010 +0300 +++ b/userlibandfileserver/fileserver/shostmassstorage/msproxy/tmsmemmap.h Wed Apr 14 17:22:59 2010 +0300 @@ -1,4 +1,4 @@ -// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2008-2010 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" @@ -26,21 +26,20 @@ class TMsDataMemMap { public: - static const TInt KSectorSize = 0x200; // 512 - static const TInt KFormatSectorShift = 9; TMsDataMemMap(); void Reset(); - void InitDataArea(TUint32 aFirstDataSector, TUint32 aNumSectors); + void InitDataArea(TUint32 aFirstDataSector, TUint32 aNumSectors, TUint32 aSectorSize); void InitDataArea(TUint64 aSize); - TInt BlockLength() const; + TUint32 BlockLength() const; TUint64 DataSize() const; TInt64 GetDataPos(TInt64 aPos) const; TInt TranslateDataPos(TInt64& aPos, TInt& aLength) const; TInt CheckBlockInRange(TInt64& aPos, TInt aLength) const; + TInt FormatSectorShift() const; private: // Whole media @@ -50,6 +49,12 @@ // Data Area // Offset TInt64 iDataOffset; + + // Sector Size (Media Block Size) + TUint32 iSectorSize; + + // Sector-size dependant + TInt iFormatSectorShift; }; #include "tmsmemmap.inl" diff -r 2f92ad2dc5db -r 1df514389a47 userlibandfileserver/fileserver/shostmassstorage/msproxy/tmsmemmap.inl --- a/userlibandfileserver/fileserver/shostmassstorage/msproxy/tmsmemmap.inl Wed Mar 31 23:38:45 2010 +0300 +++ b/userlibandfileserver/fileserver/shostmassstorage/msproxy/tmsmemmap.inl Wed Apr 14 17:22:59 2010 +0300 @@ -1,4 +1,4 @@ -// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +// Copyright (c) 2008-2010 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" @@ -26,9 +26,9 @@ } -inline TInt TMsDataMemMap::BlockLength() const +inline TUint32 TMsDataMemMap::BlockLength() const { - return KSectorSize; + return iSectorSize; } @@ -37,11 +37,20 @@ return iSize - iDataOffset; } -inline void TMsDataMemMap::InitDataArea(TUint32 aFirstDataSector, TUint32 aNumSectors) - { - iDataOffset = static_cast(aFirstDataSector) * KSectorSize; - iSize = static_cast(aNumSectors) * KSectorSize; - } +inline void TMsDataMemMap::InitDataArea(TUint32 aFirstDataSector, TUint32 aNumSectors, TUint32 aSectorSize) + { + iSectorSize = aSectorSize; + + iFormatSectorShift = 0; + while(aSectorSize) + { + ++iFormatSectorShift; + aSectorSize >>= 1; + } + + iDataOffset = static_cast(aFirstDataSector) * iSectorSize; + iSize = static_cast(aNumSectors) * iSectorSize; + } inline void TMsDataMemMap::InitDataArea(TUint64 aSize) @@ -55,3 +64,8 @@ return aPos + iDataOffset; } +inline TInt TMsDataMemMap::FormatSectorShift() const + { + return iFormatSectorShift; + } +