Merge
authorShabe Razvi <shaber@symbian.org>
Tue, 04 May 2010 18:23:12 +0100
changeset 105 ea2434cf3670
parent 104 466a0df5c15a (current diff)
parent 103 8811011454cf (diff)
child 111 aba5f24f35c1
Merge
--- a/kernel/eka/bld.inf	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/bld.inf	Tue May 04 18:23:12 2010 +0100
@@ -386,20 +386,20 @@
 include/e32utrace.mmh							SYMBIAN_OS_LAYER_PUBLIC_EXPORT_PATH(e32utrace.mmh)
 
 //Open System Trace API
-include/opensystemtrace.h					/epoc32/include/platform/
-include/opensystemtrace.inl					/epoc32/include/platform/
-include/opensystemtrace_types.h					/epoc32/include/platform/
-include/opensystemtrace.mmh					/epoc32/include/platform/
+include/opensystemtrace.h                       SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(opensystemtrace.h)
+include/opensystemtrace.inl                     SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(opensystemtrace.inl)
+include/opensystemtrace_types.h                 SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(opensystemtrace_types.h)
+include/opensystemtrace.mmh                     SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(opensystemtrace.mmh)
 
 // ROM building scripts
-rombuild/base.iby								/epoc32/rom/include/			//
-rombuild/PlatSecEnforcement.oby					/epoc32/rom/include/			//
-rombuild/PlatSecDiagnostics.oby					/epoc32/rom/include/			//
-rombuild/btrace.iby								/epoc32/rom/include/			//
+rombuild/base.iby								/epoc32/rom/include/
+rombuild/PlatSecEnforcement.oby					/epoc32/rom/include/
+rombuild/PlatSecDiagnostics.oby					/epoc32/rom/include/
+rombuild/btrace.iby								/epoc32/rom/include/
 rombuild/kernel.hby								/epoc32/rom/include/
 rombuild/rm_debug_svr.iby						/epoc32/rom/include/			// Run mode debug driver
-rombuild/utrace.iby								/epoc32/rom/include/			//utrace
-rombuild/ost.iby								/epoc32/rom/include/			//ost
+rombuild/utrace.iby								/epoc32/rom/include/
+rombuild/ost.iby								/epoc32/rom/include/
 
 // Byte pair compressor
 include/byte_pair_compress.h					SYMBIAN_OS_LAYER_PLATFORM_EXPORT_PATH(byte_pair_compress.h)
--- a/kernel/eka/bmarm/ekernsmp.def	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/bmarm/ekernsmp.def	Tue May 04 18:23:12 2010 +0100
@@ -1053,4 +1053,5 @@
 	Stats__13KernCoreStatsPv @ 1052 NONAME R3UNUSED ; KernCoreStats::Stats(void *)
 	SetNumberOfActiveCpus__5NKerni @ 1053 NONAME
 	SetIdleHandler__3ArmPFPvUlPVv_vPv @ 1054 NONAME R3UNUSED ; Arm::SetIdleHandler(void (*)(void *, unsigned long, void volatile *), void *)
+	FreeRamZone__4EpocUi @ 1055 NONAME R3UNUSED ; Epoc::FreeRamZone(unsigned int)
 
--- a/kernel/eka/bmarm/ekernu.def	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/bmarm/ekernu.def	Tue May 04 18:23:12 2010 +0100
@@ -1050,3 +1050,4 @@
 	Retire__13KernCoreStatsii @ 1049 NONAME R3UNUSED ; KernCoreStats::Retire(int, int)
 	Stats__13KernCoreStatsPv @ 1050 NONAME R3UNUSED ; KernCoreStats::Stats(void *)
 	SetIdleHandler__3ArmPFPvUl_vPv @ 1051 NONAME R3UNUSED ; Arm::SetIdleHandler(void (*)(void *, unsigned long), void *)
+	FreeRamZone__4EpocUi @ 1052 NONAME R3UNUSED ; Epoc::FreeRamZone(unsigned int)
--- a/kernel/eka/bx86/ekernsmp.def	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/bx86/ekernsmp.def	Tue May 04 18:23:12 2010 +0100
@@ -1010,4 +1010,5 @@
 	?Retire@KernCoreStats@@SAHHH@Z @ 1009 NONAME	;  public: static int KernCoreStats::Retire(int, int)
 	?Stats@KernCoreStats@@SAHPAX@Z @ 1010 NONAME	;  public: static int KernCoreStats::Stats(void *)
 	?SetNumberOfActiveCpus@NKern@@SAXH@Z @ 1011 NONAME ; public: static void __cdecl NKern::SetNumberOfActiveCpus(int)
+	?FreeRamZone@Epoc@@SAHI@Z @ 1012 NONAME ; public: static int Epoc::FreeRamZone(unsigned int)
 
--- a/kernel/eka/bx86/ekernu.def	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/bx86/ekernu.def	Tue May 04 18:23:12 2010 +0100
@@ -955,4 +955,5 @@
 	?LeaveIdle@KernCoreStats@@SAXI@Z @ 954 NONAME	;  public: static void KernCoreStats::LeaveIdle(unsigned int)
 	?Retire@KernCoreStats@@SAHHH@Z @ 955 NONAME	;  public: static int KernCoreStats::Retire(int, int)
 	?Stats@KernCoreStats@@SAHPAX@Z @ 956 NONAME	;  public: static int KernCoreStats::Stats(void *)
+	?FreeRamZone@Epoc@@SAHI@Z @ 957 NONAME ; public: static int Epoc::FreeRamZone(unsigned int)
 
--- a/kernel/eka/bx86gcc/ekernsmp.def	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/bx86gcc/ekernsmp.def	Tue May 04 18:23:12 2010 +0100
@@ -1098,4 +1098,5 @@
 	_ZN13KernCoreStats6RetireEii @ 1097 NONAME
 	_ZN13KernCoreStats9ConfigureEj @ 1098 NONAME
 	_ZN5NKern21SetNumberOfActiveCpusEi @ 1099 NONAME
+	_ZN4Epoc11FreeRamZoneEj @ 1100 NONAME
 
--- a/kernel/eka/bx86gcc/ekernu.def	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/bx86gcc/ekernu.def	Tue May 04 18:23:12 2010 +0100
@@ -1038,4 +1038,5 @@
 	_ZN13KernCoreStats9ConfigureEj @ 1037 NONAME
 	_ZN13KernCoreStats9EnterIdleEv @ 1038 NONAME
 	_ZN13KernCoreStats9LeaveIdleEj @ 1039 NONAME
+	_ZN4Epoc11FreeRamZoneEj @ 1040 NONAME
 
--- a/kernel/eka/debug/crashMonitor/inc/scmdatasave.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/debug/crashMonitor/inc/scmdatasave.h	Tue May 04 18:23:12 2010 +0100
@@ -43,6 +43,7 @@
 
 
 _LIT8(KKernelHeapChunkName, "ekern.exe::SvHeap");
+_LIT8(KKernelProcessName, "ekern.exe");
 
 
 /**
--- a/kernel/eka/debug/crashMonitor/src/scmdatasave.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/debug/crashMonitor/src/scmdatasave.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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<KMaxKernelName> 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;
 			}
 		}
--- a/kernel/eka/debug/securityServer/group/rm_debug_svr.mmp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/debug/securityServer/group/rm_debug_svr.mmp	Tue May 04 18:23:12 2010 +0100
@@ -46,3 +46,5 @@
 
 //TCB is added for the RLocalDrive methods.
 CAPABILITY AllFiles TCB
+
+SMPSAFE
--- a/kernel/eka/drivers/debug/group/rm_debug_kerneldriver.mmh	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/drivers/debug/group/rm_debug_kerneldriver.mmh	Tue May 04 18:23:12 2010 +0100
@@ -51,3 +51,5 @@
 EPOCALLOWDLLDATA
 
 capability			all
+
+SMPSAFE
--- a/kernel/eka/drivers/pbus/mmc/sdcard/sdcard3c/sdcard.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/drivers/pbus/mmc/sdcard/sdcard3c/sdcard.cpp	Tue May 04 18:23:12 2010 +0100
@@ -481,6 +481,12 @@
 		// Before issueing commands, see if there's actually a card present
 		if (!CardDetect(iCxCardCount))
 			SMF_GOTOS(EStMoreCardsCheck)
+		
+		// Card Previously Marked as Corrupt do not re-initialise	
+		if ((CardArray().CardP(iCxCardCount)->iFlags)& KSDCardIsCorrupt)
+		    {
+            SMF_GOTOS(EStMoreCardsCheck)
+		    }
 
 		m.SetTraps(KMMCErrResponseTimeOut);
 		SMF_INVOKES(InitialiseMemoryCardSMST, EStSendCIDIssued)
@@ -814,6 +820,7 @@
 					{
 					__KTRACE_OPT2(KPBUS1, KPANIC, Kern::Printf("-sd:ocr busy timed out"));
 					OstTraceFunctionExitExt( DSDSTACK_INITIALISEMEMORYCARDSM_EXIT2, this, (TInt) KMMCErrBusTimeOut );
+					(CardArray().CardP(iCxCardCount)->iFlags)|=KSDCardIsCorrupt;
 					return KMMCErrBusTimeOut;
 					}
 					
--- a/kernel/eka/drivers/power/smppower/idlehelper.cia	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/drivers/power/smppower/idlehelper.cia	Tue May 04 18:23:12 2010 +0100
@@ -1,23 +1,19 @@
-/*
-* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
-* This component and the accompanying materials are made available
-* under the terms of "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:  
-* os\kernelhwsrv\kernel\eka\drivers\power\smpidlehelper.cpp
-* Impelentation of helper classes required to implement CPU idle
-* functionality in a SMP BSP.
-*
-*/
-
+// 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"
+// 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:
+// os\kernelhwsrv\kernel\eka\drivers\power\smpidlehelper.cpp
+// Impelentation of helper classes required to implement CPU idle
+// functionality in a SMP BSP.
 
 /**
  @file
--- a/kernel/eka/drivers/power/smppower/idlehelper.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/drivers/power/smppower/idlehelper.cpp	Tue May 04 18:23:12 2010 +0100
@@ -1,23 +1,19 @@
-/*
-* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
-* This component and the accompanying materials are made available
-* under the terms of "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:  
-* os\kernelhwsrv\kernel\eka\drivers\power\smppower\idlehelper.cpp
-* Impelentation of helper classes required to implement CPU idle
-* functionality in a SMP BSP.
-*
-*/
-
+// 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"
+// 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:
+// os\kernelhwsrv\kernel\eka\drivers\power\smppower\idlehelper.cpp
+// Impelentation of helper classes required to implement CPU idle
+// functionality in a SMP BSP.
 
 /**
  @file
--- a/kernel/eka/drivers/power/smppower/idlehelper_lib.mmp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/drivers/power/smppower/idlehelper_lib.mmp	Tue May 04 18:23:12 2010 +0100
@@ -1,9 +1,9 @@
-// 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 "Eclipse Public License v1.0"
+// 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".
+// at the URL " http://www.eclipse.org/legal/epl-v10.html ".
 //
 // Initial Contributors:
 // Nokia Corporation - initial contribution.
@@ -14,7 +14,6 @@
 // e32\drivers\power\smppower\smpidlehelper_lib.mmp
 // Helper library required to implement CPU idle
 // functionality in a SMP BSP.
-//
 
 
 #define NO_EKERN_LIB
--- a/kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler.cpp	Tue May 04 18:23:12 2010 +0100
@@ -1,23 +1,19 @@
-/*
-* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
-* This component and the accompanying materials are made available
-* under the terms of "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:  
-* os\kernelhwsrv\kernel\eka\drivers\power\smppower\sample_idlehandler\smpidlehandler.cpp
-* implements a basic smp idle handler generic layer that can be derived from 
-* to create platform specific SMP idle handlers
-*
-*/
-
+// 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"
+// 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:
+// os\kernelhwsrv\kernel\eka\drivers\power\smppower\sample_idlehandler\smpidlehandler.cpp
+// implements a basic smp idle handler generic layer that can be derived from 
+// to create platform specific SMP idle handlers
 
 /**
  @file
--- a/kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler_lib.mmp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/drivers/power/smppower/sample_idlehandler/smpidlehandler_lib.mmp	Tue May 04 18:23:12 2010 +0100
@@ -1,9 +1,9 @@
 // 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 "Eclipse Public License v1.0"
+// 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".
+// at the URL " http://www.eclipse.org/legal/epl-v10.html ".
 //
 // Initial Contributors:
 // Nokia Corporation - initial contribution.
@@ -14,7 +14,6 @@
 // eka\drivers\power\smppower\sample_idlehandler\smpidlehandler_lib.mmp
 // Helper library required to implement CPU idle
 // functionality in a SMP BSP.
-//
 
 
 #define NO_EKERN_LIB
--- a/kernel/eka/drivers/usbc/usbdma.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/drivers/usbc/usbdma.cpp	Tue May 04 18:23:12 2010 +0100
@@ -619,7 +619,14 @@
 			{
 			if (iEndpointType == KUsbEpTypeBulk)
 				{
-				isShortPacket = (size < iMaxPacketSize) || (size & maxPacketSizeMask);
+                if(iExtractOffset & maxPacketSizeMask)
+                	{
+                    isShortPacket = ((size+iExtractOffset) < iMaxPacketSize) || ((size+iExtractOffset) & maxPacketSizeMask);
+                	}
+                else
+                	{
+                    isShortPacket = (size < iMaxPacketSize) || (size & maxPacketSizeMask);
+                	}
 				}
 			else
 				{
@@ -830,17 +837,7 @@
 		if (iEndpointType == KUsbEpTypeBulk)
 			{
 			const TInt mask = iMaxPacketSize - 1;
-			if (iTotalRxBytesAvail & mask)
-				return ETrue;
 
-			// residue==0; this can be because
-			// zlps exist, or short packets combine to n * max_packet_size
-			// This means spadework
-			const TInt s = iCurrentPacketSizeArray[iCurrentPacket] - iExtractOffset;
-			if ((s == 0) || (s & mask))
-				{
-				return ETrue;
-				}
 
 			for (TInt i = 0; i < iNumberofBuffers; i++)
 				{
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/base_drivers_usbdescriptors.mrp	Tue May 04 18:23:12 2010 +0100
@@ -0,0 +1,27 @@
+#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "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: 
+#
+# 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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/bld.inf	Tue May 04 18:23:12 2010 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescparser.cpp	Tue May 04 18:23:12 2010 +0100
@@ -0,0 +1,379 @@
+// 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 <d32usbdescriptors.h>
+#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)
+		{
+		if(!aDesc)
+			{
+			ret = KErrNotFound;
+			}
+		else
+			{
+			// 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;
+		}
+
+	// release the allocated descriptor if there was an error
+	if(ret != KErrNone && aDesc)
+		{
+		delete aDesc;
+		aDesc = NULL;
+		}
+
+	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<CUsbCustomDescriptorParserList*>(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<CUsbCustomDescriptorParserList*>(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<const CUsbCustomDescriptorParserList*>(Dll::Tls());
+	if(parserList)
+		{
+		TInt numOfParsers = parserList->NumOfRegisteredParsers()-1;
+		for(TInt index=0; index<numOfParsers; ++index)
+			{
+			TUsbDescriptorParserL parserL = parserList->RegisteredParser(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;
+	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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 <d32usbdescriptors.h>
+#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<TUsbGenericDescriptor*>(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<TUsbDeviceDescriptor*>(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<TUsbDeviceQualifierDescriptor*>(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<TUsbConfigurationDescriptor*>(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<TUsbOtherSpeedDescriptor*>(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<TUsbInterfaceAssociationDescriptor*>(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<TUsbInterfaceDescriptor*>(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<TUsbEndpointDescriptor*>(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<TUsbOTGDescriptor*>(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<TUsbStringDescriptor*>(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;
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescriptors.mmp	Tue May 04 18:23:12 2010 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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];
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdescriptors/usbdescutils.h	Tue May 04 18:23:12 2010 +0100
@@ -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 <d32usbdescriptors.h>
+#include <d32usbdi_errors.h>
+
+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<UsbDescriptorParser::TUsbDescriptorParserL> iParserList;
+	};
+
+
+#endif // USBDESCUTILS_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/base_drivers_usbdi_utils.mrp	Tue May 04 18:23:12 2010 +0100
@@ -0,0 +1,27 @@
+#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "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: 
+#
+# 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
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/bld.inf	Tue May 04 18:23:12 2010 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbdi_utils.mmp	Tue May 04 18:23:12 2010 +0100
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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);
+	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbdiutils.h	Tue May 04 18:23:12 2010 +0100
@@ -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 <d32usbdi_errors.h>
+
+
+NONSHARABLE_CLASS(UsbdiUtils)
+	{
+public:
+	static void Panic(UsbdiPanics::TUsbdiPanics aPanic);
+	static void Fault(UsbdiFaults::TUsbdiFaults aFault);
+	};
+
+#endif // USBDIUTILS_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbinterface.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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 <d32usbdi.h>
+
+#include <d32usbtransfers.h>
+#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<TUint32> 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);
+	}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbpipe.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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 <d32usbdi.h>
+#include <d32usbtransfers.h>
+
+#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);
+	}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbtransfers.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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 <d32usbtransfers.h>
+
+#include <d32usbdi_errors.h>
+#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.
+*/
+EXPORT_C 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);
+	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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 <d32usbtransfers.h>
+#include <d32usbdi_errors.h>
+#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<RUsbTransferStrategy*>(this);
+	if(aTransfer.iType == RUsbTransferDescriptor::EIsochronous)
+		{
+		static_cast<RUsbIsocTransferDescriptor&>(aTransfer).iWriteHandle = aHandle;
+		}
+	}
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/usbtransferstrategy.h	Tue May 04 18:23:12 2010 +0100
@@ -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 <e32std.h>
+#include <d32usbtransfers.h>
+
+
+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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.h	Tue May 04 18:23:12 2010 +0100
@@ -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 <e32def.h>
+
+// 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopymetadata.inl	Tue May 04 18:23:12 2010 +0100
@@ -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<typename XReturnType, TInt XFieldOffset>
+inline XReturnType& Field(TAddrType aBase, TInt aHeaderOffset)
+	{
+	TInt offset = aHeaderOffset + XFieldOffset;
+	return *reinterpret_cast<XReturnType*>(aBase + offset);
+	}
+
+
+//
+// UsbZeroCopyChunkHeaderBase
+//
+
+inline RUsbTransferDescriptor::TTransferType& UsbZeroCopyChunkHeaderBase::TransferType(TAddrType aBase, TInt aHeaderOffset)
+	{
+	return Field<RUsbTransferDescriptor::TTransferType, ETransferType>(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<TInt, EDataOffset>(aBase, aHeaderOffset);
+	}
+
+inline TInt& UsbZeroCopyBulkIntrChunkHeader::DataLength(TAddrType aBase, TInt aHeaderOffset)
+	{
+	return Field<TInt, EDataLength>(aBase, aHeaderOffset);
+	}
+
+inline TInt& UsbZeroCopyBulkIntrChunkHeader::DataMaxLength(TAddrType aBase, TInt aHeaderOffset)
+	{
+	return Field<TInt, EDataMaxLength>(aBase, aHeaderOffset);
+	}
+	
+inline RUsbTransferDescriptor::TZlpStatus& UsbZeroCopyBulkIntrChunkHeader::ZlpStatus(TAddrType aBase, TInt aHeaderOffset)
+	{
+	return Field<RUsbTransferDescriptor::TZlpStatus, EZlpStatus>(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<TInt, EFirstElementOffset>(aBase, aHeaderOffset);
+	}
+
+inline TInt& UsbZeroCopyIsocChunkHeader::MaxNumPackets(TAddrType aBase, TInt aHeaderOffset)
+	{
+	return Field<TInt, EMaxNumPackets>(aBase, aHeaderOffset);
+	}
+
+inline TInt& UsbZeroCopyIsocChunkHeader::MaxPacketSize(TAddrType aBase, TInt aHeaderOffset)
+	{
+	return Field<TInt, EMaxPacketSize>(aBase, aHeaderOffset);
+	}
+
+inline TInt& UsbZeroCopyIsocChunkHeader::LengthsOffset(TAddrType aBase, TInt aHeaderOffset)
+	{
+	return Field<TInt, ELengthsOffset>(aBase, aHeaderOffset);
+	}
+	
+inline TInt& UsbZeroCopyIsocChunkHeader::ReqLenOffset(TAddrType aBase, TInt aHeaderOffset)
+	{
+	return Field<TInt, EReqLenOffset>(aBase, aHeaderOffset);
+	}
+	
+inline TInt& UsbZeroCopyIsocChunkHeader::ResultsOffset(TAddrType aBase, TInt aHeaderOffset)
+	{
+	return Field<TInt, EResultsOffset>(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<TInt, EDataOffset>(aBase, aHeaderOffset);
+	}
+
+inline TInt& UsbZeroCopyIsocChunkElement::NumPackets(TAddrType aBase, TInt aHeaderOffset)
+	{
+	return Field<TInt, ENumPackets>(aBase, aHeaderOffset);
+	}
+
+inline TInt& UsbZeroCopyIsocChunkElement::NextElementOffset(TAddrType aBase, TInt aHeaderOffset)
+	{
+	return Field<TInt, ENextElementOffset>(aBase, aHeaderOffset);
+	}
+	
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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 <d32usbtransfers.h>
+#include <d32usbdi.h>
+#include <d32usbdi_errors.h>
+#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<TUint16*>(chunkBase + lengthsOffset);
+	
+	TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle);
+	TUint16* reqLenPtr = reinterpret_cast<TUint16*>(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<TInt*>(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<TUint32>(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<TUint16*>(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<TUint16*>(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<TUint16*>(chunkBase + lengthsOffset + previousPacketCount * sizeof(TUint16));
+			TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle);
+			TUint16* reqLenPtr = reinterpret_cast<TUint16*>(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<TUint32>(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<TUint16*>(chunkBase + lengthsOffset);
+	TInt reqLenOffset = UsbZeroCopyIsocChunkHeader::ReqLenOffset(chunkBase, aHandle);
+	TUint16* reqLenPtr = reinterpret_cast<TUint16*>(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<TUint32>(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;
+	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernel/eka/drivers/usbho/usbdi_utils/zerocopytransferstrategy.h	Tue May 04 18:23:12 2010 +0100
@@ -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<TUsbTransferDescriptorDetails> iRegisteredTransfers;
+
+private:
+	RUsbInterface* iInterfaceHandle;
+	RChunk iChunk;
+	TInt iBaseOffset;
+	TInt iPageSize;
+	};
+
+#endif // ZEROCOPYTRANSFERSTRATEGY_H
--- a/kernel/eka/eabi/ekernsmp.def	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/eabi/ekernsmp.def	Tue May 04 18:23:12 2010 +0100
@@ -1187,4 +1187,5 @@
 	_ZN13KernCoreStats9ConfigureEj @ 1186 NONAME
 	_ZN5NKern21SetNumberOfActiveCpusEi @ 1187 NONAME
 	_ZN3Arm14SetIdleHandlerEPFvPvmPVvES0_ @ 1188 NONAME
+	_ZN4Epoc11FreeRamZoneEj @ 1189 NONAME
 
--- a/kernel/eka/eabi/ekernu.def	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/eabi/ekernu.def	Tue May 04 18:23:12 2010 +0100
@@ -1179,4 +1179,5 @@
 	_ZN13KernCoreStats9EnterIdleEv @ 1178 NONAME
 	_ZN13KernCoreStats9LeaveIdleEj @ 1179 NONAME
 	_ZN3Arm14SetIdleHandlerEPFvPvmES0_ @ 1180 NONAME
+	_ZN4Epoc11FreeRamZoneEj @ 1181 NONAME
 
--- a/kernel/eka/eabi/usbdi_utilsu.def	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/eabi/usbdi_utilsu.def	Tue May 04 18:23:12 2010 +0100
@@ -37,4 +37,5 @@
 	_ZN26RUsbIsocTransferDescriptor7ResultsEv @ 36 NONAME
 	_ZNK14TPacketResults2AtEi @ 37 NONAME
 	_ZNK14TPacketResultsixEi @ 38 NONAME
+	_ZN22RUsbTransferDescriptor5CloseEv @ 39 NONAME
 
--- a/kernel/eka/euser/us_ksvr.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/euser/us_ksvr.cpp	Tue May 04 18:23:12 2010 +0100
@@ -3469,16 +3469,17 @@
 be invoked on this TThreadCreateInfo to set the type of the thread to be created
 before being passed as a paramter to RThread::Create().
 
-@param aName        The name to be assigned to the thread.
+@param aName		The name to be assigned to the thread.
 					KNullDesC, to create an anonymous thread.
-@param aFunction    A pointer to a function. Control passes to this function
-                    when the thread is first resumed, i.e. when the thread
-                    is initially scheduled to run.
-@param aStackSize   The size of the new thread's stack.
-@param aPtr         A pointer to data to be passed as a parameter to
-                    the thread function when the thread is initially scheduled
-                    to run. If the thread function does not need any data then
-                    this pointer can be NULL.
+@param aFunction	A pointer to a function. Control passes to this function
+					when the thread is first resumed, i.e. when the thread
+					is initially scheduled to run.
+@param aStackSize	The size of the new thread's stack.  This must be at least
+					512 bytes, otherwise RThread::Create() will fail with KErrArgument.
+@param aPtr			A pointer to data to be passed as a parameter to
+					the thread function when the thread is initially scheduled
+					to run. If the thread function does not need any data then
+					this pointer can be NULL.
 */
 EXPORT_C TThreadCreateInfo::TThreadCreateInfo(const TDesC &aName, TThreadFunction aFunction, 
 											TInt aStackSize, TAny* aPtr) :
@@ -3604,25 +3605,27 @@
 If KNullDesC is specified for the name, then an anonymous thread will be created.
 Anonymous threads are not global, and cannot be opened by other processes.
 
-@param aName        The name to be assigned to this thread.
+@param aName		The name to be assigned to this thread.
 					KNullDesC, to create an anonymous thread.
-@param aFunction    A pointer to a function.. Control passes to this function
-                    when the thread is first resumed, i.e. when the thread
-                    is initially scheduled to run.
-@param aStackSize   The size of the new thread's stack.
+@param aFunction	A pointer to a function.. Control passes to this function
+					when the thread is first resumed, i.e. when the thread
+					is initially scheduled to run.
+@param aStackSize	The size of the new thread's stack.  This must be at least
+					512 bytes, otherwise this method will fail with KErrArgument.
 @param aHeapMinSize The minimum size for the new thread's heap.
 @param aHeapMaxSize The maximum size for the new thread's heap.
-@param aPtr         A pointer to data to be passed as a parameter to
-                    the thread function when the thread is initially scheduled
-                    to run. If the thread function does not need any data then
-                    this pointer can be NULL. It must be ensured that the memory 
-                    pointed to by this pointer is still valid when accessed by 
-                    the new thread, e.g. if aPtr points to data on the stack.
-@param aType        An enumeration whose enumerators define the ownership of
-                    this thread handle. If not explicitly specified,
-                    EOwnerProcess is taken as default.
+@param aPtr			A pointer to data to be passed as a parameter to
+					the thread function when the thread is initially scheduled
+					to run. If the thread function does not need any data then
+					this pointer can be NULL. It must be ensured that the memory 
+					pointed to by this pointer is still valid when accessed by 
+					the new thread, e.g. if aPtr points to data on the stack.
+@param aType		An enumeration whose enumerators define the ownership of
+					this thread handle. If not explicitly specified,
+					EOwnerProcess is taken as default.
 
 @return KErrNone if successful, otherwise one of the other system-wide error codes.
+		KErrArgument if aStackSize is less than 512 bytes.
         KErrAlreadyExists will be returned if there is another thread in this process with the
         specified name.
 
@@ -3630,7 +3633,10 @@
 @panic USER 110 if aHeapMinSize is less than KMinHeapSize.
 @panic USER 111 if aHeapMaxSize is less than aHeapMinSize.
 */
-	{
+	{// This must be true otherwise the comment on aStackSize will be incorrect and BC 
+	// break will occur.  See ExecHandler::ThreadCreate() for details.
+	__ASSERT_COMPILE(KMaxThreadCreateInfo == 256);
+
 	TThreadCreateInfo createInfo(aName, aFunction, aStackSize, aPtr);
 	createInfo.SetOwner(aType);
 	createInfo.SetCreateHeap(aHeapMinSize, aHeapMaxSize);
@@ -3655,25 +3661,27 @@
 If KNullDesC is specified for the name, then an anonymous thread will be created.
 Anonymous threads are not global, and cannot be opened by other processes.
 
-@param aName      The name to be assigned to this thread.
-				  KNullDesC, to create an anonymous thread.
-@param aFunction  A pointer to a function. Control passes to this function when 
-	              the thread is first resumed, i.e. when the thread is
-	              initially scheduled to run.
-@param aStackSize The size of the new thread's stack.
-@param aAllocator A pointer to the handle of the heap belonging to another thread 
-                  which this thread is to use.
-@param aPtr       A pointer to data to be passed as a parameter to the thread
-                  function when the thread is initially scheduled to run.
-                  If the thread function does not need any data,
-                  then this pointer can be NULL. It must be ensured that the 
-                  memory pointed to by this pointer is still valid when accessed 
-                  by the new thread, e.g. if aPtr points to data on the stack.
-@param aType      An enumeration whose enumerators define the ownership of this 
-                  thread handle. If not explicitly specified, EOwnerProcess is
-                  taken as default.
+@param aName		The name to be assigned to this thread.
+					KNullDesC, to create an anonymous thread.
+@param aFunction	A pointer to a function. Control passes to this function when 
+					the thread is first resumed, i.e. when the thread is
+					initially scheduled to run.
+@param aStackSize	The size of the new thread's stack.  This must be at least
+					512 bytes, otherwise this method will fail with KErrArgument.
+@param aAllocator	A pointer to the handle of the heap belonging to another thread 
+					which this thread is to use.
+@param aPtr			A pointer to data to be passed as a parameter to the thread
+					function when the thread is initially scheduled to run.
+					If the thread function does not need any data,
+					then this pointer can be NULL. It must be ensured that the 
+					memory pointed to by this pointer is still valid when accessed 
+					by the new thread, e.g. if aPtr points to data on the stack.
+@param aType		An enumeration whose enumerators define the ownership of this 
+					thread handle. If not explicitly specified, EOwnerProcess is
+					taken as default.
 
 @return KErrNone if successful otherwise one of the other system-wide error codes.
+		KErrArgument if aStackSize is less than 512 bytes.
         KErrAlreadyExists will be returned if there is another thread in this process with the
         specified name.
 
--- a/kernel/eka/include/d32otgdi.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/include/d32otgdi.h	Tue May 04 18:23:12 2010 +0100
@@ -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"
@@ -348,7 +348,13 @@
 		EMessageVbusPowerDownNotPermitted	= KErrUsbOtgVbusPowerDownNotPermitted,
 		EMessageVbusClearErrorNotPermitted	= KErrUsbOtgVbusClearErrorNotPermitted,
 		EMessageHnpNotResponding			= KErrUsbOtgHnpNotResponding,
-		EMessageHnpBusDrop					= KErrUsbOtgHnpBusDrop
+		EMessageHnpBusDrop					= KErrUsbOtgHnpBusDrop,
+		
+		/**
+		Bad device attach/detach message
+		*/
+		EMessageBadDeviceAttached 			= KErrUsbOtgBadDeviceAttached,
+		EMessageBadDeviceDetached 			= KEventUsbOtgBadDeviceDetached
 		};
 
 public:
--- a/kernel/eka/include/d32otgdi_errors.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/include/d32otgdi_errors.h	Tue May 04 18:23:12 2010 +0100
@@ -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"
@@ -36,8 +36,13 @@
 const TInt KErrUsbOtgStateQueueOverflow			= -6671;
 const TInt KErrUsbOtgMessageQueueOverflow		= -6672;
 
+const TInt KErrUsbOtgBadDeviceAttached 			= -6673;
+const TInt KEventUsbOtgBadDeviceDetached 		= -6674;
+
 const TInt KErrUsbOtgBadState					= -6675;
 
+const TInt KErrUsbOtgInOPTTestingMode              = -6676;
+
 const TInt KErrUsbOtgStackNotStarted			= -6680;
 const TInt KErrUsbOtgVbusAlreadyRaised			= -6681;
 const TInt KErrUsbOtgSrpForbidden				= -6682;
--- a/kernel/eka/include/d32usbdi.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/include/d32usbdi.h	Tue May 04 18:23:12 2010 +0100
@@ -180,7 +180,7 @@
 	// Some utility functions
 	//
 	inline TInt GetBusId(TUsbBusId& aBusId);
-	inline TInt HcdPageSize();
+	inline TInt GetHcdPageSize(TInt& aHcdPageSize);
 	inline TInt GetDeviceSpeed(TDeviceSpeed& aDeviceSpeed);
 
 private:
--- a/kernel/eka/include/d32usbdi.inl	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/include/d32usbdi.inl	Tue May 04 18:23:12 2010 +0100
@@ -414,11 +414,12 @@
 /**
 Returns the size of pages used by the HCD.
 @internalComponent
-@return The HCD's page size.
+@param aHcdPageSize on success provides the HCD's page size.
+@return KErrNone on success, otherwise a system-wide error code.
 */
-TInt RUsbInterface::HcdPageSize()
+TInt RUsbInterface::GetHcdPageSize(TInt& aHcdPageSize)
 	{
-	return DoControl(EHcdPageSize);
+	return DoControl(EHcdPageSize, &aHcdPageSize);
 	}
 
 /**
--- a/kernel/eka/include/d32usbtransfers.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/include/d32usbtransfers.h	Tue May 04 18:23:12 2010 +0100
@@ -54,7 +54,7 @@
 friend class RUsbTransferStrategy;
 
 public:
-	virtual void Close();
+	IMPORT_C virtual void Close();
 
 protected:
 	RUsbTransferDescriptor(TTransferType aType, TInt aMaxSize, TInt aMaxNumPackets);
--- a/kernel/eka/include/drivers/sdcard.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/include/drivers/sdcard.h	Tue May 04 18:23:12 2010 +0100
@@ -44,6 +44,7 @@
 const TUint32 KSDSwitchFunctionHighSpeed = 0x80FFFF01;
 
 const TUint32 KSDCardIsSDCard			 = KBit16;	// KMMCardFirstCustomFlag
+const TUint32 KSDCardIsCorrupt           = KBit17;
 const TUint32 KSDCardFirstCustomFlag	 = KBit24;
 
 const TUint   KSDDTClk25MHz				 = 25000; //25000KHz
--- a/kernel/eka/include/e32ver.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/include/e32ver.h	Tue May 04 18:23:12 2010 +0100
@@ -28,7 +28,7 @@
 
 const TInt KE32MajorVersionNumber=2;
 const TInt KE32MinorVersionNumber=0;
-const TInt KE32BuildVersionNumber=3040;
+const TInt KE32BuildVersionNumber=3053;
 
 const TInt KMachineConfigurationMajorVersionNumber=1;
 const TInt KMachineConfigurationMinorVersionNumber=0;
--- a/kernel/eka/include/kernel/kerncorestats.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/include/kernel/kerncorestats.h	Tue May 04 18:23:12 2010 +0100
@@ -1,7 +1,7 @@
 // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
 // All rights reserved.
 // This component and the accompanying materials are made available
-// under the terms of "Eclipse Public License v1.0"
+// 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".
 //
--- a/kernel/eka/include/memmodel/epoc/mmubase/mmubase.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/include/memmodel/epoc/mmubase/mmubase.h	Tue May 04 18:23:12 2010 +0100
@@ -410,6 +410,7 @@
 	TInt ZoneAllocPhysicalRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aNumPages, TPhysAddr* aPageList);
 	TInt FreePhysicalRam(TPhysAddr aPhysAddr, TInt aSize);
 	TInt FreePhysicalRam(TInt aNumPages, TPhysAddr* aPageList);
+	TInt FreeRamZone(TUint aZoneId, TPhysAddr& aZoneBase, TUint& aZoneBytes);
 	TInt ClaimPhysicalRam(TPhysAddr aPhysAddr, TInt aSize);
 	TInt GetPageTableId(TPhysAddr aPtPhys);
 	void MapRamPage(TLinAddr aAddr, TPhysAddr aPage, TPte aPtePerm);
--- a/kernel/eka/include/memmodel/epoc/mmubase/ramalloc.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/include/memmodel/epoc/mmubase/ramalloc.h	Tue May 04 18:23:12 2010 +0100
@@ -153,7 +153,7 @@
 	TInt GetZonePageCount(TUint aId, SRamZonePageCount& aPageData);
 	void ChangePageType(SPageInfo* aPageInfo, TZonePageType aOldType, TZonePageType aNewType);
 #ifdef BTRACE_RAM_ALLOCATOR
-	void SendInitialBtraceLogs(void);
+	void DoBTracePrime(void);
 #endif
 	TInt GetZoneAddress(TUint aZoneId, TPhysAddr& aPhysBase, TUint& aNumPages);
 	TInt HalFunction(TInt aFunction, TAny* a1, TAny* a2);
--- a/kernel/eka/include/memmodel/epoc/platform.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/include/memmodel/epoc/platform.h	Tue May 04 18:23:12 2010 +0100
@@ -382,6 +382,7 @@
 	IMPORT_C static TInt ZoneAllocPhysicalRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aNumPages, TPhysAddr* aPageList);
 	IMPORT_C static TInt FreePhysicalRam(TPhysAddr aPhysAddr, TInt aSize);
 	IMPORT_C static TInt FreePhysicalRam(TInt aNumPages, TPhysAddr* aPageList);
+	IMPORT_C static TInt FreeRamZone(TUint aZoneId);
 	IMPORT_C static TInt ClaimPhysicalRam(TPhysAddr aPhysAddr, TInt aSize);
 	IMPORT_C static TPhysAddr LinearToPhysical(TLinAddr aLinAddr);
 	IMPORT_C static void RomProcessInfo(TProcessCreateInfo& aInfo, const TRomImageHeader& aRomImageHeader);	/**< @internalComponent */
--- a/kernel/eka/kernel/arm/cipc.cia	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/kernel/arm/cipc.cia	Tue May 04 18:23:12 2010 +0100
@@ -57,7 +57,7 @@
 
 __NAKED__ void ExecHandler::MessageComplete(RMessageK* /*aMsg*/, TInt /*aReason*/)
 	{
-	asm("ldr ip, [r0, #%a0]" : : "i" _FOFF(RMessageK, iFunction));		// get iFunction, as per preprocessor
+	asm("ldr ip, [r0, #%a0]" : : "i" _FOFF(RMessageK, iFunction));				// get iFunction, as per preprocessor
 
 	// Subroutine MessageComplete
 	// Complete an IPC message
@@ -69,65 +69,73 @@
 
 #ifdef BTRACE_CLIENT_SERVER
 	asm("stmfd sp!,{r0,r1,ip,lr}");
-	asm("mov r2,r1");							// arg2 = aReason
-	asm("mov r1,r0");							// arg1 = aMsg
-	asm("ldr r0,_messageCompleteTraceHeader");	// arg0 = header
+	asm("mov r2,r1");															// arg2 = aReason
+	asm("mov r1,r0");															// arg1 = aMsg
+	asm("ldr r0,_messageCompleteTraceHeader");									// arg0 = header
 	asm("bl " CSM_ZN6BTrace4OutXEmmmm);
 	asm("ldmfd sp!,{r0,r1,ip,lr}");
 #endif
 
 	asm("cmp ip, #%a0" : : "i" (RMessage2::EDisConnect));
 	asm("ldreq r0, [r0, #%a0]" : : "i" _FOFF(RMessageK,iSession));
-	asm("beq " CSM_ZN8DSession19CloseFromDisconnectEv );	// if disconnect, do it in C++
-	asm("mov r2, r1 ");					// r2=aReason
+	asm("beq " CSM_ZN8DSession19CloseFromDisconnectEv );						// if disconnect, do it in C++
+
+	asm("mov r2, r1 ");															// r2 = aReason
 	ASM_DEBUG2(Complete,r0,r2);
-	asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(RMessageK, iSession)); 	// r3=iSession
-	
-	asm("subs r1, ip, #%a0" : : "i" (RMessage2::EConnect));		// (m.iFunction == RMessage2::EConnect)?
-	asm("streq r1, [r3, #%a0] " : : "i" _FOFF(DSession, iConnectMsgPtr));	// iSession->iConnectMsgPtr = NULL
-
-	asm("ldr r1, [r3, #%a0]" : : "i" _FOFF(DSession,iAccessCount));	// r1=iSession->iAccessCount	
-	asm("cmp r1, #0 ");					// iAccessCount = 0?
+	asm("ldr r3, [r0, #%a0]" : : "i" _FOFF(RMessageK, iSession)); 				// r3 = iSession
+	asm("subs r1, ip, #%a0" : : "i" (RMessage2::EConnect));						// (m.iFunction == RMessage2::EConnect)?
+	asm("streq r1, [r3, #%a0] " : : "i" _FOFF(DSession, iConnectMsgPtr));		// iSession->iConnectMsgPtr = NULL
+	asm("ldr r1, [r3, #%a0]" : : "i" _FOFF(DSession,iAccessCount));				// r1 = iSession->iAccessCount	
+	asm("cmp r1, #0 ");															// iAccessCount = 0?
 	asm("beq 2f ");
 
-	// if (!s->IsClosing())
-	asm("mov r1, r0");					// r1 = RMessageK ptr
-	asm("ldr r0, [r0, #%a0] " : : "i" _FOFF(RMessageK,iClient));    // r0=iClient
+	// !s->IsClosing()
+	asm("mov r1, r0");															// r1 = RMessageK ptr
+	asm("ldr r0, [r0, #%a0] " : : "i" _FOFF(RMessageK,iClient));    			// r0 = iClient
+	asm("ldrb ip, [r0, #%a0] " : : "i" _FOFF(DThread,iMState));    				// ip = iClient->iMState
+	asm("cmp ip, #%a0" : : "i" (DThread::EDead));								// (iMState == EDead)?
+	asm("beq 1f ");
+
+	// if (!s->IsClosing() && m.iClient->iMState != DThread::EDead)
 	asm("mov ip, #1");
-	asm("str ip, [r1, #%a0]" : : "i" _FOFF(RMessageK, iServerLink.iNext));	// iServerLink.iNext=1
-	asm("b " CSM_ZN4Kern20QueueRequestCompleteEP7DThreadP14TClientRequesti);
+	asm("str ip, [r1, #%a0]" : : "i" _FOFF(RMessageK, iServerLink.iNext));		// iServerLink.iNext=1
+	asm("b " CSM_ZN4Kern20QueueRequestCompleteEP7DThreadP14TClientRequesti);	// tail call
 
-	// if (s->IsClosing())
+	// m.iClient->iMState == DThread::EDead
+	asm("1: ");																	// shuffle RMessageK and iFunction back to expected registers
+	asm("ldr ip, [r1, #%a0]" : : "i" _FOFF(RMessageK, iFunction));				// refetch iFunction
+	asm("mov r0, r1");															// r0 = RMessageK ptr
+
+	// else (closing or dead)
 	asm("2: ");
-	asm("cmp ip, #%a0" : : "i" (RMessage2::EConnect));	// (m.iFunction == RMessage2::EConnect)?
-	asm("beq 4f ");
-	asm("3: ");
-	asm("stmfd sp!, {r0,lr} ");
-	asm("bl " CSM_ZN14TClientRequest5ResetEv);
-	asm("ldmfd sp!, {r0,lr} ");
-	asm("b " CSM_ZN9RMessageK8CloseRefEv);
+	asm("cmp ip, #%a0" : : "i" (RMessage2::EConnect));							// (m.iFunction == RMessage2::EConnect)?
+	asm("bne 3f ");
 
-	asm("4: ");
-	// if closing & connect msg
-	asm("ldr r2, [r3, #%a0] " : : "i" _FOFF(DSession, iSessionCookie));	// r2=iSession->iSessionCookie
+	// (closing or dead) and it's a connect msg
+	asm("ldr r2, [r3, #%a0] " : : "i" _FOFF(DSession, iSessionCookie));			// r2=iSession->iSessionCookie
 	asm("teq r2, #0");
 #ifdef _DEBUG
 	asm("beq nosession ");
-	asm("ldr r1, [r3, #%a0] " : : "i" _FOFF(DSession, iServer));		// r1=iSession->iServer
+	asm("ldr r1, [r3, #%a0] " : : "i" _FOFF(DSession, iServer));				// r1=iSession->iServer
 	asm("cmp r1, #0 ");
  	asm("beq noserver ");
-	asm("ldr r2, [r3, #%a0] " : : "i" (_FOFF(DSession, iDisconnectMsgPtr)));  // r2=iSession->iDisconnectMsgPtr
+	asm("ldr r2, [r3, #%a0] " : : "i" (_FOFF(DSession, iDisconnectMsgPtr)));	// r2=iSession->iDisconnectMsgPtr
 	asm("ldr r2, [r2, #%a0] " : : "i" (_FOFF(RMessageK, iServerLink.iNext)));	// r2=iDisconnectMsgPtr->iServerLink.iNext
 	asm("cmp r2, #0 ");
-	asm("beq __FaultMsgCompleteDiscNotSent ");	// die if a session has been created and no disc msg sent
-	asm("ldr r2, [r3, #%a0] " : : "i" _FOFF(DSession, iSessionCookie));	// r2=iSession->iSessionCookie
+	asm("beq __FaultMsgCompleteDiscNotSent ");									// tail call to die if a session has been created and no disc msg sent
+	asm("ldr r2, [r3, #%a0] " : : "i" _FOFF(DSession, iSessionCookie));			// r2=iSession->iSessionCookie
 	asm("noserver: ");
 	asm("teq r2, #0");
 	asm("nosession: ");
 #endif //_DEBUG
 	asm("moveq r0, r3 ");
-	asm("beq __SendDiscMsg ");	// if no session object to clean up, send disc msg in C++
-	asm("b 3b ");				// return
+	asm("beq __SendDiscMsg ");													// if no session object to clean up, tail call to send disc msg in C++
+
+	asm("3: ");
+	asm("stmfd sp!, {r0,lr} ");
+	asm("bl " CSM_ZN14TClientRequest5ResetEv);
+	asm("ldmfd sp!, {r0,lr} ");
+	asm("b " CSM_ZN9RMessageK8CloseRefEv);										// tail call
 
 #ifdef BTRACE_CLIENT_SERVER
 	asm("_messageCompleteTraceHeader:");
--- a/kernel/eka/kernel/kerncorestats.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/kernel/kerncorestats.cpp	Tue May 04 18:23:12 2010 +0100
@@ -1,7 +1,7 @@
 // Copyright (c) 1994-2009 Nokia Corporation and/or its subsidiary(-ies).
 // All rights reserved.
 // This component and the accompanying materials are made available
-// under the terms of "Eclipse Public License v1.0"
+// 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".
 //
--- a/kernel/eka/kernel/sexec.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/kernel/sexec.cpp	Tue May 04 18:23:12 2010 +0100
@@ -758,7 +758,7 @@
 
 	__KTRACE_OPT(KEXEC,Kern::Printf("Exec::ThreadRequestSignal"));
 	if(aThread->iOwningProcess!=TheCurrentThread->iOwningProcess)
-		K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Attempt to use RThread::RequestComplete on a thread in another process"));
+		K::ProcessIsolationFailure(__PLATSEC_DIAGNOSTIC_STRING("Attempt to use RThread::RequestComplete or RThread::RequestSignal on a thread in another process"));
 	NKern::ThreadRequestSignal(&aThread->iNThread, SYSTEM_LOCK);
 	}
 
--- a/kernel/eka/kernel/sipc.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/kernel/sipc.cpp	Tue May 04 18:23:12 2010 +0100
@@ -1144,7 +1144,7 @@
 
 		if(m->IsDelivered() || m->IsAccepted())
 			{
-			if (!IsClosing())
+			if (!IsClosing() && t->iMState != DThread::EDead)
 				{
 				m->SetCompleting();
 				Kern::QueueRequestComplete(t, m, aReason);
@@ -1752,7 +1752,7 @@
 		s->iConnectMsgPtr = NULL;
 
 	__KTRACE_OPT(KIPC,Kern::Printf("MsgCo: M:%d r:%d %O->%O", m.iFunction, aReason, TheCurrentThread, m.iClient));
-	if (!s->IsClosing())
+	if (!s->IsClosing() && m.iClient->iMState != DThread::EDead)
 		{
 		m.SetCompleting();
 		Kern::QueueRequestComplete(m.iClient, &m, aReason);
--- a/kernel/eka/kernel/sthread.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/kernel/sthread.cpp	Tue May 04 18:23:12 2010 +0100
@@ -114,8 +114,23 @@
 	iTls.Close();
 	if (iSyncMsgPtr)
 		{
-		__KTRACE_OPT(KSERVER,Kern::Printf("DThread::Destruct(%08X) freeing sync message at %08X", this, iSyncMsgPtr));
-		iSyncMsgPtr->ReleaseMessagePool(RMessageK::ESync, 1);
+		// The sync message might still be outstanding; in particular it may be
+		// on the kernel server's list of messages to be cleaned up on behalf of
+		// dead clients. So we only release it here if it's free; otherwise, we
+		// mutate the type, so that cleanup will return it to the Global pool.
+		NKern::LockSystem();
+		if (iSyncMsgPtr->IsFree())
+			{
+			NKern::UnlockSystem();
+			__KTRACE_OPT(KSERVER,Kern::Printf("DThread::Destruct(%08X) releasing sync message at %08X", this, iSyncMsgPtr));
+			iSyncMsgPtr->ReleaseMessagePool(RMessageK::ESync, 1);
+			}
+		else
+			{
+			__KTRACE_OPT(KSERVER,Kern::Printf("DThread::Destruct(%08X) mutating sync message at %08X", this, iSyncMsgPtr));
+			iSyncMsgPtr->iMsgType = RMessageK::EGlobal;
+			NKern::UnlockSystem();
+			}
 		iSyncMsgPtr = NULL;
 		}
 	FreeSupervisorStack();
--- a/kernel/eka/memmodel/epoc/direct/mutils.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/direct/mutils.cpp	Tue May 04 18:23:12 2010 +0100
@@ -474,6 +474,32 @@
 
 
 /**
+Free a RAM zone which was previously allocated by one of these methods:
+Epoc::AllocPhysicalRam(), Epoc::ZoneAllocPhysicalRam() or 
+TRamDefragRequest::ClaimRamZone().
+
+All of the pages in the RAM zone must be allocated and only via one of the methods 
+listed above, otherwise a system panic will occur.
+
+@param	aZoneId			The ID of the RAM zone to free.
+@return	KErrNone 		If the operation was successful.
+		KErrArgument 	If a RAM zone with ID aZoneId was not found.
+
+@pre Calling thread must be in a critical section.
+@pre Interrupts must be enabled.
+@pre Kernel must be unlocked.
+@pre No fast mutex can be held.
+@pre Call in a thread context.
+@pre Can be used in a device driver.
+*/
+EXPORT_C TInt Epoc::FreeRamZone(TUint aZoneId)
+	{
+	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"Epoc::FreeRamZone");
+	return KErrNotSupported;
+	}
+
+
+/**
 	@pre	Call in a thread context.
 	@pre	Interrupts must be enabled.
 	@pre	Kernel must be unlocked.
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.cpp	Tue May 04 18:23:12 2010 +0100
@@ -64,7 +64,7 @@
 	*/
 	static DCodePagedMemoryManager TheManager;
 
-	friend DPagingDevice* CodePagingDevice(TInt aDiveNum);
+	friend DPagingDevice* CodePagingDevice(TInt aDriveNum);
 	};
 
 
@@ -207,11 +207,11 @@
 
 TInt DCodePagedMemoryManager::CleanPage(DMemoryObject* aMemory, SPageInfo* aPageInfo, TPhysAddr*& aPageArrayEntry)
 	{
-	if(aPageInfo->IsDirty()==false)
+	if(!aPageInfo->IsDirty())
 		return KErrNone;
 
 	// shouldn't be asked to clean a page which is writable...
-	__NK_ASSERT_DEBUG(aPageInfo->IsWritable()==false);
+	__NK_ASSERT_DEBUG(!aPageInfo->IsWritable());
 
 	// Note, memory may have been modified by the CodeModifier class.
 
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mcodepaging.h	Tue May 04 18:23:12 2010 +0100
@@ -21,6 +21,6 @@
 #ifndef MCODEPAGING_H
 #define MCODEPAGING_H
 
-extern DPagingDevice* CodePagingDevice(TInt aDiveNum);
+extern DPagingDevice* CodePagingDevice(TInt aDriveNum);
 
 #endif
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mexport.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mexport.cpp	Tue May 04 18:23:12 2010 +0100
@@ -16,7 +16,7 @@
 #include "memmodel.h"
 #include "mm.h"
 #include "mmu.h"
-
+#include "mpager.h"
 #include "mrom.h"
 
 /**	Returns the amount of free RAM currently available.
@@ -510,6 +510,35 @@
 
 
 /**
+Free a RAM zone which was previously allocated by one of these methods:
+Epoc::AllocPhysicalRam(), Epoc::ZoneAllocPhysicalRam() or 
+TRamDefragRequest::ClaimRamZone().
+
+All of the pages in the RAM zone must be allocated and only via one of the methods 
+listed above, otherwise a system panic will occur.
+
+@param	aZoneId			The ID of the RAM zone to free.
+@return	KErrNone 		If the operation was successful.
+		KErrArgument 	If a RAM zone with ID aZoneId was not found.
+
+@pre Calling thread must be in a critical section.
+@pre Interrupts must be enabled.
+@pre Kernel must be unlocked.
+@pre No fast mutex can be held.
+@pre Call in a thread context.
+@pre Can be used in a device driver.
+*/
+EXPORT_C TInt Epoc::FreeRamZone(TUint aZoneId)
+	{
+	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"Epoc::FreeRamZone");
+	RamAllocLock::Lock();
+	TInt r = TheMmu.FreeRamZone(aZoneId);
+	RamAllocLock::Unlock();
+	return r;
+	}
+
+
+/**
 Allocate a specific block of physically contiguous RAM, specified by physical
 base address and size.
 If and when the RAM is no longer required it should be freed using
@@ -607,13 +636,29 @@
 	}
 
 
-#ifdef BTRACE_KERNEL_MEMORY
 void M::BTracePrime(TUint aCategory)
 	{
-	// TODO:
+	(void)aCategory;
+
+#ifdef BTRACE_KERNEL_MEMORY
+	// Must check for -1 as that is the default value of aCategory for
+	// BTrace::Prime() which is intended to prime all categories that are 
+	// currently enabled via a single invocation of BTrace::Prime().
+	if(aCategory == BTrace::EKernelMemory || (TInt)aCategory == -1)
+		{
+		NKern::ThreadEnterCS();
+		RamAllocLock::Lock();
+		BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryInitialFree, TheSuperPage().iTotalRamSize);
+		BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryCurrentFree, Kern::FreeRamInBytes());
+		BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscAlloc, Epoc::KernelMiscPages << KPageShift);
+		BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryDemandPagingCache, ThePager.MinimumPageCount() << KPageShift);
+		BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, Epoc::DriverAllocdPhysRam, -1);
+		RamAllocLock::Unlock();
+		NKern::ThreadLeaveCS();
+		}
+#endif
+	TheMmu.BTracePrime(aCategory);
 	}
-#endif
-
 
 
 //
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mm.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mm.cpp	Tue May 04 18:23:12 2010 +0100
@@ -394,7 +394,7 @@
 	}
 
 
-TInt MM::MemoryAddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages)
+TInt MM::MemoryAddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, const TPhysAddr* aPages)
 	{
 	TRACE(("MM::MemoryAddPages(0x%08x,0x%08x,0x%08x,?)",aMemory,aIndex,aCount));
 	MemoryObjectLock::Lock(aMemory);
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mm.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mm.h	Tue May 04 18:23:12 2010 +0100
@@ -84,6 +84,9 @@
 	EMemoryObjectMovable but with the additional option of marking pages as
 	'discardable'. Discardable pages may be reclaimed (remove) by the system at
 	any time, this state is controlled using the functions:
+	- MM::MemoryAlloc
+	- MM::MemoryAllocContiguous
+	- MM::MemoryFree
 	- MM::MemoryAllowDiscard
 	- MM::MemoryDisallowDiscard
 	*/
@@ -485,7 +488,7 @@
 			KErrNotSupported, if the memory object doesn't support this operation;
 			otherwise another of the system wide error codes.
 	*/
-	static TInt MemoryAddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages);
+	static TInt MemoryAddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, const TPhysAddr* aPages);
 
 	/**
 	Add a contiguous range of pages to a region in a memory object.
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mmanager.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mmanager.cpp	Tue May 04 18:23:12 2010 +0100
@@ -66,7 +66,7 @@
 	}
 
 
-TInt DMemoryManager::AddPages(DMemoryObject* /*aMemory*/, TUint /*aIndex*/, TUint /*aCount*/, TPhysAddr* /*aPages*/)
+TInt DMemoryManager::AddPages(DMemoryObject* /*aMemory*/, TUint /*aIndex*/, TUint /*aCount*/, const TPhysAddr* /*aPages*/)
 	{
 	return KErrNotSupported;
 	}
@@ -1161,7 +1161,7 @@
 public:
 	// from DMemoryManager...
 	virtual void Destruct(DMemoryObject* aMemory);
-	virtual TInt AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages);
+	virtual TInt AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, const TPhysAddr* aPages);
 	virtual TInt AddContiguous(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr aPhysAddr);
 	virtual TInt RemovePages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages);
 	virtual TInt Pin(DMemoryObject* aMemory, DMemoryMappingBase* aMapping, TPinArgs& aPinArgs);
@@ -1226,14 +1226,14 @@
 	}
 
 
-TInt DHardwareMemoryManager::AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages)
+TInt DHardwareMemoryManager::AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, const TPhysAddr* aPages)
 	{
 	TRACE2(("DHardwareMemoryManager::AddPages(0x%08x,0x%x,0x%x,?)",aMemory, aIndex, aCount));
 	__NK_ASSERT_DEBUG(MemoryObjectLock::IsHeld(aMemory));
 
 	// validate arguments...
-	TPhysAddr* pages = aPages;
-	TPhysAddr* pagesEnd = aPages+aCount;
+	const TPhysAddr* pages = aPages;
+	const TPhysAddr* pagesEnd = aPages+aCount;
 	TPhysAddr checkMask = 0;
 	do checkMask |= *pages++;
 	while(pages<pagesEnd);
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mmanager.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mmanager.h	Tue May 04 18:23:12 2010 +0100
@@ -153,7 +153,7 @@
 			KErrNotSupported if the manager doesn't support this function,
 			otherwise one of the system wide error codes.
 	*/
-	virtual TInt AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, TPhysAddr* aPages);
+	virtual TInt AddPages(DMemoryObject* aMemory, TUint aIndex, TUint aCount, const TPhysAddr* aPages);
 
 	/**
 	Add a contiguous range of physical memory pages to a region of a memory object.
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mmappinglist.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mmappinglist.cpp	Tue May 04 18:23:12 2010 +0100
@@ -153,6 +153,7 @@
 			iPrev = prev;
 			// flash lock...
 			__SPIN_FLASH_IRQ(iSpinLock);
+			flash = 0;
 			// remove iterator again...
 			next = iNext;
 			prev = iPrev;
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mmappinglist.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mmappinglist.h	Tue May 04 18:23:12 2010 +0100
@@ -206,23 +206,15 @@
 	/**
 	Update the page table entry for a specified page in all mappings in the list that contain it.
 
-	@param aPages				The page array entry of the page in a memory object. 
+	@param aPageArray			The page array entry of the page in a memory object. 
 								Only array entries which have a target state of 
 								RPageArray::ECommitted should be mapped into the 
 								mapping's page tables.
-
 	@param aIndex				The index of the page in the memory object.
-
-	@param aMapInstanceCount	The instance of this mapping which is to be updated.
-								Whenever this no longer matches the current #MapInstanceCount
-								the function must not update any more of the mapping's
-								page table entries, (but must still return KErrNone).
-
-	@param	aInvalidateTLB		Set to ETrue when the TLB entries associated with this page
+	@param aInvalidateTLB		Set to ETrue when the TLB entries associated with this page
 								should be invalidated.  This must be done when there is 
 								already a valid pte for this page, i.e. if the page is still 
 								mapped.
-
 	@see #DMemoryMappingBase::RemapPage
 	*/
 	void RemapPage(TPhysAddr& aPageArray, TUint aIndex, TBool aInvalidateTLB);	
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mmu.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mmu.cpp	Tue May 04 18:23:12 2010 +0100
@@ -312,7 +312,8 @@
 	}
 
 
-#if 0
+#ifdef FMM_VERIFY_RAM
+// Attempt to write to each unused RAM page and verify the contents.
 void Mmu::VerifyRam()
 	{
 	Kern::Printf("Mmu::VerifyRam() pass 1");
@@ -474,6 +475,10 @@
 					__ASSERT_ALWAYS(r==KErrNone || r==KErrAlreadyExists, Panic(EBadMappedPageAfterBoot));
 					if(pi->Type()==SPageInfo::EUnused)
 						pi->SetFixed();
+#ifdef BTRACE_KERNEL_MEMORY
+					if(r == KErrNone)
+						++Epoc::KernelMiscPages;
+#endif
 					}
 				}
 			}
@@ -500,21 +505,24 @@
 	r = K::MutexCreate(iPhysMemSyncMutex, KLitPhysMemSync, NULL, EFalse, KMutexOrdSyncPhysMem);
 	if(r!=KErrNone)
 		Panic(EPhysMemSyncMutexCreateFailed);
-//	VerifyRam();
+
+#ifdef FMM_VERIFY_RAM
+	VerifyRam();
+#endif
 	}
 
 
 void Mmu::Init2FinalCommon()
 	{
 	__KTRACE_OPT2(KBOOT,KMMU,Kern::Printf("Mmu::Init2FinalCommon"));
-	// hack, reduce free memory to <2GB...
+	// Reduce free memory to <2GB...
 	while(FreeRamInPages()>=0x80000000/KPageSize)
 		{
 		TPhysAddr dummyPage;
 		TInt r = iRamPageAllocator->AllocRamPages(&dummyPage,1, EPageFixed);
 		__NK_ASSERT_ALWAYS(r==KErrNone);
 		}
-	// hack, reduce total RAM to <2GB...
+	// Reduce total RAM to <2GB...
 	if(TheSuperPage().iTotalRamSize<0)
 		TheSuperPage().iTotalRamSize = 0x80000000-KPageSize;
 
@@ -540,6 +548,27 @@
 	iDefrag->Init3(TheMmu.iRamPageAllocator);
 	}
 
+
+void Mmu::BTracePrime(TUint aCategory)
+	{
+	(void)aCategory;
+
+#ifdef BTRACE_RAM_ALLOCATOR
+	// Must check for -1 as that is the default value of aCategory for
+	// BTrace::Prime() which is intended to prime all categories that are 
+	// currently enabled via a single invocation of BTrace::Prime().
+	if(aCategory==BTrace::ERamAllocator || (TInt)aCategory == -1)
+		{
+		NKern::ThreadEnterCS();
+		RamAllocLock::Lock();
+		iRamPageAllocator->DoBTracePrime();
+		RamAllocLock::Unlock();
+		NKern::ThreadLeaveCS();
+		}
+#endif
+	}
+
+
 //
 // Utils
 //
@@ -619,18 +648,7 @@
 		PagesAllocated(aPageList, aNumPages, (Mmu::TRamAllocFlags)EMemAttStronglyOrdered);
 
 		// update page infos...
-		TUint flash = 0;
-		TPhysAddr* pageEnd = aPageList + aNumPages;
-		MmuLock::Lock();
-		TPhysAddr* page = aPageList;
-		while (page < pageEnd)
-			{
-			MmuLock::Flash(flash,KMaxPageInfoUpdatesInOneGo/2);
-			TPhysAddr pagePhys = *page++;
-			__NK_ASSERT_DEBUG(pagePhys != KPhysAddrInvalid);
-			SPageInfo::FromPhysAddr(pagePhys)->SetPhysAlloc();
-			}
-		MmuLock::Unlock();
+		SetAllocPhysRam(aPageList, aNumPages);
 		}
 	__KTRACE_OPT(KMMU,Kern::Printf("Mmu::ZoneAllocPhysicalRam returns %d",r));
 	return r;
@@ -963,19 +981,7 @@
 		return r;
 
 	// update page infos...
-	TPhysAddr* pages = aPages;
-	TPhysAddr* pagesEnd = pages+aCount;
-	MmuLock::Lock();
-	TUint flash = 0;
-	while(pages<pagesEnd)
-		{
-		MmuLock::Flash(flash,KMaxPageInfoUpdatesInOneGo/2);
-		TPhysAddr pagePhys = *pages++;
-		__NK_ASSERT_DEBUG(pagePhys!=KPhysAddrInvalid);
-		SPageInfo* pi = SPageInfo::FromPhysAddr(pagePhys);
-		pi->SetPhysAlloc();
-		}
-	MmuLock::Unlock();
+	SetAllocPhysRam(aPages, aCount);
 
 	return KErrNone;
 	}
@@ -1004,6 +1010,19 @@
 	MmuLock::Unlock();
 
 	iRamPageAllocator->FreeRamPages(aPages,aCount, EPageFixed);
+
+#ifdef BTRACE_KERNEL_MEMORY
+	if (BTrace::CheckFilter(BTrace::EKernelMemory))
+		{// Only loop round each page if EKernelMemory tracing is enabled
+		pages = aPages;
+		pagesEnd = aPages + aCount;
+		while (pages < pagesEnd)
+			{
+			BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysFree, KPageSize, *pages++);
+			Epoc::DriverAllocdPhysRam -= KPageSize;
+			}
+		}
+#endif
 	}
 
 
@@ -1015,17 +1034,7 @@
 		return r;
 
 	// update page infos...
-	SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr);
-	SPageInfo* piEnd = pi+aCount;
-	TUint flash = 0;
-	MmuLock::Lock();
-	while(pi<piEnd)
-		{
-		MmuLock::Flash(flash,KMaxPageInfoUpdatesInOneGo);
-		pi->SetPhysAlloc();
-		++pi;
-		}
-	MmuLock::Unlock();
+	SetAllocPhysRam(aPhysAddr, aCount);
 
 	return KErrNone;
 	}
@@ -1050,7 +1059,25 @@
 		}
 	MmuLock::Unlock();
 
-	iRamPageAllocator->FreePhysicalRam(aPhysAddr, aCount << KPageShift);
+	TUint bytes = aCount << KPageShift;
+	iRamPageAllocator->FreePhysicalRam(aPhysAddr, bytes);
+
+#ifdef BTRACE_KERNEL_MEMORY
+	BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysFree, bytes, aPhysAddr);
+	Epoc::DriverAllocdPhysRam -= bytes;
+#endif
+	}
+
+
+TInt Mmu::FreeRamZone(TUint aZoneId)
+	{
+	TPhysAddr zoneBase;
+	TUint zonePages;
+	TInt r = iRamPageAllocator->GetZoneAddress(aZoneId, zoneBase, zonePages);
+	if (r != KErrNone)
+		return r;
+	FreePhysicalRam(zoneBase, zonePages);
+	return KErrNone;
 	}
 
 
@@ -1058,25 +1085,11 @@
 	{
 	__KTRACE_OPT(KMMU,Kern::Printf("Mmu::ClaimPhysicalRam(0x%08x,0x%x,0x%08x)",aPhysAddr,aCount,aFlags));
 	aPhysAddr &= ~KPageMask;
-	TInt r = iRamPageAllocator->ClaimPhysicalRam(aPhysAddr,(aCount << KPageShift));
-	if(r!=KErrNone)
+	TInt r = iRamPageAllocator->ClaimPhysicalRam(aPhysAddr, aCount << KPageShift);
+	if(r != KErrNone)
 		return r;
 
-	PagesAllocated((TPhysAddr*)(aPhysAddr|1), aCount, aFlags);
-
-	// update page infos...
-	SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr);
-	SPageInfo* piEnd = pi+aCount;
-	TUint flash = 0;
-	MmuLock::Lock();
-	while(pi<piEnd)
-		{
-		MmuLock::Flash(flash,KMaxPageInfoUpdatesInOneGo);
-		pi->SetPhysAlloc();
-		++pi;
-		}
-	MmuLock::Unlock();
-
+	AllocatedPhysicalRam(aPhysAddr, aCount, aFlags);
 	return KErrNone;
 	}
 
@@ -1088,17 +1101,59 @@
 	PagesAllocated((TPhysAddr*)(aPhysAddr|1), aCount, aFlags);
 
 	// update page infos...
+	SetAllocPhysRam(aPhysAddr, aCount);
+	}
+
+
+void Mmu::SetAllocPhysRam(TPhysAddr aPhysAddr, TUint aCount)
+	{
 	SPageInfo* pi = SPageInfo::FromPhysAddr(aPhysAddr);
 	SPageInfo* piEnd = pi+aCount;
 	TUint flash = 0;
 	MmuLock::Lock();
 	while(pi<piEnd)
 		{
-		MmuLock::Flash(flash,KMaxPageInfoUpdatesInOneGo);
+		MmuLock::Flash(flash, KMaxPageInfoUpdatesInOneGo);
 		pi->SetPhysAlloc();
 		++pi;
 		}
 	MmuLock::Unlock();
+
+#ifdef BTRACE_KERNEL_MEMORY
+	TUint bytes = aCount << KPageShift;
+	BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, bytes, aPhysAddr);
+	Epoc::DriverAllocdPhysRam += bytes;
+#endif
+	}
+
+
+void Mmu::SetAllocPhysRam(TPhysAddr* aPageList, TUint aNumPages)
+	{
+	TPhysAddr* page = aPageList;
+	TPhysAddr* pageEnd = aPageList + aNumPages;
+	TUint flash = 0;
+	MmuLock::Lock();
+	while (page < pageEnd)
+		{
+		MmuLock::Flash(flash, KMaxPageInfoUpdatesInOneGo / 2);
+		TPhysAddr pagePhys = *page++;
+		__NK_ASSERT_DEBUG(pagePhys != KPhysAddrInvalid);
+		SPageInfo::FromPhysAddr(pagePhys)->SetPhysAlloc();
+		}
+	MmuLock::Unlock();
+
+#ifdef BTRACE_KERNEL_MEMORY
+	if (BTrace::CheckFilter(BTrace::EKernelMemory))
+		{// Only loop round each page if EKernelMemory tracing is enabled
+		TPhysAddr* pAddr = aPageList;
+		TPhysAddr* pAddrEnd = aPageList + aNumPages;
+		while (pAddr < pAddrEnd)
+			{
+			BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, KPageSize, *pAddr++);
+			Epoc::DriverAllocdPhysRam += KPageSize;
+			}
+		}
+#endif
 	}
 
 
@@ -1187,20 +1242,10 @@
 	__NK_ASSERT_DEBUG(iSize>=1);
 	__NK_ASSERT_DEBUG(iCount==0);
 
-	TUint colour = aColour&KPageColourMask;
-	TLinAddr addr = iLinAddr+(colour<<KPageShift);
-	TPte* pPte = iPtePtr+colour;
-	iColour = colour;
-
-	__ASSERT_DEBUG(*pPte==KPteUnallocatedEntry,MM::Panic(MM::ETempMappingAlreadyInUse));
-	*pPte = (aPage&~KPageMask) | iBlankPte;
-	CacheMaintenance::SinglePteUpdated((TLinAddr)pPte);
-	InvalidateTLBForPage(addr|KKernelOsAsid);
-
-	iCount = 1;
-	return addr;
+	return Map(aPage, aColour, iBlankPte);
 	}
 
+
 /**
 Map a single physical page into this temporary mapping using the given page table entry (PTE) value.
 
@@ -1215,16 +1260,17 @@
 	{
 	__NK_ASSERT_DEBUG(iSize>=1);
 	__NK_ASSERT_DEBUG(iCount==0);
-
-	TUint colour = aColour&KPageColourMask;
-	TLinAddr addr = iLinAddr+(colour<<KPageShift);
-	TPte* pPte = iPtePtr+colour;
+	__NK_ASSERT_DEBUG(!(aBlankPte & ~KPageMask));
+
+	TUint colour = aColour & KPageColourMask;
+	TLinAddr addr = iLinAddr + (colour << KPageShift);
+	TPte* pPte = iPtePtr + colour;
 	iColour = colour;
 
-	__ASSERT_DEBUG(*pPte==KPteUnallocatedEntry,MM::Panic(MM::ETempMappingAlreadyInUse));
-	*pPte = (aPage&~KPageMask) | aBlankPte;
+	__ASSERT_DEBUG(*pPte == KPteUnallocatedEntry, MM::Panic(MM::ETempMappingAlreadyInUse));
+	*pPte = (aPage & ~KPageMask) | aBlankPte;
 	CacheMaintenance::SinglePteUpdated((TLinAddr)pPte);
-	InvalidateTLBForPage(addr|KKernelOsAsid);
+	InvalidateTLBForPage(addr | KKernelOsAsid);
 
 	iCount = 1;
 	return addr;
@@ -1290,19 +1336,16 @@
 	TUint colour = iColour;
 	TLinAddr addr = iLinAddr+(colour<<KPageShift);
 	TPte* pPte = iPtePtr+colour;
-	TUint count = iCount;
-
-	while(count)
+
+	while(iCount)
 		{
 		*pPte = KPteUnallocatedEntry;
 		CacheMaintenance::SinglePteUpdated((TLinAddr)pPte);
 		InvalidateTLBForPage(addr|KKernelOsAsid);
 		addr += KPageSize;
 		++pPte;
-		--count;
+		--iCount;
 		}
-
-	iCount = 0;
 	}
 
 #ifdef __SMP__
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mmu.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mmu.h	Tue May 04 18:23:12 2010 +0100
@@ -84,7 +84,8 @@
 		Page is in an indeterminate state.
 
 		A page is placed into this state by Mmu::PagesAllocated when it is
-		allocated (ceases to be #EUnused). Once the page
+		allocated (ceases to be #EUnused). Once the page has been assigned to 
+		its new use its type will be updated.
 		*/
 		EUnknown,
 
@@ -218,7 +219,7 @@
 		{
 		/**
 		The memory object which owns this page.
-		Used for always set for #EManaged pages and can be set for #PhysAlloc pages.
+		Always set for #EManaged pages and can be set for #PhysAlloc pages.
 		*/
 		DMemoryObject* iOwner;
 
@@ -297,7 +298,7 @@
 	*/
 	FORCE_INLINE static SPageInfo* FromLink(SDblQueLink* aLink)
 		{
-		return (SPageInfo*)((TInt)aLink-_FOFF(SPageInfo,iLink));
+		return _LOFF(aLink, SPageInfo, iLink);
 		}
 
 	//
@@ -483,7 +484,7 @@
 		}
 
 	/**
-	Reutrns a pointer to the SPageInfo of the page that this page is shadowing.
+	Returns a pointer to the SPageInfo of the page that this page is shadowing.
 
 	@return	A pointer to the SPageInfo that this page is shadowing
 
@@ -570,7 +571,7 @@
 		}
 
 	/**
-	The the pages #iModifier value.
+	Set the page's #iModifier value.
 
 	#iModifier is cleared to zero whenever the usage or paging state of the page
 	changes. So if a thread sets this to a suitable unique value (e.g. the address
@@ -1433,7 +1434,7 @@
 	*/
 	FORCE_INLINE static SPageTableInfo* FromFreeLink(SDblQueLink* aLink)
 		{
-		return (SPageTableInfo*)((TInt)aLink-_FOFF(SPageTableInfo,iUnused));
+		return _LOFF(aLink, SPageTableInfo, iUnused);
 		}
 
 	/**
@@ -1710,9 +1711,9 @@
 	*/
 	static FORCE_INLINE void UnlockGuardStart()
 		{
-		#ifdef _DEBUG
-			++UnlockGuardNest;
-		#endif
+#ifdef _DEBUG
+		++UnlockGuardNest;
+#endif
 		}
 
 	/**
@@ -1721,18 +1722,18 @@
 
 	@see UnlockGuardStart
 
-	@return True if the MmuLock was released between a previous #UnlockGuardStart
+	@return EFalse if the MmuLock was released between a previous #UnlockGuardStart
 			and the call this function.
 	*/
 	static FORCE_INLINE TBool UnlockGuardEnd()
 		{
-		#ifdef _DEBUG
-			__NK_ASSERT_DEBUG(UnlockGuardNest);
-			--UnlockGuardNest;
-			return UnlockGuardFail==0;
-		#else
-			return true;
-		#endif
+#ifdef _DEBUG
+		__NK_ASSERT_DEBUG(UnlockGuardNest);
+		--UnlockGuardNest;
+		return UnlockGuardFail==0;
+#else
+		return ETrue;
+#endif
 		}
 
 private:
@@ -1742,10 +1743,10 @@
 	*/
 	static FORCE_INLINE void UnlockGuardCheck()
 		{
-		#ifdef _DEBUG
-			if(UnlockGuardNest)
-				UnlockGuardFail = true;
-		#endif
+#ifdef _DEBUG
+		if(UnlockGuardNest)
+			UnlockGuardFail = ETrue;
+#endif
 		}
 
 public:
@@ -1950,6 +1951,8 @@
 	void Init2FinalCommon();
 	void Init3();
 
+	void BTracePrime(TUint aCategory);
+
 	static void Panic(TPanic aPanic);
 
 	static TInt HandlePageFault(TLinAddr aPc, TLinAddr aFaultAddress, TUint aAccessPermissions, TAny* aExceptionInfo);
@@ -1971,6 +1974,7 @@
 	TInt ZoneAllocPhysicalRam(TUint* aZoneIdList, TUint aZoneIdCount, TInt aNumPages, TPhysAddr* aPageList);
 	TInt RamHalFunction(TInt aFunction, TAny* a1, TAny* a2);	
 	void ChangePageType(SPageInfo* aPageInfo, TZonePageType aOldPageType, TZonePageType aNewPageType);
+	TInt FreeRamZone(TUint aZoneId);
 
 	TInt AllocPhysicalRam(TPhysAddr* aPages, TUint aCount, TRamAllocFlags aFlags);
 	void FreePhysicalRam(TPhysAddr* aPages, TUint aCount);
@@ -1978,7 +1982,11 @@
 	void FreePhysicalRam(TPhysAddr aPhysAddr, TUint aCount);
 	TInt ClaimPhysicalRam(TPhysAddr aPhysAddr, TUint aCount, TRamAllocFlags aFlags);
 	void AllocatedPhysicalRam(TPhysAddr aPhysAddr, TUint aCount, TRamAllocFlags aFlags);
+private:
+	void SetAllocPhysRam(TPhysAddr aPhysAddr, TUint aCount);
+	void SetAllocPhysRam(TPhysAddr* aPageList, TUint aNumPages);
 
+public:
 	TLinAddr MapTemp(TPhysAddr aPage, TUint aColour, TUint aSlot=0);
 	void UnmapTemp(TUint aSlot=0);
 	void RemoveAliasesForPageTable(TPhysAddr aPageTable);
@@ -2131,8 +2139,11 @@
 	TUint iRamAllocInitialFreePages;
 
 	friend class RamAllocLock;
+
+#ifdef FMM_VERIFY_RAM
 private:
 	void VerifyRam();
+#endif
 	};
 
 /**
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mpagearray.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpagearray.cpp	Tue May 04 18:23:12 2010 +0100
@@ -258,7 +258,7 @@
 	}
 
 
-void RPageArray::TIter::Add(TUint aCount, TPhysAddr* aPages)
+void RPageArray::TIter::Add(TUint aCount, const TPhysAddr* aPages)
 	{
 	// MmuLock NOT required because...
 	// 1. AddStart has ensured all segments are allocated and locked (so they can't be deleted)
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mpagearray.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpagearray.h	Tue May 04 18:23:12 2010 +0100
@@ -543,7 +543,7 @@
 		@param aCount		The number of pages to add.
 		@param aPages		Pointer to list of \a aCount physical page addresses to add.
 		*/
-		void Add(TUint aCount, TPhysAddr* aPages);
+		void Add(TUint aCount, const TPhysAddr* aPages);
 
 		/**
 		Add contiguous pages to the array, setting each entry state as ECommitted.
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mpagecleaner.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpagecleaner.cpp	Tue May 04 18:23:12 2010 +0100
@@ -1,7 +1,7 @@
-// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+// 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 "Eclipse Public License v1.0"
+// 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".
 //
@@ -30,8 +30,8 @@
 
 const TInt KThreadPriority = 25;
 
-// The length of time the paging device is idle before we decide to use it for cleaning dirty
-// pages, in milliseconds.
+/// The length of time the paging device is idle before we decide to use it for cleaning dirty
+/// pages, in milliseconds.
 const TInt KIdleDelayInMillis = 2;
 
 class DPageCleaner
@@ -63,13 +63,13 @@
 
 	// All state below is accessed with the MmuLock held.
 
-	// Whether the paging device is currently idle.
+	/// Whether the paging device is currently idle.
 	TBool iPagingDeviceIdle;
 
-	// Whether the paging device has been idle for longer than the wait period.
+	/// Whether the paging device has been idle for longer than the wait period.
 	TBool iIdleForAWhile;
 	
-	// Whether the page cleaner is currently running.
+	/// Whether the page cleaner is currently running.
 	TBool iCleaningInProgress;	
 	};
 
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mpagecleaner.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpagecleaner.h	Tue May 04 18:23:12 2010 +0100
@@ -1,7 +1,7 @@
-// Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+// 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 "Eclipse Public License v1.0"
+// 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".
 //
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mpager.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpager.cpp	Tue May 04 18:23:12 2010 +0100
@@ -92,7 +92,7 @@
 
 #elif defined(__CPU_X86)
 
-/*	Need at least 6 mapped pages to guarantee to be able to execute all ARM instructions,
+/*	Need at least 6 mapped pages to guarantee to be able to execute all X86 instructions,
 	plus enough pages for 6 page tables to map those pages, plus enough pages for the
 	page table info structures of those page tables.
 	(Worst case is (?) a MOV [X],[Y] instruction with instruction, 'X' and 'Y' all
@@ -200,8 +200,7 @@
 		TInt r = m.AllocRam(&pagePhys, 1, 
 							(Mmu::TRamAllocFlags)(EMemAttNormalCached|Mmu::EAllocNoWipe|Mmu::EAllocNoPagerReclaim), 
 							EPageDiscard);
-		if(r!=KErrNone)
-			__NK_ASSERT_ALWAYS(0);
+		__NK_ASSERT_ALWAYS(r == KErrNone);
 		MmuLock::Lock();
 		AddAsFreePage(SPageInfo::FromPhysAddr(pagePhys));
 		MmuLock::Unlock();
@@ -214,50 +213,50 @@
 
 
 #ifdef _DEBUG
-TBool DPager::CheckLists()
+#ifdef FMM_PAGER_CHECK_LISTS
+TBool CheckList(SDblQueLink* aHead, TUint aCount)
 	{
-#if 0
-	__NK_ASSERT_DEBUG(MmuLock::IsHeld());
-	SDblQueLink* head = &iOldList.iA;
-	TInt n = iOldCount;
-	SDblQueLink* link = head;
-	while(n--)
+	SDblQueLink* link = aHead;
+	while(aCount--)
 		{
 		link = link->iNext;
-		if(link==head)
-			return false;
+		if(link == aHead)
+			return EFalse;
 		}
 	link = link->iNext;
-	if(link!=head)
-		return false;
-
-	head = &iYoungList.iA;
-	n = iYoungCount;
-	link = head;
-	while(n--)
-		{
-		link = link->iNext;
-		if(link==head)
-			return false;
-		}
-	link = link->iNext;
-	if(link!=head)
-		return false;
-
-//	TRACEP(("DP: y=%d o=%d f=%d",iYoungCount,iOldCount,iNumberOfFreePages));
-#endif
-//	TraceCounts();
+	if(link != aHead)
+		return EFalse;
+	return ETrue;
+	}
+#endif // #ifdef FMM_PAGER_CHECK_LISTS
+
+TBool DPager::CheckLists()
+	{
+#ifdef FMM_PAGER_CHECK_LISTS
+	__NK_ASSERT_DEBUG(MmuLock::IsHeld());
+	if (!CheckList(&iOldList.iA, iOldCount))
+		return EFalse;
+	if (!CheckList(&iYoungList.iA, iYoungCount))
+		return EFalse;
+	if (!CheckList(&iOldestCleanList.iA, iOldestCleanCount))
+		return EFalse;
+	if (!CheckList(&iOldestDirtyList.iA, iOldestDirtyCount))
+		return EFalse;
+	TRACEP(("DP: y=%d o=%d oc=%d od=%d f=%d", iYoungCount, iOldCount, 
+			iOldestCleanCount, iOldestDirtyCount, iNumberOfFreePages));
+	TraceCounts();
+#endif // #ifdef FMM_PAGER_CHECK_LISTS
 	return true;
 	}
 
 void DPager::TraceCounts()
 	{
-	TRACEP(("DP: y=%d o=%d f=%d min=%d max=%d ml=%d res=%d",
-		iYoungCount,iOldCount,iNumberOfFreePages,iMinimumPageCount,
-		iMaximumPageCount,iMinimumPageLimit,iReservePageCount));
+	TRACEP(("DP: y=%d o=%d oc=%d od=%d f=%d min=%d max=%d ml=%d res=%d",
+		iYoungCount, iOldCount, iOldestCleanCount, iOldestDirtyCount, 
+		iNumberOfFreePages, iMinimumPageCount, iMaximumPageCount,
+		iMinimumPageLimit, iReservePageCount));
 	}
-
-#endif
+#endif //#ifdef _DEBUG
 
 
 TBool DPager::HaveTooManyPages()
@@ -1984,7 +1983,7 @@
 
 	MmuLock::Lock();
 
-	__NK_ASSERT_ALWAYS(iYoungOldRatio!=0);
+	__NK_ASSERT_ALWAYS(iYoungOldRatio);
 
 	// Make sure aMinimumPageCount is not less than absolute minimum we can cope with...
 	iMinimumPageLimit = iMinYoungPages * (1 + iYoungOldRatio) / iYoungOldRatio
@@ -1997,9 +1996,8 @@
 		aMaximumPageCount=aMinimumPageCount;
 
 	// Increase iMaximumPageCount?
-	TInt extra = aMaximumPageCount-iMaximumPageCount;
-	if(extra>0)
-		iMaximumPageCount += extra;
+	if(aMaximumPageCount > iMaximumPageCount)
+		iMaximumPageCount = aMaximumPageCount;
 
 	// Reduce iMinimumPageCount?
 	TInt spare = iMinimumPageCount-aMinimumPageCount;
@@ -2837,15 +2835,15 @@
 EXPORT_C TInt DDemandPagingLock::Lock(DThread* aThread, TLinAddr aStart, TInt aSize)
 	{
 //	TRACEP(("DDemandPagingLock[0x%08x]::Lock(0x%08x,0x%08x,0x%08x)",this,aThread,aStart,aSize));
-	if(iLockedPageCount)
-		__NK_ASSERT_ALWAYS(0); // lock already used
+	__NK_ASSERT_ALWAYS(!iLockedPageCount); // lock already used
 
 	// calculate the number of pages that need to be locked...
 	TUint mask=KPageMask;
 	TUint offset=aStart&mask;
 	TInt numPages = (aSize+offset+mask)>>KPageShift;
-	if(numPages>iMaxPageCount)
-		__NK_ASSERT_ALWAYS(0);
+
+	// Should never be asked to lock more pages than are allocated to this object.
+	__NK_ASSERT_ALWAYS(numPages <= iMaxPageCount);
 
 	NKern::ThreadEnterCS();
 
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mpager.h	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpager.h	Tue May 04 18:23:12 2010 +0100
@@ -57,6 +57,11 @@
 		MmuLock::Unlock();
 		return ret;
 		}
+
+	FORCE_INLINE TUint MinimumPageCount()
+		{
+		return iMinimumPageCount;
+		}
 	
 	FORCE_INLINE void SetWritable(SPageInfo& aPageInfo)
 		{
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mpdalloc.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mpdalloc.cpp	Tue May 04 18:23:12 2010 +0100
@@ -134,7 +134,14 @@
 	RamAllocLock::Lock();
 	TInt r = m.AllocContiguousRam(pdPhys, KLocalPdPages, KLocalPdShift-KPageShift, iPageDirectoryMemory->RamAllocFlags());
 	if(r==KErrNone)
+		{
 		AssignPages(offset>>KPageShift,KLocalPdPages,pdPhys);
+
+#ifdef BTRACE_KERNEL_MEMORY
+		BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscAlloc, KLocalPdPages << KPageShift);
+		Epoc::KernelMiscPages += KLocalPdPages;
+#endif
+		}
 	RamAllocLock::Unlock();
 
 	if(r==KErrNone)
@@ -147,6 +154,11 @@
 			{
 			RamAllocLock::Lock();
 			m.FreeContiguousRam(pdPhys,KLocalPdPages);
+
+#ifdef BTRACE_KERNEL_MEMORY
+			BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscFree, KLocalPdPages << KPageShift);
+			Epoc::KernelMiscPages -= KLocalPdPages;
+#endif
 			RamAllocLock::Unlock();
 			}
 		else
@@ -206,6 +218,11 @@
 	Mmu& m = TheMmu;
 	// Page directories are fixed.
 	m.FreeRam(pages, KLocalPdPages, EPageFixed);
+
+#ifdef BTRACE_KERNEL_MEMORY
+	BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscFree, KLocalPdPages << KPageShift);
+	Epoc::KernelMiscPages -= KLocalPdPages;
+#endif
 	RamAllocLock::Unlock();
 	}
 
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mptalloc.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mptalloc.cpp	Tue May 04 18:23:12 2010 +0100
@@ -177,6 +177,14 @@
 	else
 		{// Allocate fixed paged as page tables aren't movable.
 		r = TheMmu.AllocRam(&pagePhys, 1, aMemory->RamAllocFlags(), EPageFixed);
+
+#ifdef BTRACE_KERNEL_MEMORY
+		if (r == KErrNone)
+			{
+			BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscAlloc, KPageSize);
+			++Epoc::KernelMiscPages;
+			}
+#endif
 		}
 	RamAllocLock::Unlock();
 
@@ -241,7 +249,14 @@
 		if(aDemandPaged)
 			ThePager.PageInFreePages(&pagePhys,1);
 		else
+			{
 			TheMmu.FreeRam(&pagePhys, 1, EPageFixed);
+
+#ifdef BTRACE_KERNEL_MEMORY
+			BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscFree, KPageSize);
+			--Epoc::KernelMiscPages;
+#endif
+			}
 		r = 1;
 		}
 
@@ -362,11 +377,8 @@
 	{
 	iReserveCount = aReserveCount;
 	iDemandPaged = aDemandPaged;
-	while(iFreeCount<aReserveCount)
-		if(!aAllocator->AllocReserve(*this))
-			{
-			__NK_ASSERT_ALWAYS(0);
-			}
+	while(iFreeCount < aReserveCount)
+		__NK_ASSERT_ALWAYS(aAllocator->AllocReserve(*this));
 	}
 
 
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mrom.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mrom.cpp	Tue May 04 18:23:12 2010 +0100
@@ -969,6 +969,11 @@
 		MmuLock::Lock();
 		SPageInfo::FromPhysAddr(iNewPage)->SetShadow(aIndex,aMemory->PageInfoFlags());
 		MmuLock::Unlock();
+
+#ifdef BTRACE_KERNEL_MEMORY
+		BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscAlloc, KPageSize);
+		++Epoc::KernelMiscPages;
+#endif
 		}
 
 	RamAllocLock::Unlock();
@@ -992,6 +997,11 @@
 		{
 		RamAllocLock::Lock();
 		TheMmu.FreeRam(&iNewPage, 1, EPageFixed);
+
+#ifdef BTRACE_KERNEL_MEMORY
+		BTrace4(BTrace::EKernelMemory, BTrace::EKernelMemoryMiscFree, KPageSize);
+		--Epoc::KernelMiscPages;
+#endif
 		RamAllocLock::Unlock();
 		}
 	if(IsAttached())
--- a/kernel/eka/memmodel/epoc/flexible/mmu/mvalloc.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/flexible/mmu/mvalloc.cpp	Tue May 04 18:23:12 2010 +0100
@@ -688,7 +688,7 @@
 
 RVirtualAllocSlabSet* RVirtualAllocSlabSet::New(RVirtualAllocator* aAllocator, TUint aNumSlabTypes, DMutex*& aWriteLock)
 	{
-	TUint size = sizeof(RVirtualAllocSlabSet)+sizeof(((RVirtualAllocSlabSet*)0x100)->iSlabs)*(aNumSlabTypes-1);
+	TUint size = sizeof(RVirtualAllocSlabSet) + sizeof(SDblQue) * (aNumSlabTypes - 1);
 	RVirtualAllocSlabSet* set = (RVirtualAllocSlabSet*)Kern::AllocZ(size);
 	if(set)
 		new (set) RVirtualAllocSlabSet(aAllocator,aNumSlabTypes,aWriteLock);
@@ -764,8 +764,9 @@
 		if(!slab)
 			return KErrNoMemory;
 		TLinAddr addr = slab->Alloc(aSizeShift);
-		if(!addr)
-			return KErrNoMemory;
+		// Shouldn't ever fail as we've just allocated an empty slab and we can't 
+		// attempt to allocate more than a whole slab.
+		__NK_ASSERT_DEBUG(addr);
 		aAddr = addr;
 		return KErrNone;
 		}
@@ -830,8 +831,8 @@
 RVirtualAllocator::~RVirtualAllocator()
 	{
 	__NK_ASSERT_DEBUG(iAllocator==0 || iAllocator->iAvail==iAllocator->iSize); // should be empty
-	Kern::Free(iAllocator);
-	Kern::Free(iSlabSet);
+	delete iAllocator;
+	delete iSlabSet;
 	}
 
 
--- a/kernel/eka/memmodel/epoc/mmubase/defragbase.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/mmubase/defragbase.cpp	Tue May 04 18:23:12 2010 +0100
@@ -405,7 +405,7 @@
 		BTrace4(BTrace::ERamAllocator, BTrace::ERamAllocClaimZone, zone->iId);
 #endif
 
-#ifdef BTRACE_KERNEL_MEMORY
+#if defined(BTRACE_KERNEL_MEMORY) && !defined(__MEMMODEL_FLEXIBLE__)
 		TUint size = zone->iPhysPages << M::PageShift();
 		BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysAlloc, size, zone->iPhysBase);
 		Epoc::DriverAllocdPhysRam += size;
--- a/kernel/eka/memmodel/epoc/mmubase/mmubase.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/mmubase/mmubase.cpp	Tue May 04 18:23:12 2010 +0100
@@ -651,6 +651,17 @@
 	}
 
 
+TInt MmuBase::FreeRamZone(TUint aZoneId, TPhysAddr& aZoneBase, TUint& aZoneBytes)
+	{
+	TUint zonePages;
+	TInt r = iRamPageAllocator->GetZoneAddress(aZoneId, aZoneBase, zonePages);
+	if (r != KErrNone)
+		return r;
+	aZoneBytes = zonePages << KPageShift;
+	return MmuBase::FreePhysicalRam(aZoneBase, aZoneBytes);
+	}
+
+
 TInt MmuBase::ClaimPhysicalRam(TPhysAddr aPhysAddr, TInt aSize)
 	{
 	__KTRACE_OPT(KMMU,Kern::Printf("Mmu::ClaimPhysicalRam(%08x,%x)",aPhysAddr,aSize));
@@ -1263,14 +1274,14 @@
 #endif
 
 #ifdef BTRACE_RAM_ALLOCATOR
-	// Must check for -1 as that is the default value of aCategroy for
+	// Must check for -1 as that is the default value of aCategory for
 	// BTrace::Prime() which is intended to prime all categories that are 
 	// currently enabled via a single invocation of BTrace::Prime().
 	if(aCategory==BTrace::ERamAllocator || (TInt)aCategory == -1)
 		{
 		NKern::ThreadEnterCS();
 		Mmu::Wait();
-		Mmu::Get().iRamPageAllocator->SendInitialBtraceLogs();
+		Mmu::Get().iRamPageAllocator->DoBTracePrime();
 		Mmu::Signal();
 		NKern::ThreadLeaveCS();
 		}
@@ -2051,6 +2062,45 @@
 
 
 /**
+Free a RAM zone which was previously allocated by one of these methods:
+Epoc::AllocPhysicalRam(), Epoc::ZoneAllocPhysicalRam() or 
+TRamDefragRequest::ClaimRamZone().
+
+All of the pages in the RAM zone must be allocated and only via one of the methods 
+listed above, otherwise a system panic will occur.
+
+@param	aZoneId			The ID of the RAM zone to free.
+@return	KErrNone 		If the operation was successful.
+		KErrArgument 	If a RAM zone with ID aZoneId was not found.
+
+@pre Calling thread must be in a critical section.
+@pre Interrupts must be enabled.
+@pre Kernel must be unlocked.
+@pre No fast mutex can be held.
+@pre Call in a thread context.
+@pre Can be used in a device driver.
+*/
+EXPORT_C TInt Epoc::FreeRamZone(TUint aZoneId)
+	{
+	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL,"Epoc::FreeRamZone");
+	MmuBase& m = *MmuBase::TheMmu;
+	MmuBase::Wait();
+	TPhysAddr zoneBase;
+	TUint zoneBytes;
+	TInt r = m.FreeRamZone(aZoneId, zoneBase, zoneBytes);
+#ifdef BTRACE_KERNEL_MEMORY
+	if (r == KErrNone)
+		{
+		BTrace8(BTrace::EKernelMemory, BTrace::EKernelMemoryDrvPhysFree, zoneBytes, zoneBase);
+		Epoc::DriverAllocdPhysRam -= zoneBytes;
+		}
+#endif
+	MmuBase::Signal();
+	return r;
+	}
+
+
+/**
 Translate a virtual address to the corresponding physical address.
 
 @param	aLinAddr	The virtual address to be translated.
--- a/kernel/eka/memmodel/epoc/mmubase/ramalloc.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/memmodel/epoc/mmubase/ramalloc.cpp	Tue May 04 18:23:12 2010 +0100
@@ -2852,7 +2852,7 @@
 It outputs the zone configuration and the base addresses of any contiguous block
 of allocated pages.
 */
-void DRamAllocator::SendInitialBtraceLogs(void)
+void DRamAllocator::DoBTracePrime(void)
 	{
 	M::RamAllocIsLocked();
 	CHECK_PRECONDITIONS(MASK_THREAD_CRITICAL, "DRamAllocator::SendInitialBtraceLogs");
--- a/kernel/eka/release.txt	Tue May 04 16:57:20 2010 +0100
+++ b/kernel/eka/release.txt	Tue May 04 18:23:12 2010 +0100
@@ -1,3 +1,155 @@
+Version 2.00.3053
+=================
+(Made by vfebvre 26/03/2010)
+
+1.	jimmzhou
+	1.	ou1cimx1#320634 [kernelmcl]Phone Crash when USB MobileTV device CU-14A is connected
+
+2.	kmetherm
+	1.	REQ 417-57581 RVCT 4 compatible software codebase (SSS)
+		PackageReleaseID=476546 FeaturePlanID=444184
+
+
+Version 2.00.3052
+=================
+(Made by vfebvre 25/03/2010)
+
+1.	gavguo
+	1.	REQ:417-57581:RVCT 4 compatible software codebase
+		PackageReleaseID=462344 FeaturePlanID=444184
+
+
+Version 2.00.3051
+=================
+(Made by vfebvre 25/03/2010)
+
+1.	lanerobe
+	1.	PDEF145143 KHS Documentation is not contributed to the Symbian Foundation
+
+
+Version 2.00.3050
+=================
+(Made by vfebvre 23/03/2010)
+
+1.	josezhou
+	1.	ou1cimx1#312908 : RUsbHubDriver interface can only be called by FDF, but multiple clients might have conflict requests to the interfaces 
+
+2.	lanerobe
+	1.	DEF145040 E32TEST T_THREAD test failure investigation
+
+
+Version 2.00.3049
+=================
+(Made by vfebvre 22/03/2010)
+
+1.	lanerobe
+	1.	DEF145041 E32TEST T_TIMER test failure investigation
+
+
+Version 2.00.3048
+=================
+(Made by vfebvre 22/03/2010)
+
+1.	lanerobe
+	1.	DEF145039 E32TEST T_SDRIVERS test failure investigation
+	2.	PDEF144928 Symbian Foundation build error due to missing usb components
+
+
+Version 2.00.3047
+=================
+(Made by vfebvre 19/03/2010)
+
+1.	jimmzhou
+	1.	ou1cimx1#310882: BELS-7YXDRY RDevUsbcClient::ReadUntilShort complete unexpected
+
+2.	lanerobe
+	1.	DEF144874 Intermittent E32TEST T_MSTIM test failures on the H4 (line 371)
+
+3.	fagortz
+	1.	DEF144667 WDP: t_medch crashes the system if a page out happens
+
+
+Version 2.00.3046
+=================
+(Made by vfebvre 18/03/2010)
+
+1.	lanerobe
+	1.	DEF145036 T_CONTEXT test failure investigation 
+
+2.	ferporta
+	1.	DEF145026 Remove SCM memory model dependency
+	2.	DEF144875 E32TEST T_RMDEBUG2_OEM failing on UREL SMP configurations
+
+3.	genwei
+	1.	ou1cimx1#301181: The device under test exits the high-speed host electrical test mode without operator action
+
+
+Version 2.00.3045
+=================
+(Made by vfebvre 17/03/2010)
+
+1.	lanerobe
+	1.	MINOR_CHANGE Fix copyright notices on power management code
+
+2.	martai
+	1.	PDEF145027 FMM - BTrace messages EKernelMemory are missing from the flexible memory model
+
+
+Version 2.00.3044
+=================
+(Made by vfebvre 15/03/2010)
+
+1.	jimmzhou
+	1.	CR ou1cimx1#300759: kernel_mcl: A malfunctioning peripheral still cannot be reported to the UI, breaking the "no silent failures" policy of USB OTG
+		TKEA-836MEU
+
+2.	martai
+	1.	PDEF144923 FMM - The virtual address space manager allocates incorrect size heap cells
+	2.	DEF144936 It is not possible to free a RAM zone via its ID
+
+
+Version 2.00.3043
+=================
+(Made by vfebvre 12/03/2010)
+
+1.	seolney
+	1.	DEF144850 E32TEST T_DMASIM fails on x86pc (level 012) 
+
+2.	necliffo
+	1.	PDEF144977 EMOL-83CGYT: SPB 10.1: Device freeze when corrupted memory card is used.
+
+3.	mmaksymi
+	1.	DEF144804 OST Kernel Code Doesn't Comply with Header Relocation Rules
+
+
+Version 2.00.3042
+=================
+(Made by vfebvre 11/03/2010)
+
+1.	jimmzhou
+	1.	DEF144836: for submission to MCL: TSW defect TSW YXIO-82ZBP
+
+2.	gcochran
+	1.	PDEF144935 MMEG-83F9A8 - Misleading error message in ExecHandler::ThreadRequestSignal
+
+3.	tommarti
+	1.	DEF144920 Wrong license in some FMM source files
+
+
+Version 2.00.3041
+=================
+(Made by vfebvre 10/03/2010)
+
+1.	gayarama
+	1.	PDEF144756 t_tbus_datapaging test fails on Vasco/TB9.2 due to fileserver api issue
+
+2.	martai
+	1.	DEF144781: MMEG-8369AQ RThread::Create documentation doesn't mention the minimum stack size 
+
+3.	davegord
+	1.	DEF144743 Kernel Message Pool corrupted by delayed DeadClientCleanup 
+
+
 Version 2.00.3040
 =================
 (Made by vfebvre 09/03/2010)
Binary file kernelhwsrv_info/doc_pub/base_how_to_64bit_file_server_client_porting_guide.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_64bit_file_server_file_system_plugin_porting_guide.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_align_partitions_to_media_block_boundaries_for_optimised_performance.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_armv7_cache_and_access_remapping_-_design.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_btrace.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_configure_platform_security_settings.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_crash_logging.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_debug_nonxip_problems.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_estart.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_file_caching.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_handle_sharing.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_impacts_of_demand_paging_on_kernel-side_code.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_ipc.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_message_queues.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_migrate_device_drivers_to_paging_environment.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_migrate_media_drivers_to_support_demand_paging.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_migrate_to_client-server_v2_apis.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_mmc_direct_physical_addressing.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_mmc_double_buffering.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_persisting_a_custom_restart_reason.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_port_emmc_controller.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_port_sdio_controller_supplement.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_publish_and_subscribe.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_share_file_handles.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_usb_client_porting_and_test.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_usb_mass_storage_app.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_usb_mass_storage_double_buffering.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_use_cfileman_test_framework.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_use_dma_for_sdio_data_transfers.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_use_t_fatcharsetconv_framework.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_how_to_vfp_support.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_migrating_device_drivers_dfc_q.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_migrating_media_drivers_dma.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_smp_driver_migration_guide.doc has changed
Binary file kernelhwsrv_info/doc_pub/base_smp_user_side_migration_guide.doc has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kernelhwsrv_info/doc_pub/kernelhwsrv_doc_pub.mrp	Tue May 04 18:23:12 2010 +0100
@@ -0,0 +1,26 @@
+#
+# Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+# All rights reserved.
+# This component and the accompanying materials are made available
+# under the terms of "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: 
+#
+# 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 
+
--- a/kerneltest/e32test/debug/t_context.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/debug/t_context.cpp	Tue May 04 18:23:12 2010 +0100
@@ -408,6 +408,7 @@
 	// run again only after it is blocked on its request semaphore.
 	t.SetPriority(EPriorityMore);
 	t.Resume();
+	User::After(500000);
 
 	if (aCallback != ENoCallback)
 		{
--- a/kerneltest/e32test/defrag/d_ramdefrag.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/defrag/d_ramdefrag.cpp	Tue May 04 18:23:12 2010 +0100
@@ -72,6 +72,7 @@
 	TInt ZoneAllocToMany2(TInt aZoneIndex, TInt aNumPages);
 	TInt AllocContiguous(TUint aNumBytes);
 	TInt FreeZone(TInt aNumPages);
+	TInt FreeZoneId(TUint aZoneId);
 	TInt FreeFromAllZones();
 	TInt FreeFromAddr(TInt aNumPages, TUint32 aAddr);
 	TInt PageCount(TUint aId, STestUserSidePageCount* aPageData);
@@ -389,6 +390,10 @@
 			retVal = DRamDefragFuncTestChannel::FreeZone((TInt)a1);
 			break;
 
+		case RRamDefragFuncTestLdd::EFreeZoneId:
+			retVal = DRamDefragFuncTestChannel::FreeZoneId((TUint)a1);
+			break;
+
 		case RRamDefragFuncTestLdd::EFreeFromAllZones:
 			retVal = DRamDefragFuncTestChannel::FreeFromAllZones();	
 			break;
@@ -1512,6 +1517,30 @@
 	}
 
 //
+// FreeZoneId
+//
+// Call Epoc::FreeRamZone()
+//
+TInt DRamDefragFuncTestChannel::FreeZoneId(TUint aZoneId)
+	{
+	NKern::ThreadEnterCS();
+	
+	TInt r = Epoc::FreeRamZone(aZoneId);
+	if (r == KErrNone)
+		{
+		if (iContigAddr == KPhysAddrInvalid)
+			{
+			Kern::Printf("Error some how freed a RAM zone that wasn't previously claimed");
+			NKern::ThreadLeaveCS();
+			return KErrGeneral;
+			}
+		iContigAddr = KPhysAddrInvalid;
+		}
+	NKern::ThreadLeaveCS();
+	return r;
+	}
+
+//
 // FreeFromAllZones
 //
 // Call the overloaded Epoc::FreePhysicalRam function
--- a/kerneltest/e32test/defrag/t_ramdefrag.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/defrag/t_ramdefrag.cpp	Tue May 04 18:23:12 2010 +0100
@@ -7073,16 +7073,20 @@
 //! @SYMPREQ					PREQ308
 //! @SYMTestPriority			High
 //! @SYMTestActions				
-//! 	1.	Allocate fixed pages and call function to free all fixed pages allocated.  
+//! 	1.	Allocate fixed pages and call function to free all fixed pages allocated.
+//!		2.	Claim a RAM zone and then free it via Epoc::FreeRamZone().
+//!		3.	Invoke Epoc::FreeRamZone() with an invalid RAM zone ID.
 //! 
 //! @SYMTestExpectedResults
 //! 	1.	KErrNone
+//!		2.	KErrNone
+//!		3.	KErrArgument
 //---------------------------------------------------------------------------------------------------------------------
 TInt TestFreeZone()
 	{
 	TInt r = 0;
 	TUint zoneID = 0;
-	test.Start(_L("Test1: Free allocated pages"));	
+	test.Start(_L("Test1: Freeing allocated pages"));	
 	TestStart();	
 	
 	TInt pages = 50;
@@ -7128,7 +7132,58 @@
 			}
 		}
 	TestEnd();
-
+	test.End();
+
+	test.Start(_L("Test2: Epoc::FreeRamZone() on a claimed RAM zone"));
+	TestStart();
+	GetAllPageInfo();
+	TUint zoneIndex = 0;
+	while (zoneIndex < gZoneCount)
+		{
+		if (gZoneUtilArray[zoneIndex].iFreePages == gZoneUtilArray[zoneIndex].iPhysPages)
+			break;
+		zoneIndex++;
+		}
+	if (zoneIndex >= gZoneCount)
+		{
+		test.Printf(_L("Cannot find zone to perform test, Skipping test step...\n"));
+		goto Test2End;
+		}
+	zoneID = gZoneConfigArray[zoneIndex].iZoneId;
+	r = Ldd.CallDefrag(DEFRAG_TYPE_CLAIM, DEFRAG_VER_SYNC, zoneID);
+	if (r != KErrNone)
+		{
+		test.Printf(_L("Fail: r = %d, expected = %d\n"), r, KErrNone);
+		TEST_FAIL;
+		}
+	GetAllPageInfo();
+	if (gZoneUtilArray[zoneIndex].iPhysPages != gZoneUtilArray[zoneIndex].iAllocFixed)
+		{
+		test.Printf(_L("Fail: RAM zone ID %d not claimed successfully"), zoneID);
+		TEST_FAIL;
+		}
+	r = Ldd.FreeZoneId(zoneID);
+	GetAllPageInfo();
+	if (r != KErrNone ||
+		gZoneUtilArray[zoneIndex].iPhysPages != gZoneUtilArray[zoneIndex].iFreePages)
+		{
+		test.Printf(_L("Fail: RAM zone ID %d not freed successfully r=%d"), zoneID, r);
+		TEST_FAIL;
+		}
+Test2End:
+	TestEnd();
+	test.End();
+
+	test.Start(_L("Test2: Epoc::FreeRamZone() on an invalid RAM zone"));
+	TestStart();
+	r = Ldd.FreeZoneId(KInvalidZoneID);
+	if (r != KErrArgument)
+		{
+		test.Printf(_L("Fail: Error RAM zone ID %d r=%d"), KInvalidZoneID, r);
+		TEST_FAIL;
+		}
+	
+	TestEnd();
 	test.End();
 	return KErrNone;
 	}
--- a/kerneltest/e32test/defrag/t_ramdefrag.h	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/defrag/t_ramdefrag.h	Tue May 04 18:23:12 2010 +0100
@@ -139,6 +139,7 @@
 		EZoneAllocToMany2,
 		EAllocContiguous,
 		EFreeZone,
+		EFreeZoneId,
 		EFreeFromAllZones,
 		EFreeFromAddr, 
 		ECheckCancel,
@@ -224,6 +225,8 @@
 	inline TInt FreeFromAllZones()
 		{ return DoControl(EFreeFromAllZones,(TAny*)NULL, (TAny*)NULL); }
 
+	inline TInt FreeZoneId(TUint aZoneId)
+		{ return DoControl(EFreeZoneId, (TAny*)aZoneId); }
 
 	inline TInt CheckCancel(TInt aDefragType, TUint aID = 0)
 		{ 
--- a/kerneltest/e32test/demandpaging/t_tbus_datapaging.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/demandpaging/t_tbus_datapaging.cpp	Tue May 04 18:23:12 2010 +0100
@@ -79,6 +79,7 @@
 
 LOCAL_D RFs TheFs;
 TInt gFsDriveNumber	= -1;
+TBool gMediaIsRam = EFalse;
 	
 RTest test(_L("T_TBUS_DATAPAGING"));
 _LIT(KChunkName, "t_datapaging chunk");
@@ -698,6 +699,9 @@
 			continue;
 
 		TPtrC mediaType = GetMediaType(di.iType);
+		if (di.iType == EMediaRam)
+			gMediaIsRam = ETrue;
+
 		test.Printf(_L("Drive %C Type %S DriveAtt 0x%x MediaAtt 0x%x FileSysId %S SerialNum %S\n"), 
 			'A' + n, &mediaType, di.iDriveAtt, di.iMediaAtt, &fsName, &GetSerialNumber(serialNum));
 
@@ -794,11 +798,13 @@
 	__DECLARE_VAR_IN_CHUNK(TBusLocalDrive, &drive)
 	TInt driveSize = TestDriveConnectAndCaps(drive, fatDriveNumber);
 	
-	TestDriveSizeRelatedMethods(drive, 0x00001000, driveSize);
+	if (!gMediaIsRam) // If media is RAM then the tests are invalid
+		TestDriveSizeRelatedMethods(drive, 0x00001000, driveSize);
 	
 	TestWriteReadRelatedMethods(drive);
 	
-	TestFormatRelatedMethods(drive, driveSize);
+	if (!gMediaIsRam)
+		TestFormatRelatedMethods(drive, driveSize);
 	
 	if(callPasswordRelated)
 		{
--- a/kerneltest/e32test/dma/t_dma.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/dma/t_dma.cpp	Tue May 04 18:23:12 2010 +0100
@@ -348,7 +348,7 @@
 	TBuf<16> name;
 	name = _L("TESTER-");
 	name.AppendNum(aIdx);
-	test(iThread.Create(name, ThreadFunction, 0x1000, NULL, this) == KErrNone);
+	test(iThread.Create(name, ThreadFunction, 0x2000, NULL, this) == KErrNone);
 	iThread.SetPriority(EPriorityLess);
 	iThread.Logon(iStatus);
 	SetActive();
--- a/kerneltest/e32test/group/d_kerncorestats.mmp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/group/d_kerncorestats.mmp	Tue May 04 18:23:12 2010 +0100
@@ -1,7 +1,7 @@
-// Copyright (c) 2006-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 "Eclipse Public License v1.0"
+// 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".
 //
--- a/kerneltest/e32test/group/t_kerncorestats.mmp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/group/t_kerncorestats.mmp	Tue May 04 18:23:12 2010 +0100
@@ -1,7 +1,7 @@
-// Copyright (c) 2005-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 "Eclipse Public License v1.0"
+// 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".
 //
--- a/kerneltest/e32test/misc/d_testkerncorestats.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/misc/d_testkerncorestats.cpp	Tue May 04 18:23:12 2010 +0100
@@ -1,7 +1,7 @@
-// Copyright (c) 2007-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 "Eclipse Public License v1.0"
+// 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".
 //
--- a/kerneltest/e32test/misc/d_testkerncorestats.h	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/misc/d_testkerncorestats.h	Tue May 04 18:23:12 2010 +0100
@@ -1,7 +1,7 @@
-// Copyright (c) 2007-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 "Eclipse Public License v1.0"
+// 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".
 //
--- a/kerneltest/e32test/misc/t_kerncorestats.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/misc/t_kerncorestats.cpp	Tue May 04 18:23:12 2010 +0100
@@ -1,7 +1,7 @@
-// Copyright (c) 2007-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 "Eclipse Public License v1.0"
+// 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".
 //
--- a/kerneltest/e32test/pccd/t_medch.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/pccd/t_medch.cpp	Tue May 04 18:23:12 2010 +0100
@@ -50,6 +50,9 @@
 
 const TInt KPowerUpTimeOut = 5000000; // Give the card 5 seconds to power up
 
+const TUint KDriveAttMask = KDriveAttLocal | KDriveAttRom | KDriveAttRemote;
+const TUint KMediaAttMask = KMediaAttVariableSize | KMediaAttDualDensity | KMediaAttLockable | KMediaAttLocked | KMediaAttHasPassword  | KMediaAttReadWhileWrite;
+
 LOCAL_D	RTest test(_L("Media change test"));
 
 LOCAL_D	TBusLocalDrive TheDrive;
@@ -57,6 +60,129 @@
 LOCAL_D TRequestStatus TheMediaStatus;
 LOCAL_D TBool TheChangedFlag;
 
+LOCAL_C TInt FindDataPagingDrive()
+/** 
+Find the drive containing the swap partition.
+
+@return		Local drive identifier or KErrNotFound if not found
+*/
+	{
+	TInt drive = KErrNotFound;
+	
+	RLocalDrive	d;
+	TBool change = EFalse;
+	TLocalDriveCapsV5 driveCaps;
+	TPckg<TLocalDriveCapsV5> capsPack(driveCaps);
+	
+	for(TInt i = 0; i < KMaxLocalDrives && drive < 0; ++i)
+		{
+		if(d.Connect(i, change) == KErrNone)
+			{
+			if(d.Caps(capsPack) == KErrNone)
+				{
+				if ((driveCaps.iMediaAtt & KMediaAttPageable) &&
+					(driveCaps.iPartitionType == KPartitionTypePagedData))
+					{
+					drive = i;
+					}
+				}
+			d.Close();
+			}
+		}
+		
+	if(drive == KErrNotFound)
+		{
+		test.Printf(_L("No data paging drive found\n"));
+		}
+		
+	return drive;
+	}
+	
+LOCAL_C TInt DataPagingMediaCaps(TLocalDriveCapsV5 &aCaps)
+/** 
+Return the caps of the media containing a swap partition.
+
+@return		Error code, on success aCaps contains the capabilities of the paging drive
+*/
+	{
+	TInt dataPagingDrive = FindDataPagingDrive();
+	
+	if (dataPagingDrive == KErrNotFound)
+		{
+		return KErrNotFound;
+		}
+
+	RLocalDrive	dpDrive;
+	TBool change = EFalse;
+
+	TInt r = dpDrive.Connect(dataPagingDrive, change);
+	test(r == KErrNone);
+	
+	TLocalDriveCapsV5 dpDriveCaps;
+	TPckg<TLocalDriveCapsV5> capsPack(dpDriveCaps);
+	r = dpDrive.Caps(capsPack);
+	test(r == KErrNone);
+	
+	if((dpDriveCaps.iDriveAtt & KDriveAttHidden) == 0)
+		{
+		test.Printf(_L("Paging partition is not hidden! Assuming it is correct anyway!\n"));
+		}
+	
+	aCaps = dpDriveCaps;
+	
+	return KErrNone;
+	}
+	
+LOCAL_C TBool IsDriveOnPagingMedia(TInt aDrive, TLocalDriveCapsV5 &aPagingMediaCaps)
+/** 
+Determines whether a drive is on the same media as the paging media by comparing 
+media characteristics
+
+@return		ETrue if (likely) to be on the same media, EFalse if not.
+*/	{
+	RLocalDrive	drive;
+	TBool change = EFalse;
+
+	TInt r = drive.Connect(aDrive, change);
+	test(r == KErrNone);
+	
+	TLocalDriveCapsV5 driveCaps;
+	TPckg<TLocalDriveCapsV5> capsPack(driveCaps);
+	r = drive.Caps(capsPack);
+	test(r == KErrNone);
+	
+	// Check media serial number
+	if(aPagingMediaCaps.iSerialNumLength > 0)
+		{
+		if((driveCaps.iSerialNumLength > 0) && 
+		   ((memcompare(driveCaps.iSerialNum, driveCaps.iSerialNumLength, 
+			aPagingMediaCaps.iSerialNum, aPagingMediaCaps.iSerialNumLength)) == 0))
+			{
+			// serial numbers equal, so drive in question is on same media as paging drive
+			test.Printf(_L("Based on serial number match, drive %d shares the same media as paging drive\n"), aDrive);
+			return ETrue;
+			}
+		}
+	else
+		{
+		// Turn off bits which may be different
+		aPagingMediaCaps.iDriveAtt &= KDriveAttMask;
+		aPagingMediaCaps.iMediaAtt &= KMediaAttMask;
+		driveCaps.iDriveAtt &= KDriveAttMask;
+		driveCaps.iMediaAtt &= KMediaAttMask;
+
+		if ((driveCaps.iType == aPagingMediaCaps.iType) &&
+			(driveCaps.iDriveAtt == aPagingMediaCaps.iDriveAtt) && 
+			(driveCaps.iMediaAtt == aPagingMediaCaps.iMediaAtt))
+			{
+			test.Printf(_L("Based on media characteristics match, drive %d shares the same media as paging drive\n"), aDrive);
+			return ETrue;
+			}
+		}
+		
+	return EFalse;
+	}
+
 
 LOCAL_C TBool SetupDrivesForPlatform(TInt& aDrive, TInt& aSocket)
 /**
@@ -75,11 +201,26 @@
 	aDrive  = -1;
 	aSocket = -1;
 	
+	TLocalDriveCapsV5 pagingMediaCaps;
+	TBool pagingMediaCheck = EFalse;
+	if(DataPagingMediaCaps(pagingMediaCaps) == KErrNone)
+		{
+		pagingMediaCheck = ETrue;
+		}
+	
 	for(aDrive=0; aDrive < di.iTotalSupportedDrives; aDrive++)
 		{
 		test.Printf(_L(" Drive %d - %S\r\n"), aDrive, &di.iDriveName[aDrive]);
 		if(di.iDriveName[aDrive].MatchF(_L("MultiMediaCard0")) == KErrNone)
-			break;
+			{
+			if(pagingMediaCheck)
+				{
+				if( ! IsDriveOnPagingMedia(aDrive, pagingMediaCaps))
+					{
+					break;
+					}
+				}
+			}
 		}
 
 	if(aDrive == di.iTotalSupportedDrives)
@@ -172,14 +313,14 @@
  */
 	{
 	test.Console()->SetPos(20, 25);
-	test.Printf(_L("%S [%d cycles]"), &aTitle, aCycles);
+	test.Printf(_L("%S [%d cycles]\n"), &aTitle, aCycles);
 #ifdef __MANUAL_TEST__
 	test.Console()->SetPos(20, 27);
-	test.Printf(_L("<press a key>"));
+	test.Printf(_L("<press a key>\n"));
 	test.Getch();
 #endif
 	}
-		
+
 GLDEF_C TInt E32Main()
 /**
  * Test Entry Point for T_MEDCH.
@@ -213,6 +354,7 @@
 	 */
 	TInt drive;
 	TInt socket;
+
 	if(SetupDrivesForPlatform(drive, socket))
 		{
 		b.Format(_L("Connect to local drive %d"), drive);
--- a/kerneltest/e32test/prime/t_timer.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/prime/t_timer.cpp	Tue May 04 18:23:12 2010 +0100
@@ -290,16 +290,17 @@
             t2.HomeTime();
             }
         while (t2==t1);
-#if defined(_DEBUG)
-		TDateTime dt=t2.DateTime();
-		test.Printf(_L("%d:%d\r\n"),dt.Second(),dt.MicroSecond());
-#endif
-        test(t2>t1);
+
+		if (t2 <= t1)
+			{
+			test.Printf(_L("Time comparison failed\r\n"));
+			test.Printf(_L("Before: 0x%lx\r\n"), t1.Int64());
+			test.Printf(_L("After:  0x%lx\r\n"), t2.Int64());
+			test(t2>t1);
+			}
+
         t1=t2;
         }
-#if defined(_DEBUG)
-	test.Printf(_L("\r\n"));
-#endif
     }
 
 TInt AtTwice(TAny*)
--- a/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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
--- a/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.h	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/rm_debug/basic_tests/t_rmdebug2.h	Tue May 04 18:23:12 2010 +0100
@@ -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);
--- a/kerneltest/e32test/rm_debug/common/t_target_launcher.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/rm_debug/common/t_target_launcher.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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();
--- a/kerneltest/e32test/rm_debug/debug_targets/t_rmdebug_app.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/rm_debug/debug_targets/t_rmdebug_app.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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();
--- a/kerneltest/e32test/rm_debug/multi_target_tests/t_multi_target.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/rm_debug/multi_target_tests/t_multi_target.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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;
     }
 
 
--- a/kerneltest/e32test/secure/t_sdrivers.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/secure/t_sdrivers.cpp	Tue May 04 18:23:12 2010 +0100
@@ -367,7 +367,7 @@
 
 	// get another thread to try and call device GetCaps with descriptor in kernel memory...
 	test.Next(_L("Check GetCaps with bad descriptor 2"));
-	r = thread.Create(_L("TestGetCapsThread"),TestGetCapsThread,KDefaultStackSize,0x2000,0x2000,(TAny*)kernelPtr);
+	r = thread.Create(_L("TestGetCapsThread2"),TestGetCapsThread,KDefaultStackSize,0x2000,0x2000,(TAny*)kernelPtr);
 	test_KErrNone(r);
 	thread.Logon(ls);
 	thread.Rendezvous(rs);
--- a/kerneltest/e32test/system/t_mstim.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/system/t_mstim.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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()
--- a/kerneltest/e32test/thread/t_thread.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/e32test/thread/t_thread.cpp	Tue May 04 18:23:12 2010 +0100
@@ -601,7 +601,8 @@
 		test(thread.ExitCategory()==_L("panic"));
 		test(thread.ExitReason()==123);
 		test(thread.ExitType()==EExitPanic);
-		CLOSE_AND_WAIT(thread);
+		r = RTest::CloseHandleAndWaitForDestruction(thread);
+		test_KErrNone(r);
 		}
 	
 	test.Next(_L("Internal exit"));
--- a/kerneltest/f32test/server/t_ext1.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/f32test/server/t_ext1.cpp	Tue May 04 18:23:12 2010 +0100
@@ -448,6 +448,19 @@
 	test.Start(_L("Starting Test - T_EXT1"));
 	test(err==KErrNone);
 
+	// Check that the drive supports extensions.
+	TBool extensionsSupported = EFalse;
+	TPckg<TBool> dataBuf(extensionsSupported);
+	err = TheFs.QueryVolumeInfoExt(drive,EFSysExtensionsSupported,dataBuf);
+	test(err==KErrNone);
+	if(!extensionsSupported)
+	    {
+        test.Printf(_L("Drive %d does not support file sys extensions. Skipping test."), drive);
+        test.End();
+        test.Close();
+        return;
+	    }
+	
     PrintDrvInfo(TheFs, drive);
 
 //Do not run this test on the NAND drive, as
--- a/kerneltest/f32test/server/t_rcache.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/kerneltest/f32test/server/t_rcache.cpp	Tue May 04 18:23:12 2010 +0100
@@ -1446,7 +1446,7 @@
 
 */
 LOCAL_C void TestReadAhead()
-{
+	{
 	TInt r = 0,tcreate;
 	RFile fileRead;
 	HBufC8* dummy = NULL;
@@ -1454,28 +1454,6 @@
 
 	TUint32 initTicks = 0;
 	TUint32 finalTicks = 0;
-	TTimeIntervalMicroSeconds timeTakenReadFirst(0);
-	TTimeIntervalMicroSeconds timeTakenReadSubsequent(0);
-
-	// On NAND/FAT and NOR/LFFS drives, due to the lack of DMA support, the read-ahead is likely to happen
-	// BEFORE control is returned to this test app - for NAND this could be fixed by adding
-	// "FileCacheReadAsync OFF" to the estart.txt file, but we can't do this on the integrator as it has no
-	// estart.txt file. Also, we can't set "FileCacheReadAsync OFF" for LFFS as it kills the LFFS background
-	// processing (!)
-	// So... it's only really worth testing on MMC.
-	_LIT(KFATName,"FAT");
-	TDriveInfo driveInfo;
-	test(TheFs.Drive(driveInfo, gDrive) == KErrNone);
-	TFileName fileSystem;
-	r = TheFs.FileSystemName(fileSystem, gDrive);
-	fileSystem.UpperCase();
-	test((r==KErrNone)||(r==KErrNotFound));
-	// ONLY test on MMC
-	if ((driveInfo.iType != EMediaHardDisk) || (fileSystem.Compare(KFATName) != 0))
-		{
-		test.Printf(_L("Skipping read-ahead testing (drive is not MMC)...\n"));
-		return;
-		}
 
 	//--Find out if the drive is sync/async at this point and print information
     TPckgBuf<TBool> drvSyncBuf;
@@ -1514,82 +1492,81 @@
 	r = fileRead.Open(TheFs,gFirstFile,EFileShareAny|EFileRead|EFileReadBuffered|EFileReadAheadOn);
 	test_KErrNone(r);
 
-	// Read #1
-	test.Printf(_L("Issuing read #1...\n"));
-	initTicks = User::FastCounter();
-	r = fileRead.Read(dummyPtr);
-	finalTicks = User::FastCounter();
+#if defined(_DEBUG) || defined(_DEBUG_RELEASE)
+	TFileCacheStats fileCacheStats;
+	r = controlIo(TheFs,gDrive, KControlIoFileCacheStats, fileCacheStats);
 	test_KErrNone(r);
+	TInt totalBytesRead = fileCacheStats.iUncachedBytesRead;
+	test.Printf(_L("totalBytesRead %d\n"), totalBytesRead);
+	TInt bytesRead = 0;
+	TInt filePos = 0;
+#endif
 
-	timeTakenReadFirst = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
-	test.Printf(_L("first read time %d \n"), I64LOW(timeTakenReadFirst.Int64()));
+	const TInt KReadCount = 6;
+	#define	PAGE_ROUND_UP(x) ((x + 4095) & (-4096))
+	TInt expectedBytesRead[KReadCount] = 
+		{
+		PAGE_ROUND_UP(KReadLen),	// read #0 from media
+		PAGE_ROUND_UP(KReadLen),	// read #1 from media
+		PAGE_ROUND_UP(KReadLen*2),	// read #2 from media, read-ahead #1 of length KReadLen
+		PAGE_ROUND_UP(KReadLen*2),	// read #3 from cache, read-ahead #2 of length KReadLen * 2
+		PAGE_ROUND_UP(KReadLen*4),	// read #4 from cache, read-ahead #3 of length KReadLen * 4
+		0,							// read #5 from cache, no read-ahead
+		};
+	TTimeIntervalMicroSeconds readTimes[KReadCount];
 
-	// Read #2
-	test.Printf(_L("Issuing read #2...\n"));
-	r = fileRead.Read(dummyPtr);
+	for (TInt n=0; n<KReadCount; n++)
+		{
+
+		initTicks = User::FastCounter();
+		r = fileRead.Read(dummyPtr);
+		finalTicks = User::FastCounter();
+		test_KErrNone(r);
 
-	// Read #3
-	test.Printf(_L("Issuing read #3......resulting in read-ahead #1\n"));
-	r = fileRead.Read(dummyPtr);
+		readTimes[n] = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
+		test.Printf(_L("%d: read time %d \n"), n, I64LOW(readTimes[n].Int64()));
 
-	// Wait for the read ahead #1 to be done - this should be approx the same size as previous read (KReadLen)
-	test.Printf(_L("Wait for read-ahead #1...\n"));
-	User::After(I64LOW(timeTakenReadFirst.Int64()) * 3 / 2);
-
+		TInt readAheadTime = I64LOW(readTimes[0].Int64()) * expectedBytesRead[n] / expectedBytesRead[0];
+		// Wait for the read ahead to be done 
+		if (n >= 2)
+			{
+			test.Printf(_L("Wait %u uS for read-ahead ...\n"), readAheadTime);
+			User::After(readAheadTime);
+			}
 
-	test.Printf(_L("Issuing read #4...resulting in read-ahead #2\n"));
-	initTicks = User::FastCounter();
-	r = fileRead.Read(dummyPtr);
-	finalTicks = User::FastCounter();
-	test_KErrNone(r);
-	timeTakenReadSubsequent = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
+#if defined(_DEBUG) || defined(_DEBUG_RELEASE)
+		// check the number of bytes read from the media is as expected. i.e. including the read-ahead length
+		// Keep waiting if it's not for up to 10 seconds
+		const TInt KMaxWaitTime = 10000000;	// 10 secs
+		TInt waitTime;
+		for (waitTime=0; waitTime <KMaxWaitTime; waitTime+= readAheadTime)
+			{
+			r = controlIo(TheFs,gDrive, KControlIoFileCacheStats, fileCacheStats);
+			test_KErrNone(r);
+			bytesRead = fileCacheStats.iUncachedBytesRead - totalBytesRead;
+			TInt bytesReadExpected = Min(gFirstFileSize - filePos, expectedBytesRead[n]);
 
-	test.Printf(_L("read time:  %d \n"), I64LOW(timeTakenReadSubsequent.Int64()));
+			test.Printf(_L("bytesRead %d, bytesReadExpected %d\n"), bytesRead, bytesReadExpected);
+
+			if (bytesRead == bytesReadExpected)
+				break;
+			User::After(readAheadTime);
+			}
+		test(waitTime < KMaxWaitTime);
+		totalBytesRead+= bytesRead;
+		filePos += bytesRead;
+#endif
 
 #if !defined(__WINS__)
-	// NB the read-ahead on LFFS occurs "synchronously" i.e. it occurs before control is returned
-	// to the caller. However it's not a good idea to mark the drive as synchronous (FileCacheReadAsync OFF)
-	// as this causes the drive thread's priority to be lowered which kills the LFFS background processing (!)
-	if (gPagedRom)
-		test.Printf(_L("Skipping timing test on paged ROM\n"));
-	else
-		test(timeTakenReadSubsequent.Int64() < timeTakenReadFirst.Int64());
+		// Read #3 should be able to be satisfied entirely from the cache, so should be quicker. If it's not quicker,
+		// display a warning rather than failing, because the read-ahead might be hogging the CPU, delaying the read from the cache.
+		if (n >= 3)
+			{
+			if (readTimes[n].Int64() >= readTimes[0].Int64())
+				test.Printf(_L("WARNING: Subsequent read not faster despite read-ahead !!!\n"));
+			}
 #endif
-
-	// The read ahead #2 should now be in progress - this should be approx KReadLen * 2
-	// so this read will take result in the next read taking longer than normal (about double)
-	test.Printf(_L("Issuing read #5......resulting in read-ahead #3\n"));
-	initTicks = User::FastCounter();
-	r = fileRead.Read(dummyPtr);
-	finalTicks = User::FastCounter();
-	test_KErrNone(r);
-	timeTakenReadSubsequent = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
-	test.Printf(_L("read time:  %d\n"), I64LOW(timeTakenReadSubsequent.Int64()));
-
-
-	// this read should take a long time, so don't test
-//#if !defined(__WINS__)
-//	test(gTimeTakenReadBlockFile.Int64() < gTimeTakenBigFile.Int64());
-//#endif
-
-	// The third read should be very quick as the previous read-ahead should have already buffered the data
-	test.Printf(_L("Issuing read #6......resulting in read-ahead #4\n"));
-	initTicks = User::FastCounter();
-	r = fileRead.Read(dummyPtr);
-	finalTicks = User::FastCounter();
-	test_KErrNone(r);
-	timeTakenReadSubsequent = TicksToMsec(initTicks, finalTicks, fastCounterFreq);
-	test.Printf(_L("read time:  %d\n"), I64LOW(timeTakenReadSubsequent.Int64()));
-
-
-#if !defined(__WINS__)
-	if (gPagedRom)
-		test.Printf(_L("Skipping timing test on paged ROM\n"));
-	else
-		test(timeTakenReadSubsequent.Int64() < timeTakenReadFirst.Int64());
-#endif
-
-
+		}
 	fileRead.Close();
 
 	r = DeleteAll(gSessionPath);
@@ -1597,8 +1574,7 @@
 
 	delete dummy;
 	test.End();
-
-}
+	}
 
 /** Main tests function
 */
--- a/package_definition.xml	Tue May 04 16:57:20 2010 +0100
+++ b/package_definition.xml	Tue May 04 18:23:12 2010 +0100
@@ -61,6 +61,14 @@
         <!-- owned and maintained by usb package. To be moved there as soon as technical limitations are resolved -->
         <unit bldFile="kernel/eka/drivers/usbc" mrp="kernel/eka/drivers/usbc/base_e32_drivers_usbcli.mrp"/>
       </component>
+      <component id="usbdescriptors" name="USB Descriptors" purpose="optional">
+        <!-- owned and maintained by usb package. To be moved there as soon as technical limitations are resolved -->
+        <unit bldFile="kernel/eka/drivers/usbho/usbdescriptors" mrp="kernel/eka/drivers/usbho/usbdescriptors/base_drivers_usbdescriptors.mrp"/>
+      </component>
+      <component id="usbdi_utils" name="USB DI Utils" purpose="optional">
+        <!-- owned and maintained by usb package. To be moved there as soon as technical limitations are resolved -->
+        <unit bldFile="kernel/eka/drivers/usbho/usbdi_utils" mrp="kernel/eka/drivers/usbho/usbdi_utils/base_drivers_usbdi_utils.mrp"/>
+      </component>
     </collection>
     <collection id="driversupport" name="Generic Driver Support" level="hw-if">
       <component id="mediadrivers" name="Media Drivers" purpose="optional">
@@ -133,6 +141,9 @@
       <component id="kernelhwsrv_metadata" name="Kernel and Hardware Services Metadata" class="config" introduced="^2" purpose="development" target="desktop">
         <unit mrp="kernelhwsrv_info/kernelhwsrv_metadata/kernelhwsrv_metadata.mrp"/>
       </component>
+      <component id="kernelhwsrv_metadata" name="Kernel and Hardware Services Public Documentation" class="doc" introduced="^3" purpose="development">
+        <unit mrp="kernelhwsrv_info/doc_pub/kernelhwsrv_doc_pub.mrp"/>
+      </component>
     </collection>
   </package>
 </SystemDefinition>
--- a/userlibandfileserver/fileserver/group/release.txt	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/group/release.txt	Tue May 04 18:23:12 2010 +0100
@@ -1,3 +1,44 @@
+Version 2.00.3024
+=================
+(Made by vfebvre 22/03/2010)
+
+1.	migubarr
+	1.	DEF144423 Frequent T_RCACHE failures on the H2/H6 (line 1556)
+
+2.	michcox
+	1.	PDEF145110 File server does not check return result of some User::ReAlloc()'s 
+
+
+Version 2.00.3023
+=================
+(Made by vfebvre 15/03/2010)
+
+1.	niccox
+	1.	DEF145021 Improper Mass Storage Error Code for Empty Drive case
+
+2.	shamaden
+	1.	PDEF144922 TRAI-82RJFS Crash when usb memory is dismounted during copy 
+
+
+Version 2.00.3022
+=================
+(Made by vfebvre 12/03/2010)
+
+1.	famustaf
+	1.	MINOR_CHANGE Updated RFs::ScanDrive and RFs::CheckDisk Documentation
+
+2.	michcox
+	1.	DEF144912 T_EXT1 fails under platsim as it doesn't support fsys extensions 
+
+
+Version 2.00.3021
+=================
+(Made by vfebvre 11/03/2010)
+
+1.	frhofman
+	1.	PDEF144919: SALM-82WCVK: efile.exe crashes in dynamic dir cache code when out-of-memory
+
+
 Version 2.00.3020
 =================
 (Made by vfebvre 08/03/2010)
--- a/userlibandfileserver/fileserver/inc/f32file.h	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/inc/f32file.h	Tue May 04 18:23:12 2010 +0100
@@ -680,6 +680,15 @@
     ETrue value means that the drive is finalised
     */
     EIsDriveFinalised,
+    
+    /**
+    Query the volume to ascertain whether File system extensions
+    are supported on this volume.
+    A boolean value is returned within the buffer defined as TPckgBuf<TBool>. 
+    ETrue value means that extensions are supported.
+    EFalse means they are not supported.
+     */
+    EFSysExtensionsSupported,
 	};
 
 /**
--- a/userlibandfileserver/fileserver/inc/f32ver.h	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/inc/f32ver.h	Tue May 04 18:23:12 2010 +0100
@@ -58,6 +58,6 @@
 
 @see TVersion
 */
-const TInt KF32BuildVersionNumber=3020;
+const TInt KF32BuildVersionNumber=3024;
 //
 #endif
--- a/userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/sfat32/sl_dir_cache.cpp	Tue May 04 18:23:12 2010 +0100
@@ -27,9 +27,9 @@
 The static cache page creation function.
 Cache page objects are not supposed to be created on the stack, so this factory function is required.
 */
-TDynamicDirCachePage* TDynamicDirCachePage::NewL(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
+TDynamicDirCachePage* TDynamicDirCachePage::CreateCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr)
 	{
-	return new(ELeave) TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr);
+	return new TDynamicDirCachePage(aOwnerCache, aStartMedPos, aStartRamAddr);
 	}
 
 /**
@@ -158,7 +158,7 @@
 
 	// allocate as many permanently locked pages as there are threads - plus one
 	// otherwise DoMakePageMRU() won't work properly with only one thread
-    //-- At present moment the size of TDrive thread pool is 1 (1 drive thread in a pool)
+	//-- At present moment the size of TDrive thread pool is 1 (1 drive thread in a pool)
 	const TUint KThreadCount = 1;
 	iPermanentlyAllocatedPageCount = KThreadCount + 1; 
 
@@ -167,7 +167,10 @@
 
 	for (TUint n=0; n<iPermanentlyAllocatedPageCount; n++)
 		{
-		TDynamicDirCachePage* pPage = AllocateAndLockNewPageL(0);
+		TDynamicDirCachePage* pPage = AllocateAndLockNewPage(0);
+		ASSERT(pPage);
+		if (!pPage)
+			User::Leave(KErrNoMemory);
 		AddFirstOntoQueue(pPage, TDynamicDirCachePage::ELocked);
 		LookupTblAdd(pPage);
 		}
@@ -694,47 +697,46 @@
 		}
 
 	TDynamicDirCachePage* pPage = FindPageByPos(aPos);
-    if (pPage)
-    	{
-    	ASSERT(pPage->IsValid());
+	if (pPage)
+		{
+		ASSERT(pPage->IsValid());
 		// lock page before make it MRU
-    	if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
-    		{
-    		ASSERT(!pPage->IsLocked());
-        	if (LockPage(pPage) == NULL)
-        		{
-        		DeQueue(pPage);
-        		LookupTblRemove(pPage->StartPos());
-        		DecommitPage(pPage);
-        		delete pPage;
-        		pPage = NULL;
-        		}
-    		}
-    	else
-    		{
-    		// error checking: page should either be locked or active
-    		ASSERT(LockPage(pPage) != NULL);
-    		}
-    	}
+		if (pPage->PageType() == TDynamicDirCachePage::EUnlocked)
+			{
+			ASSERT(!pPage->IsLocked());
+			if (LockPage(pPage) == NULL)
+				{
+				DeQueue(pPage);
+				LookupTblRemove(pPage->StartPos());
+				DecommitPage(pPage);
+				delete pPage;
+				pPage = NULL;
+				}
+			}
+		else
+			{
+			// error checking: page should either be locked or active
+			ASSERT(LockPage(pPage) != NULL);
+			}
+		}
 
-    // if page not found or page data not valid anymore, use active page to read data
-    if (!pPage)
-    	{
-        TRAPD(err, pPage = UpdateActivePageL(aPos));
-        if (err != KErrNone)
-        	{
-        	// problem occurred reading active page, return immediately.
-        	return;
-        	}
-    	}
+	// if page not found or page data not valid anymore, use active page to read data
+	if (!pPage)
+		{
+		TRAPD(err, pPage = UpdateActivePageL(aPos));
+		if (err != KErrNone)
+			{
+			// problem occurred reading active page, return immediately.
+			return;
+			}
+		}
 
-    // by now, the page is either locked or active page
+	// by now, the page is either locked or active page
 	ASSERT(pPage && pPage->IsValid() && pPage->IsLocked());
 
 
-
-	TBool allocateNewPage = pPage == iLockedQ.Last() && !CacheIsFull();
-
+	// if we used the active page (last on the queue), try to grow the cache.
+	TBool growCache = pPage == iLockedQ.Last();
 
 	switch (pPage->PageType())
 		{
@@ -762,24 +764,24 @@
 			ASSERT(0);
 		}
 
-	if (allocateNewPage)
-		{
-		TDynamicDirCachePage* nPage = NULL;
-		TRAPD(err, nPage = AllocateAndLockNewPageL(0));
-		if (err == KErrNone)
-			{
+	if (CacheIsFull() || !growCache)
+		return;
+
+	// attempt to grow the cache by appending a clean, new page at the end of the LRU list.
+	// This can fail when out of memory; the LRU mechanism then makes sure the oldest page will be re-used.
+	TDynamicDirCachePage* nPage = AllocateAndLockNewPage(0);
+	if (!nPage)
+		return;
 
-			// about to add a page to end of locked queue, so lie about iLockedQCount
-			iLockedQCount++;
-			CheckThresholds();
-			iLockedQCount--;
+	// about to add a page to end of locked queue, so lie about iLockedQCount
+	iLockedQCount++;
+	CheckThresholds();
+	iLockedQCount--;
 
-			iLockedQ.AddLast(*nPage);
-			nPage->SetPageType(TDynamicDirCachePage::ELocked);
-			++iLockedQCount;
-			LookupTblAdd(nPage);
-			}
-		}
+	iLockedQ.AddLast(*nPage);
+	nPage->SetPageType(TDynamicDirCachePage::ELocked);
+	++iLockedQCount;
+	LookupTblAdd(nPage);
 	}
 
 /**
@@ -898,21 +900,28 @@
 @param	aStartMedPos	the starting media address of the page to be created.
 @pre	aStartMedPos should not already be existing in the cache.
 */
-TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPageL(TInt64 aStartMedPos)
+TDynamicDirCachePage* CDynamicDirCache::AllocateAndLockNewPage(TInt64 aStartMedPos)
 	{
-	__PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPageL(aStartMedPos=%lx)"), aStartMedPos);
+	__PRINT1(_L("CDynamicDirCache::AllocateAndLockNewPage(aStartMedPos=%lx)"), aStartMedPos);
 
 	TUint8* startRamAddr = iCacheMemoryClient->AllocateAndLockSegments(PageSizeInSegs());
-	if (startRamAddr)
+
+	if (!startRamAddr)
+		return NULL;
+
+	TDynamicDirCachePage* pPage = TDynamicDirCachePage::CreateCachePage(this, aStartMedPos, startRamAddr);
+
+	// Failure would mean the cache chunk was able to grow but we've run out of heap.
+	// This seems extremely unlikely, but decommit the now-unmanageable cache segment just in case.
+	if (!pPage)
 		{
-		// create new page and return
-		TDynamicDirCachePage* pPage = TDynamicDirCachePage::NewL(this, aStartMedPos, startRamAddr);
-		pPage->SetLocked(ETrue);
-		pPage->SetValid(EFalse);
-		return pPage;
+		iCacheMemoryClient->DecommitSegments(startRamAddr, PageSizeInSegs());
+		return NULL;
 		}
 
-	return NULL;
+	pPage->SetLocked(ETrue);
+	pPage->SetValid(EFalse);
+	return pPage;
 	}
 
 #ifdef _DEBUG
--- a/userlibandfileserver/fileserver/sfat32/sl_dir_cache.h	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/sfat32/sl_dir_cache.h	Tue May 04 18:23:12 2010 +0100
@@ -47,7 +47,7 @@
 
 public:
 	~TDynamicDirCachePage();
-	static TDynamicDirCachePage* NewL(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr);
+	static TDynamicDirCachePage* CreateCachePage(CDynamicDirCache* aOwnerCache, TInt64 aStartMedPos, TUint8* aStartRamAddr);
 	
 	inline void	SetLocked(TBool);
 	inline TBool	IsLocked() const;
@@ -145,7 +145,7 @@
 
 	TDynamicDirCachePage* FindPageByPos(TInt64 aPos);
 	TDynamicDirCachePage* UpdateActivePageL(TInt64 aPos);
-	TDynamicDirCachePage* AllocateAndLockNewPageL(TInt64 aStartMedPos);
+	TDynamicDirCachePage* AllocateAndLockNewPage(TInt64 aStartMedPos);
 	TUint8* LockPage(TDynamicDirCachePage* aPage);
 	TInt 	UnlockPage(TDynamicDirCachePage* aPage);
 	TInt 	DecommitPage(TDynamicDirCachePage* aPage);
--- a/userlibandfileserver/fileserver/sfat32/sl_drv.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/sfat32/sl_drv.cpp	Tue May 04 18:23:12 2010 +0100
@@ -1,4 +1,4 @@
-// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
+// Copyright (c) 1996-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"
@@ -46,12 +46,11 @@
     Close the interface to the media driver
 */
 void TDriveInterface::Close()
-{
-	 if(iMount)
+{	 
+	 if((iMount != NULL) && (iMount->LocalDrive() != NULL))
 		{
 		iMount->LocalDrive()->SetMount(NULL);
-        }
-
+		}
      iMount = NULL;
 }
 
--- a/userlibandfileserver/fileserver/sfat32/sl_scan32.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/sfat32/sl_scan32.cpp	Tue May 04 18:23:12 2010 +0100
@@ -94,7 +94,7 @@
 //----------------------------------------------------------------------------------------------------
 /**
     FAT type-agnostic parser. Reads whole FAT and sets up a bit vector.
-    for FAT12/16 it's OK, because the FAT12/16 is fully cached.
+    For FAT12/16 it's OK, because the FAT12/16 is fully cached.
 */
 void CScanDrive::DoParseFatL()
     {
@@ -255,8 +255,9 @@
 
 //----------------------------------------------------------------------------------------------------
 /**
-    Start the scanner. The this calss description about what it actually does.
-    @param  aMode specifies the operational mode.
+    Starts the scanner.
+    
+    @param	aMode	Specifies the operational mode.
 */
 void CScanDrive::StartL(TScanDriveMode aMode)
 	{
@@ -946,7 +947,6 @@
     Read the "Rugged FAT" ID, stored in reserved2 in the Dos entry or associated with the Dos entry of the 
     Entry at the position passed in. This is used to find which version of two matching entries should be kept.
 
-
     @param aVFatPos Position of an entry to read ID from
     @leave System wide error codes
     @return The ID found in reserved2 field of dos entry 
--- a/userlibandfileserver/fileserver/sfile/sf_cache.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_cache.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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)
 		{
--- a/userlibandfileserver/fileserver/sfile/sf_obj.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_obj.cpp	Tue May 04 18:23:12 2010 +0100
@@ -129,7 +129,13 @@
 			if (newAlloc!=iAllocated)
 				{
 				if (newAlloc)
+				    {
 					iContainers=(CFsObjectCon**)User::ReAlloc(iContainers,newAlloc*sizeof(CFsObjectCon*));
+					if(!iContainers)
+					    {
+					    Fault(EContainerHeapCorruptionOnRemove);
+					    }
+				    }
 				else
 					{
 					delete iContainers;
@@ -489,7 +495,13 @@
 		if (newAlloc!=iAllocated)
 			{
 			if (newAlloc)
+			    {
 				iObjects=(SFsObjectIxRec*)User::ReAlloc(iObjects,newAlloc*sizeof(SFsObjectIxRec));
+				if(!iObjects)
+				    {
+                    Fault(EContainerHeapCorruptionOnRemove);
+				    }
+			    }
 			else
 				{
 				delete iObjects;
@@ -679,7 +691,13 @@
 			if (newAlloc!=iAllocated)
 				{
 				if (newAlloc)
+				    {
 					iObjects=(CFsObject**)User::ReAlloc(iObjects,newAlloc*sizeof(CFsObject*));
+					if(!iObjects)
+					    {
+					    Fault(EContainerHeapCorruptionOnRemove);
+					    }
+				    }
 				else
 					{
 					delete iObjects;
--- a/userlibandfileserver/fileserver/sfile/sf_std.h	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_std.h	Tue May 04 18:23:12 2010 +0100
@@ -235,7 +235,7 @@
 
 enum TFsPanic
 	{
-	ELdrImportedOrdinalDoesNotExist
+	ELdrImportedOrdinalDoesNotExist	
 	};
 //
 enum TFsFault
@@ -443,7 +443,8 @@
 	ETraceLddLoadFailure,				//200
 	ETooManyDrivesPerSocket,
 	ENotificationFault,
-	EFsObjectOpen
+	EFsObjectOpen,
+	EContainerHeapCorruptionOnRemove
 	};
 
 
--- a/userlibandfileserver/fileserver/sfile/sf_svr.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/sfile/sf_svr.cpp	Tue May 04 18:23:12 2010 +0100
@@ -1314,8 +1314,13 @@
 
                 return KErrNone;
             }
-
-            
+            case EFSysExtensionsSupported:
+            {
+                TBool supported = pDrive->GetFSys()->IsExtensionSupported();
+                TPckgBuf<TBool> data(supported);
+                aRequest->WriteL(KMsgPtr2,data);
+                return KErrNone;
+            }
 		default:
 			{
 			return KErrNotSupported;
--- a/userlibandfileserver/fileserver/sfsrv/cl_cli.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/sfsrv/cl_cli.cpp	Tue May 04 18:23:12 2010 +0100
@@ -2630,29 +2630,37 @@
 	}
 
 
-
 /**
-Checks the integrity of the disk on the specified drive.
-On FAT, this checks if a cluster number is invalid, if a cluster is allocated to
-more than one file entry, if an unallocated cluster is not set free, and if size
-of an entry is invalid.
-
-@param aDrive Path indicating the drive which contains the disk to be checked. If the drive 
-        information is not specified the current session drive is taken by default.
-		Checkdisk is performed on the requested drive irrespective of the correctness or
-		existance of the given path.
-
-@return KErrNone, if successful;
-		1, if successful but a file cluster contains a bad value;
-		2, if successful but two files are linked to the same cluster;
-		3, if successful but an unallocated cluster contains a value;
-		4, if successful but the size of a file is not equal to the number of clusters in chain;
-        KErrNotReady, if the specified drive is empty;
-        KErrNotSupported, if the drive cannot handle this request;
-        KErrPermissionDenied, if the caller doesn't have DiskAdmin capability;
-        Other system wide error codes may also be returned.
-
-@capability DiskAdmin
+Checks the integrity of the File System mounted on the specified drive.
+The behaviour of this API and return codes are File System specific,
+dependent on how the File System implements its CheckDisk functionality.
+Note that CheckDisk does not fix any errors that may be found,
+it just reports the first problem it has found.
+
+@param	aDrive	Path containing the drive to be checked.
+				If the drive letter is not specified, the current session drive is taken by default.
+
+@return	KErrNone				If CheckDisk has not found any errors it knows about.
+        KErrNotReady			If the specified drive is not ready.
+        KErrNotSupported		If this functionality is not supported.
+        KErrPermissionDenied	If the caller does not have DiskAdmin capability.
+        Other system-wide error codes.
+
+@capability	DiskAdmin
+
+FAT File System specific information:
+
+CheckDisk checks for a limited amount of possible corruption cases such as
+invalid cluster numbers in the FAT table, lost and cross-linked cluster chains,
+various errors within the directory entry etc.
+
+If CheckDisk returns KErrNone, this means that there are no errors that CheckDisk on FAT is aware of.
+
+Error codes returned by the FAT version of CheckDisk include: 
+		1	Bad cluster value in FAT table detected.
+		2	Cross-linked cluster chain detected.
+		3	Lost cluster chain detected.
+		4	File size does not correspond to the number of clusters reported in the FAT table.
 */
 EFSRV_EXPORT_C TInt RFs::CheckDisk(const TDesC& aDrive) const
 	{
@@ -2668,24 +2676,42 @@
 
 EFSRV_EXPORT_C TInt RFs::ScanDrive(const TDesC& aDrive) const
 /**
-Checks the specified drive for errors and corrects them. Specifically, it
-checks if long file name entries' IDs are in sequence and short name is valid,
-and file's allocated clusters are not used by other files.
-
-This does not run on the internal RAM drive, and only applies to a
-FAT file system.
-
-@param aDrive Path indicating the drive which contains the disk to be checked. If the drive 
-        information is not specified the current session drive is taken by default.
-		ScanDrive is performed on the requested drive irrespective of the correctness or
-		existance of the given path.
-
-@return KErrNone if successful,
-        KErrPermissionDenied if caller doesn't have capability DiskAdmin,
-        KErrInUse if drive is in use,
-        otherwise one of the other system-wide error codes
-
-@capability DiskAdmin
+Checks the integrity of the File System mounted on the specified drive
+and attempts to correct some known File System errors.
+The behaviour of this API and return codes are File System specific,
+dependent on how the File System implements its ScanDrive functionality.
+
+ScanDrive will not run on drives that have files or directories opened.
+
+@param	aDrive	Path indicating the drive which contains the disk to be checked.
+				If the drive letter is not specified, the current session drive is taken by default.
+
+@return KErrNone				On success.
+		KErrInUse				If drive is in use (i.e. if there are files and/or directories opened in the drive).
+		KErrCorrupt				If ScanDrive has detected a file system corruption that it cannot fix.
+        KErrNotSupported		If this functionality is not supported.
+        KErrPermissionDenied	If the caller does not have DiskAdmin capability.
+		Other system-wide error codes.
+
+@capability	DiskAdmin
+
+FAT File System specific information:
+
+ScanDrive is intended to be run ONLY on "Rugged-FAT" file system
+which is applicable to internal non-removable drives.
+Internal RAM drives are not supported.
+
+The "Rugged FAT" file system is designed in such a way that only a limited number
+of known cases of corruption can be caused by sudden power loss.
+All of these known cases can be corrected by ScanDrive.
+Hence, running ScanDrive on "Rugged FAT" file system will result in:
+		KErrNone	If there was no File System corruption or ScanDrive has successfully repaired the File System.
+		KErrCorrupt If ScanDrive has found a File System error that it cannot repair.
+		Other system-wide error codes, see above.
+
+Running ScanDrive on removable media or media that has FAT file system not in
+"Rugged FAT" mode is not practical, because ScanDrive is not designed for this.
+Therefore, do not treat ScanDrive on removable media as a generic "disk repair utility".
 */
 	{
 	TRACEMULT2(UTF::EBorder, UTraceModuleEfsrv::EFsScanDrive, MODULEUID, Handle(), aDrive);
--- a/userlibandfileserver/fileserver/shostmassstorage/msproxy/hostusbmsproxy.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/shostmassstorage/msproxy/hostusbmsproxy.cpp	Tue May 04 18:23:12 2010 +0100
@@ -1,24 +1,18 @@
-/*
-* Copyright (c) 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:
-*
-*/
+// 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"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
 //
-// hostusbmsproxy.cpp
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
 //
-// This file system extension provides a way to access a drive on the MS system in "raw format".
-// It can be used to test large files / drives
+// Contributors:
+//
+// Description:
+// This file system extension provides a way to access a drive on the MS system
+// in "raw format". It can be used to test large files / drives
 //
 
 /** @file
@@ -486,6 +480,7 @@
 	return KErrNone;
 	}
 
+
 /**
 Write to the proxy drive and pass flags to driver
 
@@ -521,6 +516,7 @@
 	return iUsbHostMsLun.Write(iMsDataMemMap.GetDataPos(aPos), aSrc.Length(), aSrc);
 	}
 
+
 /**
 Get the proxy drive's capabilities information.
 
@@ -566,19 +562,22 @@
                     capsInfo.iNumberOfBlocks, capsInfo.iBlockLength,
 		            caps().iSize, caps().iMediaAtt);
 		}
-	else
+	else if (KErrNotReady)
         {
         __HOSTPRINT(_L("<<< HOST Caps Media Not Present"));
-		c.iType = EMediaNotPresent;
-		if(r != KErrNotReady)
-			r = KErrUnknown;
+		c.iType = EMediaNotPresent;		
+		r = KErrNone;
+        }
+    else
+        {
+        __HOSTPRINT(_L("<<< HOST Caps Unknown Error"));
+		r = KErrUnknown;
         }
 	anInfo = caps.Left(Min(caps.Length(),anInfo.MaxLength()));
 	return r;
 	}
 
 
-
 /**
 Format the proxy drive. The drive is assumed to be a single partition. The
 partition size is equivalent to the size of the media.
--- a/userlibandfileserver/fileserver/shostmassstorage/server/protocol/cscsiprotocol.cpp	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/shostmassstorage/server/protocol/cscsiprotocol.cpp	Tue May 04 18:23:12 2010 +0100
@@ -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,8 +26,6 @@
 #include "shared.h"
 #include "msgservice.h"
 
-#include "mscutils.h"
-
 #include "mtransport.h"
 #include "mprotocol.h"
 #include "tscsiclientreq.h"
@@ -45,7 +43,6 @@
 #include "usbmshostpanic.h"
 
 
-
 /**
 Create the CScsiProtocol object.
 
@@ -68,8 +65,8 @@
 void CScsiProtocol::ConstructL(TLun aLun)
     {
 	__MSFNLOG
+	// iState = EEntry;
     iFsm = CMassStorageFsm::NewL(*this);
-	iState = EDisconnected;
 
     const TInt blockLength = 0x200;
 
@@ -99,6 +96,7 @@
 void CScsiProtocol::InitialiseUnitL()
     {
 	__MSFNLOG
+    iState = EDisconnected;
 
 	// A device may take time to mount the media. If the device fails attempt to
 	// retry the connection for a number of seconds
@@ -107,10 +105,9 @@
         {
         retryCounter--;
         iFsm->ConnectLogicalUnitL();
-        iState = iFsm->IsConnected() ? EConnected: EDisconnected;
-
-        if (iState == EConnected)
+        if (iFsm->IsConnected())
             {
+            iState = EConnected;
             break;
             }
         User::After(1000 * 200);    // 200 mS
@@ -162,8 +159,7 @@
     if (err)
         {
         __SCSIPRINT1(_L("READ(10) Err=%d"), err);
-        DoCheckConditionL();
-        User::LeaveIfError(KErrAbort);
+        User::LeaveIfError(DoCheckConditionL());
         }
 
     // handle residue
@@ -189,8 +185,7 @@
         TInt err = iSbcInterface->Read10L(aPos/blockLen, aCopybuf, len);
         if (err)
             {
-            DoCheckConditionL();
-            User::LeaveIfError(KErrAbort);
+            User::LeaveIfError(DoCheckConditionL());
             }
         }
     }
@@ -217,8 +212,7 @@
 	TInt err = iSbcInterface->Write10L(aPos/blockLen, aCopybuf, aOffset, len);
     if (err)
         {
-        DoCheckConditionL();
-        User::LeaveIfError(KErrAbort);
+        User::LeaveIfError(DoCheckConditionL());
         }
 
     while (len != aLen)
@@ -242,8 +236,7 @@
         TInt err = iSbcInterface->Write10L(aPos/blockLen, buf, aOffset, len);
         if (err)
             {
-            DoCheckConditionL();
-            User::LeaveIfError(KErrAbort);
+            User::LeaveIfError(DoCheckConditionL());
             }
         }
     }
@@ -268,15 +261,11 @@
         err = iSbcInterface->ReadCapacity10L(lastLba, blockLength);
         } while (err == KErrCommandStalled && stallCounter-- > 0);
 
-
     if (err)
         {
-        if (err == KErrCommandFailed)
-            {
-            // Clear sense error
-            DoCheckConditionL();
-            }
-        User::LeaveIfError(KErrAbort);
+        // DoCheckConditionL clears sense error
+        // Media not present will return KErrNotReady so leave here
+        User::LeaveIfError(DoCheckConditionL());
         }
 
     // update iWriteProtect
@@ -286,14 +275,24 @@
         if (err == KErrCommandFailed)
             {
             // Clear sense error
-            DoCheckConditionL();
+            err = DoCheckConditionL();
+            // ignore error if unsupported
+            if (err != KErrUnknown)
+                {
+                User::LeaveIfError(err);
+                }
             }
 
         err = MsModeSense6L();
         if (err == KErrCommandFailed)
             {
             // Clear sense error
-            DoCheckConditionL();
+            err = DoCheckConditionL();
+            // ignore error if unsupported
+            if (err != KErrUnknown)
+                {
+                User::LeaveIfError(err);
+                }
             }           
         }
 
@@ -481,33 +480,49 @@
     }
 
 
-void CScsiProtocol::DoCheckConditionL()
+TInt CScsiProtocol::DoCheckConditionL()
     {
 	__MSFNLOG
     User::LeaveIfError(MsRequestSenseL());
 
+    TInt err;
+
     // Check if init is needed
     if (iSenseInfo.iSenseCode == TSenseInfo::ENotReady &&
         iSenseInfo.iAdditional == TSenseInfo::EAscLogicalUnitNotReady &&
         iSenseInfo.iQualifier == TSenseInfo::EAscqInitializingCommandRequired)
         {
         // start unit
-        TInt err = iSbcInterface->StartStopUnitL(ETrue);
-
+        err = iSbcInterface->StartStopUnitL(ETrue);
         if (err)
             {
             User::LeaveIfError(MsRequestSenseL());
             }
-
         }
 
-    TInt r = GetSystemWideSenseError(iSenseInfo);
+    err = GetSystemWideSenseError(iSenseInfo);
 
-    if (((r == KErrNotReady) && (iState == EConnected)) ||
-        r == KErrDisconnected)
-	    {
-        CompleteNotifyChangeL();
+    TScsiState nextState = iState;
+    if (err == KErrDisconnected)
+        {
+        nextState = EDisconnected;
+        }
+    else if (err == KErrNotReady)
+        {
+        nextState = EMediaNotPresent;
         }
+    else
+        {
+        // no state change;
+        }
+
+    if (nextState != iState)
+        {
+        iMediaChangeNotifier.DoNotifyL();
+        iState = nextState;
+        }
+           
+    return err;
     }
 
 
@@ -730,7 +745,7 @@
     __MSFNLOG
 	TInt err = KErrNone;
 
-	if(iFsm->IsRemovableMedia() || iState == EDisconnected)
+	if(iFsm->IsRemovableMedia() || iState != EConnected)
         {
 		iFsm->SetStatusCheck();
 		TRAP(err, iFsm->ConnectLogicalUnitL());
@@ -760,18 +775,6 @@
         }
 	}
 
-void CScsiProtocol::CompleteNotifyChangeL()
-	{
-    __MSFNLOG
-    if (!iFsm->IsStatusCheck())
-		{
-		if (iState == EConnected)
-			{
-			iState = EDisconnected;
-            iMediaChangeNotifier.DoNotifyL();
-			}
-		}
-	}
 
 RMediaChangeNotifier::RMediaChangeNotifier()
 :   iRegistered(EFalse)
--- a/userlibandfileserver/fileserver/shostmassstorage/server/protocol/include/cscsiprotocol.h	Tue May 04 16:57:20 2010 +0100
+++ b/userlibandfileserver/fileserver/shostmassstorage/server/protocol/include/cscsiprotocol.h	Tue May 04 18:23:12 2010 +0100
@@ -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"
@@ -36,7 +36,7 @@
     void DoCancelL();
 
 private:
-	void CompleteNotifierL(TInt);
+	void CompleteNotifierL(TInt aReason);
 
 private:
     /** Notification service */
@@ -55,6 +55,8 @@
    /** SCSI state */
    enum TScsiState
         {
+        EEntry,
+        EMediaNotPresent,
         EConnected,
         EDisconnected
         };
@@ -88,8 +90,8 @@
 	void NotifyChange(const RMessage2& aMessage);
     void ForceCompleteNotifyChangeL();
     void CancelChangeNotifierL();
-	void CompleteNotifyChangeL();
-	void SuspendL();
+
+    void SuspendL();
 	void ResumeL();
     TBool IsConnected();
 
@@ -116,7 +118,7 @@
 private:
     void ResetSbc();
 
-    void DoCheckConditionL();
+    TInt DoCheckConditionL();
 
 	TInt GetSystemWideSenseError(const TSenseInfo& aSenseInfo);
 	TInt ProcessAsCodes(const TSenseInfo& aSenseInfo);