Revision: 201036 RCL_3
authorDremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 15 Sep 2010 13:26:16 +0300
branchRCL_3
changeset 49 a4ff6126ec76
parent 45 be079f63985a
child 55 7151b503b58d
Revision: 201036 Kit: 201036
naviengine/navienginebsp/ne1_tb/test/pci/d_pci.cpp
naviengine/navienginebsp/ne1_tb/test/pci/t_pci.cpp
naviengine/navienginebsp/ne1_tb/test/pci/t_pci.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/naviengine/navienginebsp/ne1_tb/test/pci/d_pci.cpp	Wed Sep 15 13:26:16 2010 +0300
@@ -0,0 +1,882 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This material, including documentation and any related computer
+* programs, is protected by copyright controlled by Nokia. All
+* rights are reserved. Copying, including reproducing, storing
+* adapting or translating, any or all of this material requires the
+* prior written consent of Nokia. This material also contains
+* confidential information which may not be disclosed to others
+* without the prior written consent of Nokia.
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: Device-driver for naviEngine PCI testing 
+*
+*/
+
+#include <kernel/kernel.h>
+#include <kernel/kern_priv.h>
+#include <pci.h>
+#include <naviengine.h>
+#include <kernel/cache.h>
+#include "allocator.h"
+#include "pci-ne.h"
+#include "pci_priv.h"
+#include <platform.h>
+#include "t_pci.h"
+#include "../../naviengine_assp/naviengine_pci.h"
+
+#define TEST(X) __NK_ASSERT_ALWAYS(X)
+#define TEST_KERRNONE(X) if((X) !=KErrNone) {\
+								  Kern::Printf("Assertion Failed X=%d", (X)); FAULT();}
+
+#define FUNC_LOG() __KTRACE_OPT(KPCI, Kern::Printf(__PRETTY_FUNCTION__))
+
+ 
+void TestAllocator();
+
+/**
+So that the test app can get notification
+when PCI DChunks' cleanup operation has run
+we will replace their cleanup object with this
+one, which will call the original object's destroy
+function as well completing a notification
+*/
+class TPciCleanupWrapper : public TChunkCleanup
+	{
+public:
+
+	~TPciCleanupWrapper()
+		{
+		delete iOriginal;
+		Kern::DestroyClientRequest(iClientRequest);
+		iClient->Close(NULL);
+		}
+
+	static TPciCleanupWrapper* Create(TRequestStatus* aRequestStatus)
+		{
+		__KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Create aRequestStatus=0x%08x", aRequestStatus));
+		TClientRequest* request = NULL;
+		TInt r = Kern::CreateClientRequest(request);
+		if(r != KErrNone)
+			{
+			__KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Create Failed to create client request r=%d", r));
+			return NULL;
+			}
+
+		r = request->SetStatus(aRequestStatus);
+		if(r != KErrNone)
+			{
+			__KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Create Failed to set status r=%d", r));
+			Kern::DestroyClientRequest(request);
+			return NULL;
+			}
+
+		return new TPciCleanupWrapper(request);
+		}
+
+	/**
+	Insert the cleanup object into aChunk, remembering
+	the original one
+
+	@param aChunk a chunk known to have TChunkCleanup derived cleanup object
+	*/
+	void Insert(DChunk* aChunk)
+		{
+		__KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Insert aChunk=0x%08x", aChunk));
+		__NK_ASSERT_DEBUG(aChunk);
+		__KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper replace 0x%08x with 0x%08x", aChunk->iDestroyedDfc, this));
+		iOriginal = static_cast<TChunkCleanup*>(aChunk->iDestroyedDfc);
+
+		__NK_ASSERT_DEBUG(iOriginal);
+		aChunk->iDestroyedDfc = this;
+		}
+
+	/**
+	Run the original object's destroy method
+	then notify client
+	*/
+	void Destroy()
+		{
+		__KTRACE_OPT(KPCI, Kern::Printf("TPciCleanupWrapper::Destroy\n"));
+		iOriginal->Destroy();
+
+		__NK_ASSERT_ALWAYS(iClientRequest->IsReady());
+		Kern::QueueRequestComplete(iClient, iClientRequest, KErrNone);
+		}
+
+private:
+	TPciCleanupWrapper(TClientRequest* aRequest)
+		:TChunkCleanup(), iOriginal(NULL), iClientRequest(aRequest), iClient(&Kern::CurrentThread())
+		{
+		__ASSERT_CRITICAL;
+		iClient->Open(); //don't allow thread object to be destroyed before we signal
+		}
+
+
+	TChunkCleanup* iOriginal;
+	TClientRequest* iClientRequest;
+	DThread* const iClient;
+	};
+
+
+
+
+//This information will come from the pci driver
+//if this code is ever made generic
+TPciTestInfo KTestInfo =
+	{
+	TPciDevice(0x1033, 0x35, 0),
+	TPciTestInfo::TAddrSpaceTest(0, 0x00351033, 0),
+	TPciTestInfo::TAddrSpaceTest(KPciBar0, 0, 0xFFF),
+	0,
+	TPciTestInfo::TAddrSpaceTest(0x34, 0x2EDF, 0),
+	TPciTestInfo::TAddrSpaceTest(0x20, 0, 0xF),
+	KNeBridgeNumberOfBars
+	};
+
+/**
+Class for a DChunk to remove a DPlatHwChunk chunk
+*/
+class TPciPlatChunkCleanup : public TChunkCleanup
+	{
+public:
+	TPciPlatChunkCleanup(TInt aPciFunction, DPlatChunkHw* aPciPlatChunk);
+	virtual void Destroy();
+public:
+	TInt iPciFunction;
+	DPlatChunkHw* iPciChunk;
+	};
+
+TPciPlatChunkCleanup::TPciPlatChunkCleanup(TInt aPciFunction,  DPlatChunkHw* aPciPlatChunk)
+	: TChunkCleanup(), iPciFunction(aPciFunction), iPciChunk(aPciPlatChunk)
+	{
+	}
+
+void TPciPlatChunkCleanup::Destroy()
+	{	
+	__KTRACE_OPT(KPCI, Kern::Printf("SHAREDCHUNK ChunkDestroyed DFC\n"));
+	TInt r = Pci::RemoveChunk(iPciFunction, iPciChunk);
+	__NK_ASSERT_ALWAYS(r==KErrNone);
+	}
+
+/**
+Cleanup class to remove the mapping for an externally
+mapped chunk
+*/
+class TPciMappedChunkCleanup : public TChunkCleanup
+	{
+public:
+	TPciMappedChunkCleanup (TInt aPciFunction,TUint32 aPhysicalAddress);
+	virtual void Destroy();
+public:
+	TInt iPciFunction;
+	TUint32 iPhysicalAddress;
+	};
+
+TPciMappedChunkCleanup::TPciMappedChunkCleanup(TInt aPciFunction,TUint32 aPhysicalAddress)
+	: TChunkCleanup(), iPciFunction(aPciFunction),iPhysicalAddress(aPhysicalAddress)
+	{	
+	}
+
+void TPciMappedChunkCleanup::Destroy()
+	{	
+	//remove mapping
+	TInt r = Pci::RemoveMapping(iPciFunction, iPhysicalAddress);
+	__NK_ASSERT_ALWAYS(r==KErrNone);	
+	__KTRACE_OPT(KPCI, Kern::Printf("MAPPING REMOVED ChunkDestroyed DFC\n"));
+	}
+
+class DPciTestChannel : public DLogicalChannelBase
+	{
+public:
+	DPciTestChannel();
+	virtual ~DPciTestChannel();
+	TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer);
+	virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2);
+
+private:
+	TInt OpenPciDChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus);		
+	TInt OpenPciPlatHwChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus);	
+	TInt OpenPciMappedChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus);	 
+	TInt CreateSharedChunk(TInt aPciChunkSize, TUint32 aAttributes, DChunk*& aChunk, TLinAddr& aVirt, TPhysAddr& aPhysicalAddress);
+	TInt OpenPciWindowChunk();
+	void RunUnitTests();
+
+private:
+	const TPciTestInfo& iTestInfo;
+	TInt iFunction; ///< PCI function number this channel is associated with
+	};
+
+DPciTestChannel::DPciTestChannel()
+	: iTestInfo(KTestInfo), iFunction(-1)
+	{
+	FUNC_LOG();
+	}
+
+DPciTestChannel::~DPciTestChannel()
+	{
+	FUNC_LOG();
+	}
+
+TInt DPciTestChannel::DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer)
+	{
+	if(aInfo == NULL)
+		return KErrNone; //Not a device specific channel
+
+	TPciDevice dev;
+	TPckg<TPciDevice> devPckg(dev);
+	TInt r = Kern::ThreadDesRead(&Kern::CurrentThread(), aInfo, devPckg, 0, KChunkShiftBy0);
+	if(r != KErrNone)
+		return r;
+
+	NKern::ThreadEnterCS();
+	RArray<TInt> indicies;
+	r = Pci::Probe(indicies, dev.iVendorId, dev.iDeviceId);
+	
+	if((KErrNone == r) && (dev.iInstance < indicies.Count()))
+		{
+		iFunction = indicies[dev.iInstance];
+		}
+	else
+		{
+		r = KErrNotFound;
+		}
+	
+	indicies.Close();
+	NKern::ThreadLeaveCS();
+	return r;
+	}
+
+TInt DPciTestChannel::Request(TInt aFunction, TAny* a1, TAny* a2)
+	{
+	switch (aFunction)
+		{
+		case EGetTestInfo:
+			{
+			TDes8& dest(*(TDes8*)a1);
+			TPckgC<TPciTestInfo> info(iTestInfo);
+			Kern::KUDesPut(dest, info);
+			return KErrNone;
+			}
+		case EAccessConfigSpace:
+			{
+			TPckgBuf<TUserConfigSpace> pckg;
+			Kern::KUDesGet(pckg, *reinterpret_cast<TDes8*>(a1));
+		
+			TAddrSpace* configSpace = Pci::GetConfigSpace(iFunction);
+			if(configSpace == NULL)
+				{
+				Kern::PanicCurrentThread(KPciTest, KErrGeneral);
+				return KErrGeneral;
+				}
+			return pckg().KRun(*configSpace);
+			}
+		case EAccessMemorySpace:
+			{
+			TPckgBuf<TUserMemorySpace> pckg;
+			Kern::KUDesGet(pckg, *reinterpret_cast<TDes8*>(a1));
+
+			TAddrSpace* memSpace = Pci::GetMemorySpace(iFunction, pckg().BarIndex());
+			if(memSpace == NULL)
+				{
+				Kern::PanicCurrentThread(KPciTest, KErrGeneral);
+				return KErrGeneral;
+				}
+			return pckg().KRun(*memSpace);
+			}
+		case EOpenPciWindowChunk:
+			{				
+			TInt rHandle = 0;				
+			rHandle = OpenPciWindowChunk();		
+			return rHandle;			
+			}
+		case EOpenPciDChunk: //Fall-through
+		case EOpenPciPlatHwChunk:
+		case EOpenPciMappedChunk:
+			{				
+				TPckgBuf<TPciChunkCreateInfo> pckg;				
+				Kern::KUDesGet(pckg, *reinterpret_cast<TDes8*>(a1));
+
+				TUint32 pciAddr;				
+				TInt rHandle = 0;				
+				switch (aFunction)
+					{
+				case EOpenPciDChunk:
+						{						
+						rHandle = OpenPciDChunk(pciAddr, pckg().iSize, pckg().iStatus);						
+						break;
+						}
+				case EOpenPciPlatHwChunk:
+						{						
+						rHandle = OpenPciPlatHwChunk(pciAddr, pckg().iSize, pckg().iStatus);				
+						break;
+						}
+				case EOpenPciMappedChunk:
+						{
+						rHandle = OpenPciMappedChunk(pciAddr, pckg().iSize, pckg().iStatus);					
+						break;
+						}
+				default:
+						{
+						FAULT();
+						}
+					}
+				//write back PCI address to user
+				umemput(pckg().iPciAddress,&pciAddr,sizeof(pciAddr));				
+				return rHandle;			
+			}
+		case ERunUnitTests:
+			{					
+			RunUnitTests();					
+			return KErrNone;		
+			}
+		default:
+			return KErrNotSupported;
+		}
+	}
+
+/**
+This function runs tests for the address allocator
+*/
+void DPciTestChannel::RunUnitTests()
+{
+	// Enter critical section 
+   	NKern::ThreadEnterCS();		
+	
+	TestAllocator();
+
+ 	// Finished
+	NKern::ThreadLeaveCS();
+}
+
+
+/**
+This function creates and opens a PCI DChunk and returns the PCI addresss
+@param aPciAddr on return contains the pci address
+@param aPciChunkSize contains the size of the PCI DChunk which is to be created
+*/
+TInt DPciTestChannel::OpenPciDChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus)
+{
+	//Chunk Attributes 
+	TChunkCreateInfo aInfo;
+	aInfo.iType = TChunkCreateInfo::ESharedKernelMultiple;
+	aInfo.iMapAttr = EMapAttrSupRw|EMapAttrFullyBlocking;
+	aInfo.iOwnsMemory = EFalse; // We'll be using our own devices memory
+	
+	DChunk* pciChunk;
+	pciChunk=NULL;	
+
+    // Enter critical section 
+	NKern::ThreadEnterCS();
+	
+	//Create DChunk
+	TInt r = Pci::CreateChunk(iFunction, pciChunk, aInfo,0,aPciChunkSize,aPciAddr);
+	if(r!=KErrNone)
+	{
+		// Failed to create DChunk	
+		__KTRACE_OPT(KPCI,Kern::Printf("Failed to create DChunk: Error code is=%d", r) );
+		NKern::ThreadLeaveCS(); // Finished
+		return r;		
+	}
+	else
+	{
+		TInt rHandle = KErrGeneral;
+		if(aStatus)
+			{
+			TPciCleanupWrapper* wrapper = TPciCleanupWrapper::Create(aStatus);
+			if(wrapper == NULL)
+				{
+				__KTRACE_OPT(KPCI,Kern::Printf("Creation of TPciCleanupWrapper failed"));
+				goto End;
+				}
+			wrapper->Insert(pciChunk);
+			}
+
+		__KTRACE_OPT(KPCI,Kern::Printf("Created DChunk: PCI_ADDRESS=0x%08x",aPciAddr));
+		rHandle = Kern::MakeHandleAndOpen(NULL, pciChunk);//Get DChunk handle	
+
+End:
+		pciChunk->Close(NULL);		// Close DChunk		
+		NKern::ThreadLeaveCS(); 	// Finished
+		return rHandle;
+	}
+}
+
+/**
+This function creates and opens a PCI DPlatChunk and returns the PCI addresss.
+A DPlatChunk is intially created and then a DChunk is set to point to the same 
+memory as the DPlatChunk.This is done so that it can be accessed on the user side. 
+@param aPciAddr on return contains the pci address
+@param aPciChunkSize contains the size of the PCI PlatHwChunk which is to be created
+*/
+TInt DPciTestChannel::OpenPciPlatHwChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus)
+{
+	TUint32 pciPhysicalAddr;
+	TUint32 pciChunkMapAttr;	
+	TLinAddr pciChunkKernelAddr;
+
+	DPlatChunkHw* pciPlatChunk;
+	pciPlatChunk=NULL;	
+
+    // Enter critical section 
+	NKern::ThreadEnterCS();
+	
+	//Create DPlatChunkHw
+	TInt r = Pci::CreateChunk(iFunction,pciPlatChunk,aPciChunkSize,(EMapAttrSupRw|EMapAttrFullyBlocking),aPciAddr);
+	if(r!=KErrNone)
+	{
+		// Failed to create DPlatChunkHw	
+		__KTRACE_OPT(KPCI,Kern::Printf("Failed to create DPlatChunkHw chunk: Error code is=%d", r));
+		NKern::ThreadLeaveCS(); // Finished
+		return r;	
+	}
+
+	//Get physical addresss
+	pciPhysicalAddr	= pciPlatChunk->PhysicalAddress();
+	
+	// Create DChunk cleanup object
+	TPciPlatChunkCleanup* cleanup = new TPciPlatChunkCleanup(iFunction, pciPlatChunk);
+	if(!cleanup)
+    {
+		pciPlatChunk->Close(NULL); //close pciPlatChunk
+		NKern::ThreadLeaveCS();
+		return KErrNoMemory;
+    }
+	
+	//Chunk Attributes  for DChunk
+	TChunkCreateInfo chunkinfo;
+	chunkinfo.iType         = TChunkCreateInfo::ESharedKernelMultiple;    
+	chunkinfo.iMaxSize      = 0x4000;
+	chunkinfo.iMapAttr      = EMapAttrSupRw|EMapAttrFullyBlocking; // No caching
+	chunkinfo.iOwnsMemory   = EFalse; // Use memory from system's free pool
+	chunkinfo.iDestroyedDfc = cleanup;
+
+	DChunk* pciDChunk;
+  
+	//Create DChunk
+	r = Kern::ChunkCreate(chunkinfo, pciDChunk, pciChunkKernelAddr, pciChunkMapAttr);
+	if(r!=KErrNone)
+    {
+		pciPlatChunk->Close(NULL); //close pciPlatChunk
+		delete cleanup;
+		NKern::ThreadLeaveCS();
+		return r;
+	}
+
+	pciPlatChunk=NULL; // pciDChunk now owns chunk        	
+
+	if(aStatus)
+		{
+		TPciCleanupWrapper* wrapper = TPciCleanupWrapper::Create(aStatus);
+		if(wrapper == NULL)
+			{
+			pciDChunk->Close(NULL);	// Close pciDChunk	
+			NKern::ThreadLeaveCS(); // Finished
+			return KErrGeneral;
+			}
+		wrapper->Insert(pciDChunk);
+		}
+
+	//Commit memory to a DChunk using DPlatChunkHw physical address
+	r = Kern::ChunkCommitPhysical(pciDChunk,0,aPciChunkSize,pciPhysicalAddr);
+	if(r!=KErrNone)
+	{
+		// Failed to commit memory
+		Kern::Printf("Commit failed: Error code is=%d", r);
+		__KTRACE_OPT(KPCI,Kern::Printf("Commit failed: Error code is=%d", r));
+
+		// Close chunk, which will then get deleted at some point
+		Kern::ChunkClose(pciDChunk);
+		NKern::ThreadLeaveCS();
+		return r;
+	}	
+	
+	//Close pciPlatChunk using pciDChunk as pciDChunk now owns it
+	const TInt rHandle = Kern::MakeHandleAndOpen(NULL, pciDChunk); //Get DChunk handle
+	pciDChunk->Close(NULL);	// Close pciDChunk	
+	NKern::ThreadLeaveCS(); // Finished
+	return rHandle;   	
+}
+
+/**
+This function creates and opens a PCI mapped DChunk and returns the PCI addresss
+@param aPciAddr on return contains the pci address
+@param aPciChunkSize contains the size of the PCI DChunk which is to be created
+*/
+TInt DPciTestChannel::OpenPciMappedChunk(TUint32& aPciAddr,TInt aPciChunkSize, TRequestStatus* aStatus)
+{
+	TLinAddr virt=NULL;
+	TPhysAddr physicalAddress=NULL;
+	DChunk* pciChunk=NULL;
+	TUint32 pciAttributes=EMapAttrSupRw|EMapAttrFullyBlocking;
+
+	// Enter critical section 
+	NKern::ThreadEnterCS();	
+
+	//create DChunk
+	TInt r = CreateSharedChunk(aPciChunkSize, pciAttributes, pciChunk, virt, physicalAddress);
+	if(r!=KErrNone)
+	{
+	__KTRACE_OPT(KPCI,Kern::Printf("Create shared Chunk failed: Error code is=%d", r));
+	return r;
+	}
+	
+	__NK_ASSERT_ALWAYS(pciChunk);
+
+	//create mapping
+	r=Pci::CreateMapping(iFunction, physicalAddress, aPciChunkSize, aPciAddr);
+	if(r!=KErrNone)
+	{
+	pciChunk->Close(NULL);
+	__KTRACE_OPT(KPCI,Kern::Printf("Create mapping failed: Error code is=%d", r));
+	return r;
+	}	
+
+
+	// Create DChunk cleanup object
+	TPciMappedChunkCleanup* cleanup = new TPciMappedChunkCleanup(iFunction, physicalAddress);
+	if(!cleanup)
+		{
+			pciChunk->Close(NULL);
+			NKern::ThreadLeaveCS();
+			return KErrNoMemory;
+		}
+
+	//must add the cleanup dfc to the chunk after creation
+	//since the cleanup parameters aren't known
+	//till after creating it and allocating memory to it
+	pciChunk->iDestroyedDfc = cleanup;
+
+	if(aStatus)
+		{
+		TPciCleanupWrapper* wrapper = TPciCleanupWrapper::Create(aStatus);
+		if(wrapper == NULL)
+			{
+			pciChunk->Close(NULL);	// Close pciDChunk	
+			NKern::ThreadLeaveCS();
+			return KErrGeneral;
+			}
+		wrapper->Insert(pciChunk);
+		}
+	
+	//Get DChunk handle
+	const TInt rHandle = Kern::MakeHandleAndOpen(NULL, pciChunk);	
+	
+	// Close DChunk		
+	pciChunk->Close(NULL);		    
+	
+	// Finished
+	NKern::ThreadLeaveCS(); 	
+	return rHandle;
+}
+
+/**
+This function creates and opens a PCI Window Chunk and returns the PCI Window addresss
+@param aPciChunkSize contains the size of the PCI Window DChunk which is to be created
+*/
+TInt DPciTestChannel::OpenPciWindowChunk()
+{
+	TUint32 pciChunkMapAttr;	
+	TLinAddr pciChunkKernelAddr=NULL;
+	DChunk* pciWindowChunk=NULL;	
+
+	//Chunk Attributes  for DChunk
+	TChunkCreateInfo chunkinfo;
+	chunkinfo.iType         = TChunkCreateInfo::ESharedKernelMultiple;    
+	chunkinfo.iMaxSize      = 0x2000;
+	chunkinfo.iMapAttr      = EMapAttrSupRw|EMapAttrFullyBlocking; // No caching
+	chunkinfo.iOwnsMemory   = EFalse; // Use memory from system's free pool
+
+	 // Enter critical section 
+	NKern::ThreadEnterCS();
+	
+	//Create shared chunk for PCI window
+	TInt r = Kern::ChunkCreate(chunkinfo, pciWindowChunk, pciChunkKernelAddr, pciChunkMapAttr);
+	if(r!=KErrNone)
+    {
+		// Failed to create DChunk	
+		__KTRACE_OPT(KPCI,Kern::Printf("Failed to create DChunk: Error code is=%d", r) );		
+		NKern::ThreadLeaveCS();
+		return r;
+	}
+
+	//This address is PSL specific. This will have to be changed
+	//if d_pci.cpp is ever made generic
+	TUint32 pciPhysicalAddr = KHwUSBHPhys; // Internal PCI window address
+
+	//Commit memory to a DChunk using  Internal PCI window address
+	r = Kern::ChunkCommitPhysical(pciWindowChunk,0,KHwUSBHInternalPciWindowSize, pciPhysicalAddr);
+	if(r!=KErrNone)
+	{
+		// Failed to commit memory
+		Kern::Printf("Commit failed: Error code is=%d", r);
+		__KTRACE_OPT(KPCI,Kern::Printf("Commit failed: Error code is=%d", r));
+
+		// Close chunk, which will then get deleted at some point
+		Kern::ChunkClose(pciWindowChunk);
+		NKern::ThreadLeaveCS();
+		return r;
+	}		
+
+	//Close pciPlatChunk using pciDChunk as pciDChunk now owns it
+	const TInt rHandle = Kern::MakeHandleAndOpen(NULL, pciWindowChunk); //Get PCI Window DChunk handle
+	pciWindowChunk->Close(NULL);	// Close pci window chunk	
+	NKern::ThreadLeaveCS(); // Finished
+	return rHandle;   	
+}
+
+/**
+This function creates and opens a shared chunk. The chunk is then commited to a contiguous memory
+@param aPciChunkSize contains the size of the PCI DChunk which is to be created
+@param aAttributes  on return, this is set to the mmu mapping attributes used for the chunk
+@param aChunk on return, a reference to the shared chunk
+@param aVirt on return, this is set to the virtual address shared chunk
+@param aPhysicalAddress on return, this is set to the physical address of the first page of memory
+	   which was committed.
+*/
+TInt DPciTestChannel::CreateSharedChunk(TInt aPciChunkSize, TUint32 aAttributes, DChunk*& aChunk, TLinAddr& aVirt, TPhysAddr& aPhysicalAddress)
+{
+	__NK_ASSERT_DEBUG(aChunk==NULL);
+	aPciChunkSize = Kern::RoundToPageSize(aPciChunkSize);
+	DChunk* pC=NULL;
+
+	// Enter critical section 
+	NKern::ThreadEnterCS();
+
+	//Chunk Attributes  for DChunk
+	TChunkCreateInfo info;
+	info.iType=TChunkCreateInfo::ESharedKernelSingle;
+	info.iMaxSize=aPciChunkSize;
+	info.iMapAttr=aAttributes;
+	info.iOwnsMemory=ETrue;
+
+	//Create DChunk
+	TInt r=Kern::ChunkCreate(info, pC, aVirt, aAttributes);
+	if(r!=KErrNone)
+		{
+		NKern::ThreadLeaveCS();
+		return r;
+		}
+	//Commit DChunk to Contiguous memory
+	r = Kern::ChunkCommitContiguous(pC, 0, aPciChunkSize, aPhysicalAddress);
+	if(r==KErrNone)
+		{
+			aChunk=pC;		
+		}
+	else
+		{
+		Kern::ChunkClose(pC);
+		__KTRACE_OPT(KPCI,Kern::Printf("Commit DChunk to Contiguous memory Failed : Error code is=%d",r));
+		return r;
+		}
+
+	NKern::ThreadLeaveCS(); // Finished
+	__KTRACE_OPT(KPCI, Kern::Printf("Created SC: size=0x%08x, virtual= 0x%08x, phys=0x%08x", aPciChunkSize, aVirt, aPhysicalAddress));	
+	return r;
+}
+
+class DPciDevice : public DLogicalDevice
+	{
+public:
+	DPciDevice();
+	~DPciDevice();
+	TInt Install();
+	void GetCaps(TDes8& aDes) const;
+	TInt Create(DLogicalChannelBase*& aChannel);
+	};
+
+DPciDevice::DPciDevice()
+	{
+	FUNC_LOG();
+	}
+
+DPciDevice::~DPciDevice()
+	{
+	FUNC_LOG();
+	}
+
+TInt DPciDevice::Install()
+	{
+	return SetName(&KPciLddFactory);
+	}
+
+void DPciDevice::GetCaps(TDes8&) const
+	{
+	}
+
+TInt DPciDevice::Create(DLogicalChannelBase*& aChannel)
+	{
+	aChannel = new DPciTestChannel;
+	return aChannel ? KErrNone : KErrNoMemory;
+	}
+
+/****************************************
+TUserPciSpace
+*/
+
+/**
+Decides what action to run based on contents of class
+*/
+TUint TUserPciSpace::KRun(TAddrSpace& aAddrSp)
+	{
+
+	//this could be reworked as a function pointer
+	//table, but this might be clearer
+	switch(iBitWidth)
+		{
+	case 8:
+			{
+			switch(iOperation)
+				{
+			case ERead:
+					{
+					return aAddrSp.Read8(iOffset);
+					}
+			case EWrite:
+					{
+					aAddrSp.Write8(iOffset, iWriteValue);
+					return KErrNone;
+					}
+			case EModify:
+					{
+					aAddrSp.Modify8(iOffset, iClearMask, iSetMask);
+					return KErrNone;
+					}
+			default:
+					{
+					Kern::PanicCurrentThread(KPciTest, KErrNotReady);
+					}
+				}
+			}
+	case 16:
+			{
+			switch(iOperation)
+				{
+			case ERead:
+					{
+					return aAddrSp.Read16(iOffset);
+					}
+			case EWrite:
+					{
+					aAddrSp.Write16(iOffset, iWriteValue);
+					return KErrNone;
+					}
+			case EModify:
+					{
+					aAddrSp.Modify16(iOffset, iClearMask, iSetMask);
+					return KErrNone;
+					}
+			default:
+					{
+					Kern::PanicCurrentThread(KPciTest, KErrNotReady);
+					}
+				}
+			}
+	case 32:
+			{
+			switch(iOperation)
+				{
+			case ERead:
+					{
+					return aAddrSp.Read32(iOffset);
+					}
+			case EWrite:
+					{
+					aAddrSp.Write32(iOffset, iWriteValue);
+					return KErrNone;
+					}
+			case EModify:
+					{
+					aAddrSp.Modify32(iOffset, iClearMask, iSetMask);
+					return KErrNone;
+					}
+			default:
+					{
+					Kern::PanicCurrentThread(KPciTest, KErrNotReady);
+					}
+				}
+			}
+	default:
+			{
+			Kern::PanicCurrentThread(KPciTest, KErrArgument);
+			}
+			
+		}
+
+	//unreachable return
+	return KMaxTUint;
+	}
+
+//stub implementation for kernel side
+TUint TUserConfigSpace::Call()
+		{
+		FAULT();
+		return 0;
+		} 
+
+TUserPciSpace* TUserConfigSpace::Clone() const
+		{
+		FAULT();
+		return 0;
+		} 
+
+//stub implementation for kernel side
+TUint TUserMemorySpace::Call()
+		{
+		FAULT();
+		return 0;
+		} 
+
+TUserPciSpace* TUserMemorySpace::Clone() const
+		{
+		FAULT();
+		return 0;
+		} 
+
+void TestAllocator()
+	{
+	__KTRACE_OPT(KPCI, Kern::Printf("Testing address allocator"));
+	TAddressAllocator allocator(0x80000000); //2 GB
+	TLinAddr rcvdAddr=NULL;
+	TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) );
+	TEST(0x0 ==rcvdAddr);
+	TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x100) );
+	TEST(0x100 ==rcvdAddr);
+	TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) );
+	TEST(0x10 ==rcvdAddr);
+	TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) );
+	TEST(0x20 ==rcvdAddr);
+	//test deallocating
+	TEST_KERRNONE(allocator.DeAllocate(0x0));
+	TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) );
+	TEST(0x000 ==rcvdAddr);
+
+	TEST_KERRNONE(allocator.DeAllocate(0x100));
+	TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x100) );
+	TEST(0x100 ==rcvdAddr);
+
+	TEST_KERRNONE(allocator.DeAllocate(0x10));
+	TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x10) );
+	TEST(0x10 ==rcvdAddr);
+
+	TEST_KERRNONE(allocator.DeAllocate(0x20));
+	TEST_KERRNONE(allocator.Allocate(rcvdAddr,0x20) );
+	TEST(0x20 ==rcvdAddr);
+
+	TEST(allocator.DeAllocate(0x40)==KErrNotFound);
+	TEST_KERRNONE(allocator.DeAllocate(0x100));
+	TEST_KERRNONE(allocator.DeAllocate(0x20));
+	TEST_KERRNONE(allocator.DeAllocate(0x0));
+	TEST_KERRNONE(allocator.DeAllocate(0x10));
+	}
+
+
+DECLARE_STANDARD_LDD()
+	{
+	return new DPciDevice;
+	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/naviengine/navienginebsp/ne1_tb/test/pci/t_pci.cpp	Wed Sep 15 13:26:16 2010 +0300
@@ -0,0 +1,1087 @@
+// 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:
+// This is a test for the PCI driver, so far implemented only on the
+// Naviengine platform. It aims to test:
+//	-That known values of data in config and memory space, on a given
+//	device can be read as expected.
+//	-That data can be written and modified in config and memory space
+//	-PCI memory buffers mapped or allocated by the PCI driver work as
+//	expected. These are
+//		-DChunk created by PCI driver and accessible from PCI
+//		-DPlatHwChunk created by PCI driver and accessible from PCI
+//		-DChunk created externally, then mapped in to PCI memory space
+//	There are tests to:
+//		- Create and close each buffer. Heap checking ensures proper
+//		cleanup
+//		- Create and close multiple buffers from multiple threads.
+//		This is an SMP focused test to check that the implementation
+//		of the chunk manager and allocator in the driver are thread
+//		safe. The tests should pass without triggering any assertions in
+//		the driver's invariance checks.
+//		- Write to buffers from software, and read back via the
+//		system to PCI window, and vice-versa -- a loop-back test.
+//		This checks that PCI buffers are indeed accessible to PCI devices.
+//
+// The tests require several pieces of PSL specific information:
+//	- A TPciDevice containing the vendor and device IDs of a PCI device
+//	to use for testing.
+//	- TAddrSpaceTests which identify regions of a device's config and
+//	memory space with known values, or which are known to be writable.
+//
+//	The test driver grants access to the PCI API with the following
+//	constructs: 
+//	- TUserConfigSpace and TUserMemorySpace, derived from TUserPciSpace,
+//	which are user side equivalents of kernel-side objects allowing
+//	accesses of different sizes to a PCI device's config space or
+//	memory space.
+//	- RPciChunk which is derived from and RChunk and corresponds to
+//	a kernel-side DChunk, which in turn corresponds to a PCI chunk or
+//	buffer. The test driver uses these for all PCI chunk types (a
+//	"wrapper" DChunk is used to map the memory of a PCI DPlatHwChunk
+//	to user side).
+//
+//	Known Issues:
+//	The test driver d_pci is intended to be platform independent but
+//	for now still contains some PSL specific information .eg the test
+//	info structure (which should really be passed up from the PSL) and
+//	the address and size of the system to pci window. For now the
+//	test driver code will remain in the Naviengine baseport directory.
+//	If the PCI driver is ever ported to a new platform this can be
+//	rectified.
+//	
+//
+//
+#include <e32std.h>
+#define __E32TEST_EXTENSION__
+#include <e32test.h>
+#include "t_pci.h"
+#include <assp/naviengine/pci.h>
+
+#define __E32TEST_EXTENSION__
+#include <e32test.h>
+#include <e32svr.h>
+#include <e32des8.h>
+#include <e32des8_private.h>
+#include <e32cmn.h>
+#include <e32cmn_private.h>
+#include <e32std.h>
+#include <e32std_private.h>
+    
+
+_LIT(KPciPanicCat, "test_thread.h");
+
+static const TInt KPciHeapSize=0x2000;
+
+enum TPciPanicCode
+	{
+	EThreadCreateFailed
+	};
+
+/**
+A utility class for running functions in other threads/processes
+*/
+class TTestRemote
+	{
+public:
+	virtual TInt WaitForExitL() = 0;
+	virtual ~TTestRemote()
+		{}
+
+	virtual void Rendezvous(TRequestStatus& aStatus) = 0;
+
+protected:
+	TTestRemote()
+		{}
+
+	static TInt RunFunctor(TAny* aFunctor)
+		{
+		TFunctor& functor = *(TFunctor*)aFunctor;
+		functor();
+		return KErrNone;
+		}
+
+	TRequestStatus iLogonStatus;
+	static TInt iCount;
+	};
+TInt TTestRemote::iCount=0;
+
+class TTestThread : public TTestRemote
+	{
+public:
+	TTestThread(const TDesC& aName, TThreadFunction aFn, TAny* aData, TBool aAutoResume=ETrue)
+		{
+		Init(aName, aFn, aData, aAutoResume);
+		}
+
+	/**
+	Run aFunctor in another thread
+	*/
+	TTestThread(const TDesC& aName, TFunctor& aFunctor, TBool aAutoResume=ETrue)
+		{
+		Init(aName, RunFunctor, &aFunctor, aAutoResume);
+		}
+
+	~TTestThread()
+		{
+		//RTest::CloseHandleAndWaitForDestruction(iThread);
+		iThread.Close();
+		}
+
+	void Resume()
+		{
+		iThread.Resume();
+		}
+
+	/**
+	If thread exited normally, return its return code
+	Otherwise, leave with exit reason
+	*/
+	virtual TInt WaitForExitL()
+		{
+		User::WaitForRequest(iLogonStatus);
+		const TInt exitType = iThread.ExitType();
+		const TInt exitReason = iThread.ExitReason();
+
+		__ASSERT_ALWAYS(exitType != EExitPending, User::Panic(_L("TTestThread"),0));
+
+		if(exitType != EExitKill)
+			User::Leave(exitReason);
+
+		return exitReason;
+		}
+
+	virtual void Rendezvous(TRequestStatus& aStatus)
+		{
+		iThread.Rendezvous(aStatus);
+		}
+
+private:
+	void Init(const TDesC& aName, TThreadFunction aFn, TAny* aData, TBool aAutoResume)
+		{
+		TKName name(aName);
+		name.AppendFormat(_L("-%d"), iCount++);	
+		TInt r=iThread.Create(name, aFn, KDefaultStackSize, KPciHeapSize, KPciHeapSize, aData);
+		if(r!=KErrNone)
+			{
+			RDebug::Printf("RThread::Create failed, code=%d", r);
+			User::Panic(KPciPanicCat, EThreadCreateFailed);
+			}
+		
+		iThread.Logon(iLogonStatus);
+		__ASSERT_ALWAYS(iLogonStatus == KRequestPending, User::Panic(_L("TTestThread"),0));
+
+		if(aAutoResume)
+			iThread.Resume();
+		}
+
+	RThread iThread;
+	};
+
+class CTest : public CBase, public TFunctor
+	{
+public:
+	~CTest()
+		{
+		iName.Close();
+		}
+
+	virtual void operator()()
+		{
+		RTest test(iName);
+		test.Start(iName);
+		for(TInt i=0; i<iIterations; i++)
+			{
+			test.Next(iName);
+			RunTest();
+			}
+		test.End();
+		}
+
+	virtual void RunTest() = 0; 
+
+	virtual CTest* Clone() const = 0;
+
+	const TDesC& Name() const
+		{
+		return iName;
+		}
+
+protected:
+	CTest(const TDesC& aName, TInt aIterations)
+		:iIterations(aIterations)
+		{
+		iName.CreateL(aName);
+		}
+
+
+	
+	CTest(const CTest& aOther)
+		:iIterations(aOther.iIterations)
+		{
+		iName.CreateL(aOther.iName);
+		}
+
+	//It would be useful to have an RTest member, but this can't be
+	//initialised untill the new thread is running as it will refer to
+	//the creating thread
+	RBuf iName;
+	const TInt iIterations; 
+	};
+
+/**
+Make aNumberOfThreads copies of aTest and run
+each in its own thread
+
+@param test Reference to test object
+@param aTest Referance
+*/
+void MultipleTestRun(RTest& test, const CTest& aTest, TInt aNumberOfThreads)
+	{
+	RPointerArray<CTest> testArray;
+	RPointerArray<TTestThread> threadArray;
+
+	for(TInt i=0; i<aNumberOfThreads; i++)
+		{		
+		test.Printf(_L("Create test thread"));
+		CTest* newTest = aTest.Clone();
+		test_NotNull(newTest);
+
+		TTestThread* thread = new TTestThread(aTest.Name(), *newTest);
+		test_NotNull(thread);
+
+		threadArray.AppendL(thread);
+		testArray.AppendL(newTest);
+		}
+
+	const TInt count = threadArray.Count();
+	for(TInt j=0; j<count; j++)
+		{
+		TTestThread* thread = threadArray[j];
+		
+		TInt r = KErrNone;
+		TRAPD(leaveCode, r = thread->WaitForExitL());
+		if(leaveCode != KErrNone)
+			{
+			test.Printf(_L("Thread %d: Panic code:%d\n"), j, leaveCode);
+			test_KErrNone(leaveCode);
+			}
+
+		if(r!=KErrNone)
+			{
+			test.Printf(_L("Thread Number %d\n"), j);
+			test_KErrNone(r);
+			}
+		}
+	
+	threadArray.ResetAndDestroy();
+	threadArray.Close();
+
+	testArray.ResetAndDestroy();
+	testArray.Close();
+	}
+
+class RPci;
+/**
+Extends RChunk to hold the PCI address
+associated with a chunk.
+*/
+class RPciChunk: public RChunk
+	{
+public:
+	TUint PciBase()
+		{
+		return iPciBaseAddr;
+		}
+
+	/**
+	Return the PCI accessible size
+	*/
+	TInt Size() const
+		{
+		return iPciSize;
+		}
+
+private:
+	friend class RPci;
+	TUint iPciBaseAddr;
+	TInt iPciSize; //size of the region mapped into PCI
+	};
+
+typedef TInt (RPci::*ChunkOpenFn)(RPciChunk&, TInt, TRequestStatus*);
+
+class RPci : public RBusLogicalChannel
+	{
+public:
+	TInt Open();
+	TInt GetTestInfo(TPciTestInfo& aTestInfo);
+
+	TInt Open(const TPciDevice&);
+
+	TUint AccessConfigSpace(const TUserConfigSpace& aCs);
+	TUint AccessMemorySpace(const TUserMemorySpace& aMs);
+	TInt  OpenPciDChunk(RPciChunk& aPciChunk,TInt aPciChunkSize, TRequestStatus* aStatus=0);
+	TInt  OpenPciPlatHwChunk(RPciChunk& aPciHwChunk,TInt aPciChunkSize, TRequestStatus* aStatus=0);
+	TInt  OpenPciMappedChunk(RPciChunk& aPciMappedChunk,TInt aPciChunkSize, TRequestStatus* aStatus=0);	
+	TInt  OpenPciWindowChunk(RChunk& aPciWindowChunk);
+	TInt  RunUnitTests();
+private:	
+	TInt DoOpenPciChunk(RPciChunk& aPciChunk, TInt aPciChunkSize, TPciTestCmd aCmd, TRequestStatus* aStatus);
+	};
+
+inline TInt RPci::Open()
+	{
+	return DoCreate(KPciLddFactory, TVersion(), KNullUnit, NULL, NULL);
+	}
+
+inline TInt RPci::Open(const TPciDevice& aDevice) 
+	{
+	TPckgC<TPciDevice> devicePkg(aDevice);
+	return DoCreate(KPciLddFactory, TVersion(), KNullUnit, NULL, &devicePkg);
+	}
+
+inline TInt RPci::GetTestInfo(TPciTestInfo& aTestInfo)
+	{
+	TPckg<TPciTestInfo> info(aTestInfo);
+	return DoControl(EGetTestInfo, &info);
+	}
+
+inline TInt RPci::RunUnitTests()
+	{
+	return DoControl(ERunUnitTests);
+	}
+
+TUint RPci::AccessConfigSpace(const TUserConfigSpace& aCs)
+	{
+	TPckgC<TUserConfigSpace> pkg(aCs);
+	return DoControl(EAccessConfigSpace, &pkg);
+	}
+
+TUint RPci::AccessMemorySpace(const TUserMemorySpace& aMs)
+	{
+	TPckgC<TUserMemorySpace> pkg(aMs);
+	return DoControl(EAccessMemorySpace, &pkg);
+	}
+
+TInt RPci::OpenPciDChunk(RPciChunk& aPciChunk,TInt aPciChunkSize, TRequestStatus* aStatus)	
+	{	
+	return DoOpenPciChunk(aPciChunk, aPciChunkSize, EOpenPciDChunk, aStatus);
+	}
+
+TInt RPci::OpenPciPlatHwChunk(RPciChunk& aPciHwChunk,TInt aPciChunkSize, TRequestStatus* aStatus)	
+	{
+	return DoOpenPciChunk(aPciHwChunk, aPciChunkSize, EOpenPciPlatHwChunk, aStatus);
+	}
+
+TInt RPci::OpenPciMappedChunk(RPciChunk& aPciMappedChunk,TInt aPciChunkSize, TRequestStatus* aStatus)	
+	{
+	return DoOpenPciChunk(aPciMappedChunk, aPciChunkSize, EOpenPciMappedChunk, aStatus);
+	}
+
+TInt RPci::OpenPciWindowChunk(RChunk& aPciWindowChunk)
+	{	
+	TUint chunkHandle = DoControl(EOpenPciWindowChunk);			
+	return aPciWindowChunk.SetReturnedHandle(chunkHandle);
+	}
+
+TInt RPci::DoOpenPciChunk(RPciChunk& aPciChunk, TInt aPciChunkSize, TPciTestCmd aCmd, TRequestStatus* aStatus)
+	{
+	const TInt constPciChunkSize = aPciChunkSize;
+	TPciChunkCreateInfo info(constPciChunkSize, aPciChunk.iPciBaseAddr, aStatus);
+	TPckgC<TPciChunkCreateInfo> pkg(info);
+
+	TUint chunkHandle = DoControl(aCmd, &pkg);	
+	
+	const TInt r = aPciChunk.SetReturnedHandle(chunkHandle);
+	if(r == KErrNone)
+		{		
+		aPciChunk.iPciSize = constPciChunkSize;					
+		}
+	return r;
+	}
+
+TUserPciSpace::TUserPciSpace(RPci& aPci)
+	:iPci(&aPci)
+	{}
+
+TUserConfigSpace::TUserConfigSpace(RPci& aPci)
+	:TUserPciSpace(aPci)
+	{}
+
+TUint TUserConfigSpace::Call()
+	{
+	return iPci->AccessConfigSpace(*this);
+	}
+
+TUserPciSpace* TUserConfigSpace::Clone() const
+	{
+	return new TUserConfigSpace(*this);
+	}
+
+TUserMemorySpace::TUserMemorySpace(RPci& aPci, TInt aBarIndex)
+	:TUserPciSpace(aPci), iBarIndex(aBarIndex)
+	{}
+
+TUint TUserMemorySpace::Call()
+	{
+	return iPci->AccessMemorySpace(*this);
+	}
+
+TUserPciSpace* TUserMemorySpace::Clone() const
+	{
+	return new TUserMemorySpace(*this);
+	}
+
+/**
+Test address allocator
+*/
+TInt TestRunPciUnitTest(RPci& pci)
+	{		
+	return pci.RunUnitTests();
+	}
+
+
+/**
+Read from a defined address in memory or config space, compare against expected values.
+8,16, and 32 bit accesses performed.
+
+@param aSpace Object gving access to either the config or memory space of a PCI device
+@param aInfo Contains the address and expected value of a dword
+*/
+void TestReadAddressSpace(TUserPciSpace& aSpace, const TPciTestInfo::TAddrSpaceTest& aInfo, RTest& test, TBool aVerbose=EFalse)
+	{
+	const TUint os = aInfo.iOffset;
+	//Iterate over different widths, and possible
+	//subfields of 32 bit word
+	for(TInt bitWidth=32; bitWidth>=8; bitWidth>>=1)
+		{
+		const TInt numberOfFields = (32/bitWidth);
+		for(TInt i=0; i< numberOfFields; i++)
+			{
+			const TInt extraByteOffset = i * (bitWidth >> 3);
+			const TInt byteOffset = os + extraByteOffset;
+			if(aVerbose)
+				test.Printf(_L("Access bitWidth=%d byte offset=%d\n"), bitWidth, byteOffset);
+
+			const TUint expected = aInfo.Expected(bitWidth, byteOffset);
+			const TUint read = aSpace.Read(bitWidth, byteOffset);
+			if(aVerbose)
+				test.Printf(_L("expect 0x%08x, read 0x%08x\n"), expected, read);
+			test_Equal(expected, read);
+			}
+		}
+	}
+
+/**
+Verify writes and modifications to a defined address in memory or config space. 8,16, and 32 bit
+accesses performed.
+
+@param aSpace Object gving access to either the config or memory space of a PCI device
+@param aInfo Contains the address of a (at least partially) writable dword
+*/
+void TestWriteAddressSpace(TUserPciSpace& aSpace, TPciTestInfo::TAddrSpaceTest& aInfo, RTest& test, TBool aVerbose=EFalse)
+	{
+	const TUint original = aSpace.Read(32, aInfo.iOffset);
+	const TUint os = aInfo.iOffset;
+	TUint mask = ~aInfo.iReadOnlyMask;
+
+	//The pattern will be truncated when used with bit widths
+	//less than 32.
+	const TUint initPattern = 0xFFFFFFFF;
+
+	for(TInt bitWidth=32; bitWidth>=8; bitWidth>>=1)
+		{
+		const TUint pattern = initPattern >> (32-bitWidth);
+		const TInt numberOfFields = (32/bitWidth);
+		for(TInt i=0; i< numberOfFields; i++)
+			{
+			const TInt extraByteOffset = i * (bitWidth >> 3);
+			const TInt byteOffset = os + extraByteOffset;
+			if(aVerbose)
+				test.Printf(_L("Access bitWidth=%d byte offset=%d\n"), bitWidth, byteOffset);
+			//the full dword we expect
+			//currently assume that the unwritable bits will be 0
+			const TUint writeExpect = (pattern << (bitWidth * i) ) & mask; 
+			const TUint clearExpect = 0;
+						
+			//do write followed by clear
+			const TUint expect[] = {writeExpect, clearExpect};
+			const TUint write[] = {pattern, 0};
+			for(TInt n = 0; n < 2; n++)
+				{
+				aSpace.Write(bitWidth, byteOffset, write[n]);
+				TUint result = aSpace.Read(32, os);
+							
+				if(aVerbose)
+					test.Printf(_L("wrote 0x%08x, expect 0x%08x, read 0x%08x\n"),
+						write[n], expect[n], result);
+				test_Equal(expect[n], result);
+				}
+
+			//test Modify calls. Set then clear pattern
+			TUint set[] = {pattern, 0};
+			TUint clear[] = {0, pattern};
+
+			for(TInt m = 0; m < 2; m++)
+				{	
+				aSpace.Modify(bitWidth, byteOffset, clear[m], set[m]);
+				TUint result = aSpace.Read(32, os);
+						
+				if(aVerbose)
+					test.Printf(_L("clear 0x%08x, set 0x%08x,  expect 0x%08x, read 0x%08x\n"), clear[m], set[m], expect[m], result);
+				test_Equal(expect[m], result);
+				}
+			}
+		}
+
+	//restore orginal value or we will not be able to access device
+	aSpace.Write(32, os, original);
+	}
+
+
+/**
+Verify that a PCI DChunk can be opened and closed from user side
+
+@param pci  The RPci object to use
+@param test The RTest object to use
+@param aPciChunkSize The size of the DChunk which would be created
+*/
+void TestOpenAndCloseDChunk(RPci& pci,RTest& test,TInt aPciChunkSize)
+	{
+	RPciChunk testPciDChunk;
+
+	// Create and open Chunk
+	TRequestStatus status;
+	TInt r = pci.OpenPciDChunk(testPciDChunk,aPciChunkSize, &status);	
+	test_KErrNone(r);
+	
+	test(testPciDChunk.IsWritable());
+	test(testPciDChunk.IsReadable());
+
+	test.Printf(_L("PCI Chunk base = 0x%08x\n"), testPciDChunk.Base());
+	test.Printf(_L("PCI Chunk size = %d\n"), testPciDChunk.Size());
+	test.Printf(_L("PCI Address = 0x%08x\n"), testPciDChunk.PciBase());	
+
+	//Close Chunk
+	test.Next(_L("Close PCI Chunk handle"));	
+
+	RTest::CloseHandleAndWaitForDestruction(testPciDChunk);
+	User::WaitForRequest(status);
+	}
+
+/**
+Verify that a PCI PlatHwChunk can be opened and closed from user side
+
+
+@param pci  The RPci object to use
+@param test The RTest object to use
+@param aPciChunkSize The size of the PlatHwChunk which would be created
+*/
+void TestOpenAndClosePciPlatHwChunk(RPci& pci,RTest& test,TInt aPciChunkSize)
+	{
+	RPciChunk testPciPlatHwChunk;
+
+	// Create and open Chunk
+	TRequestStatus status;
+	TInt r = pci.OpenPciPlatHwChunk(testPciPlatHwChunk,aPciChunkSize, &status);	
+	test_KErrNone(r);
+	
+	test(testPciPlatHwChunk.IsWritable());
+	test(testPciPlatHwChunk.IsReadable());
+
+	test.Printf(_L("PCI Chunk base = 0x%08x\n"), testPciPlatHwChunk.Base());
+	test.Printf(_L("PCI Chunk size = %d\n"), testPciPlatHwChunk.Size());
+	test.Printf(_L("PCI Address = 0x%08x\n"), testPciPlatHwChunk.PciBase());	
+
+	//Close Chunk	
+	testPciPlatHwChunk.Close();
+	User::WaitForRequest(status);
+	test.Next(_L("Closed PCI PlatHwChunk handle"));	
+	}
+
+/**
+Verify that pci-mapped DChunk can be opended and closed form user side 
+
+@param pci  The RPci object to use
+@param test The RTest object to use
+@param aPciChunkSize The size of the pci-mapped DChunk which would be created
+*/
+void TestPciMapppedChunk(RPci& pci,RTest& test,TInt aPciChunkSize)
+	{
+	RPciChunk testPciMappedChunk;
+
+	// Create and open Chunk
+	TRequestStatus status;
+	TInt r = pci.OpenPciMappedChunk(testPciMappedChunk,aPciChunkSize, &status);	
+	test_KErrNone(r);
+	
+	test(testPciMappedChunk.IsWritable());
+	test(testPciMappedChunk.IsReadable());
+
+	test.Printf(_L("PCI Chunk base = 0x%08x\n"), testPciMappedChunk.Base());
+	test.Printf(_L("PCI Chunk size = %d\n"), testPciMappedChunk.Size());
+	test.Printf(_L("PCI Address = 0x%08x\n"), testPciMappedChunk.PciBase());	
+
+	//Close Chunk
+	testPciMappedChunk.Close();
+	User::WaitForRequest(status);
+	test.Next(_L("Closed PCI Mapped Chunk handle"));	
+	}
+
+/**
+Verify that an RChunk can be open to grant access to the internal PCI window from the user side
+
+@param pci  The RPci object to use
+@param test The RTest object to use
+*/
+void TestPciWindowChunk(RPci& pci,RTest& test)
+	{
+	RChunk testPciWindowChunk;
+
+	// Create and open DChunk
+	TInt r = pci.OpenPciWindowChunk(testPciWindowChunk);	
+	test_KErrNone(r);
+	
+	test(testPciWindowChunk.IsWritable());
+	test(testPciWindowChunk.IsReadable());
+
+	test.Printf(_L("PCI Window Chunk base = 0x%08x\n"), testPciWindowChunk.Base());
+	test.Printf(_L("PCI Window Chunk size = %d\n"), testPciWindowChunk.Size());
+	
+	//Close Chunk
+	testPciWindowChunk.Close();
+	test.Next(_L("Closed PCI Window Chunk handle"));	
+	}
+
+
+class CPciTest : public CTest
+	{
+protected:
+	CPciTest(const TDesC& aName, TInt aIterations, RPci& aDevice)
+		: CTest(aName, aIterations), iDevice(aDevice)
+		{}
+
+	RPci iDevice;
+	};
+
+/**
+Each instance of test will open a chunk, using the function specified in
+the template argument, FUNC.
+
+The total number of chunks that can be opened by all instances is limited
+by iMaxCount.
+
+All intances of the test will hold their chunk open until iMaxCount has
+been reached.
+*/
+template<ChunkOpenFn FUNC>
+class CPciOpenChunkTest : public CPciTest
+	{
+public:
+	CPciOpenChunkTest(const TDesC& aName, TInt aIterations, RPci& aDevice,
+			RSemaphore aSemOpen, RSemaphore aSemClose, RFastLock aLock, TInt aMaxCount)
+		:CPciTest(aName, aIterations, aDevice),
+			iSemOpen(aSemOpen), iSemClose(aSemClose), iLock(aLock), iMaxCount(aMaxCount)
+		{
+		}
+
+	virtual void RunTest()
+		{
+		RTest test(iName);
+		RPciChunk chunk;
+
+		iSemOpen.Wait();
+		TRequestStatus status;
+		const TInt chunkSize = 0x400;
+		//open chunk by calling FUNC
+		TInt r = ((iDevice).*(FUNC))(chunk, chunkSize, &status);
+		test_KErrNone(r);
+
+		iLock.Wait();
+		iOpenCount++;
+		test.Printf(_L("Opened chunk %d\n"), iOpenCount);
+		if(iOpenCount == iMaxCount)
+			{
+			test.Printf(_L("Opened=%d, max=%d: Allow chunks to close\n"), iOpenCount, iMaxCount);
+			//release all waiting threads
+			//plus 1 preincrement so this
+			//thread also passes
+			iSemClose.Signal(iOpenCount);			
+			iOpenCount = 0;
+			}	
+		iLock.Signal();
+
+
+		iSemClose.Wait();
+		chunk.Close();
+		User::WaitForRequest(status);
+
+		// permit another chunk to be opened  
+		iSemOpen.Signal();
+		test.Close();
+		}
+
+	virtual CTest* Clone() const
+		{
+		//make shallow copy
+		return new CPciOpenChunkTest(*this);
+		}
+
+
+private:
+	RSemaphore& iSemOpen; ///!< Represents the number of available PCI mappings
+	RSemaphore& iSemClose; ///!< Represents the number of threads waiting to close their chunk
+	RFastLock& iLock;
+	static TInt iOpenCount;
+	const TInt iMaxCount;
+	};
+
+template<ChunkOpenFn FUNC>
+TInt CPciOpenChunkTest<FUNC>::iOpenCount = 0;
+
+
+/**
+Test which will perform various reads from a PCI address
+space (config or memory) and confirm that values are read
+as expected
+*/
+class CPciAddressSpaceRead : public CPciTest
+	{
+public:
+	CPciAddressSpaceRead(const TDesC& aName, TInt aIterations, RPci& aDevice,
+		const TUserPciSpace& aSpace, const TPciTestInfo::TAddrSpaceTest& aInfo)
+		:CPciTest(aName, aIterations, aDevice),
+			iAddressSpace(aSpace.Clone()), iSpaceTestInfo(aInfo)
+	{
+	}
+
+	CPciAddressSpaceRead(const CPciAddressSpaceRead& aOther)
+		:CPciTest(aOther)/* TODO-REVIEW have object-sliced aOther - is this ok?*/,
+			iAddressSpace(aOther.iAddressSpace->Clone()), iSpaceTestInfo(aOther.iSpaceTestInfo)
+	{
+	}
+
+	virtual ~CPciAddressSpaceRead()
+		{
+		delete iAddressSpace;
+		}
+
+	virtual void RunTest()
+		{
+		__UHEAP_MARK;
+		RTest test(iName);
+		TestReadAddressSpace(*iAddressSpace, iSpaceTestInfo, test);
+		test.Close();
+		__UHEAP_MARKEND;
+		}
+
+	virtual CTest* Clone() const
+		{
+		//make shallow copy
+		return new CPciAddressSpaceRead(*this);
+		}
+
+private:
+	TUserPciSpace* iAddressSpace;
+	const TPciTestInfo::TAddrSpaceTest& iSpaceTestInfo;
+	};
+
+/**
+For aBuffer, test writing to it then reading back from aWindow
+then write via window and read back from chunk
+
+@param test The RTest object to use
+@param aBuffer RChunk corresponding to a PCI accessible buffer
+@param aWindow RChunk coressponding an appropriate System-to-PCI memory window
+It is presumed to start at PCI address 0
+*/
+void DoLoopBackTest(RTest& test, RPciChunk aBuffer, RChunk aWindow)
+	{
+	test.Start(_L("Test accessing memory via PCI"));
+
+	TUint8* const bufferBase = aBuffer.Base();
+	const TUint bufferSize = aBuffer.Size();
+	const TUint bufferPciBase = aBuffer.PciBase();
+
+	TUint8* const windowBase = aWindow.Base();
+	const TUint windowSize = aWindow.Size();
+
+#define PRINT(N) RDebug::Printf("%s = 0x%08x (%d)", #N, (N), (N)) 
+	PRINT(bufferBase);
+	PRINT(bufferSize);
+	PRINT(bufferPciBase);
+
+	PRINT(windowBase);
+	PRINT(windowSize);
+
+#undef PRINT
+
+	//need to check that the end of the buffer
+	//is within the windowed region
+	test(bufferPciBase + bufferSize <= windowSize);
+	TUint8* const bufferBaseWithinWindow = windowBase + bufferPciBase;
+
+	test.Next(_L("write chunk"));
+	for(TUint i = 0; i < bufferSize; ++i)
+		{
+		//each byte will hold its own offset modulo 256
+		bufferBase[i] = (TUint8)i;
+		}
+
+	test.Next(_L("read back via window"));
+	for(TUint j=0; j < bufferSize; ++j)
+		{
+		const TUint8 result = bufferBaseWithinWindow[j];
+		test_Equal(j%256, result);
+		}
+
+	//clear chunk
+	memclr(bufferBase, bufferSize);
+	test.Next(_L("write via window"));
+	for(TUint k=0; k < bufferSize; ++k)
+		{
+		//each byte will hold its own offset modulo 256
+		bufferBaseWithinWindow[k] = (TUint8)k;
+		}
+
+	test.Next(_L("read back from chunk"));
+	for(TUint l=0; l < bufferSize; ++l)
+		{
+		const TUint8 result = bufferBase[l];
+		test_Equal(l%256, result);
+		}
+
+	test.End();
+	}
+
+/**
+Take care of opening a chunk, running the test and closing
+*/
+template<ChunkOpenFn OPEN_FUNC>
+inline void LoopBackTest(RPci& aPci, RTest& test, RChunk& aWindow)
+	{
+	RPciChunk pciChunk;
+	const TInt chunkSize = 0x400; //1k
+
+	//call the specified chunk opening function
+	TRequestStatus status;
+	TInt r = ((aPci).*(OPEN_FUNC))(pciChunk, chunkSize, &status);	
+	test_KErrNone(r);
+	DoLoopBackTest(test, pciChunk, aWindow);
+	pciChunk.Close();
+	User::WaitForRequest(status);
+	}
+
+/**
+Run the loopback test for the 3 types of buffer supported by the PCI driver.
+DChunk
+DPlatChunk
+Mapped In external memory
+*/
+void TestLoopBack(RPci& aPci, RTest& test)
+	{
+	test.Next(_L("Open PCI window"));
+	RChunk window;
+	
+	TInt r = aPci.OpenPciWindowChunk(window);	
+	test_KErrNone(r);
+
+	test.Next(_L("DChunk"));
+	LoopBackTest<&RPci::OpenPciDChunk>(aPci, test, window);
+
+	test.Next(_L("DPlatHwChunk"));
+	LoopBackTest<&RPci::OpenPciPlatHwChunk>(aPci, test, window);
+
+	test.Next(_L("DChunk (mapped in)"));
+	LoopBackTest<&RPci::OpenPciMappedChunk>(aPci, test, window);
+
+	window.Close();
+	}
+#ifndef __VC32__ //visual studio 6 doesn't approve of pointer to member function template parameters
+/**
+Run the CPciOpenChunkTest for each type of chunk. This function also creates (and destroys) the
+necessary semaphores and locks.
+CPciOpenChunkTest objects are run in multiple threads using MultipleTestRun().
+
+@param aDevice Handle to the test driver
+@param test RTest to use.
+@param aBufferLimit The maximum number of buffers which can be opened simultaneously
+*/
+void TestBufferOpenConcurrency(RPci& aDevice, RTest& test, TInt aBufferLimit)
+	{
+	RSemaphore semaphoreOpen;
+	RSemaphore semaphoreClose;
+	RFastLock lock;
+
+	TInt r = semaphoreOpen.CreateLocal(aBufferLimit);
+	test_KErrNone(r);
+
+	r = semaphoreClose.CreateLocal(0);
+	test_KErrNone(r);
+
+	r = lock.CreateLocal();
+	test_KErrNone(r);
+
+	const TInt iterations = 3;
+	{
+	test.Printf(_L("Opening %d PCI DChunks in %d threads\n"), aBufferLimit, aBufferLimit);
+	CPciOpenChunkTest<&RPci::OpenPciDChunk>
+		dChunkTest(_L("Concurrent-DChunk"), iterations, aDevice, semaphoreOpen, semaphoreClose, lock, aBufferLimit);
+
+	MultipleTestRun(test, dChunkTest, aBufferLimit);
+	}
+
+	{
+	test.Printf(_L("Opening %d PCI DPlatHwChunks in %d threads\n"), aBufferLimit, aBufferLimit);
+	CPciOpenChunkTest<&RPci::OpenPciPlatHwChunk>
+		platChunkTest(_L("Concurrent-DPlatHwChunk"), iterations, aDevice, semaphoreOpen, semaphoreClose, lock, aBufferLimit);
+
+	MultipleTestRun(test, platChunkTest, aBufferLimit);
+	}
+
+	{
+	test.Printf(_L("Opening %d PCI Mapped chunks in %d threads\n"), aBufferLimit, aBufferLimit);
+	CPciOpenChunkTest<&RPci::OpenPciMappedChunk>
+		mappedChunkTest(_L("Concurrent-DChunk(mapped)"), iterations, aDevice, semaphoreOpen, semaphoreClose, lock, aBufferLimit);
+
+	MultipleTestRun(test, mappedChunkTest, aBufferLimit);
+	}
+
+	semaphoreOpen.Close();
+	semaphoreClose.Close();
+	lock.Close();
+	}
+#endif
+
+TInt E32Main()
+	{
+	__UHEAP_MARK;
+
+	_LIT(KPci, "PCI");
+	RTest test(KPci);
+	test.Start(_L("Running PCI tests\n"));
+
+	TInt r = User::LoadLogicalDevice(KPciLdd);
+
+	__KHEAP_MARK;
+	
+	if(r==KErrNotFound)
+		{
+		test.Printf(_L("No PCI system present - skipping test\n"));
+		return KErrNone;
+		}
+	if(r!=KErrNone && r!=KErrAlreadyExists)
+		{
+		test_KErrNone(r);
+		}
+	
+	test.Next(_L("Open non-existant device\n"));
+	RPci device;
+	TPciDevice unavailable;
+	r = device.Open(unavailable);
+	test_Equal(KErrNotFound, r);
+
+	RPci pciInfo;
+	r = pciInfo.Open();
+	test_KErrNone(r);
+
+	test.Next(_L("Get test info from driver\n"));
+	TPciTestInfo info;
+	r = pciInfo.GetTestInfo(info);
+	test_KErrNone(r);
+	pciInfo.Close();
+
+	test.Next(_L("Open test device\n"));
+	r = device.Open(info.iDevice);
+	test_KErrNone(r);
+
+	test.Next(_L("Run Device Unit Test\n"));
+	r=TestRunPciUnitTest(device);	
+	test_KErrNone(r);
+
+	test.Next(_L("Read config space\n"));
+	TUserConfigSpace cs(device);
+	TestReadAddressSpace(cs, info.iCfgSpaceRead, test);
+
+	test.Next(_L("Write config space\n"));
+	TestWriteAddressSpace(cs, info.iCfgSpaceWrite, test);
+	
+	test.Next(_L("Read memory space\n"));
+	TUserMemorySpace ms(device, info.iMemSpaceIndex);
+	TestReadAddressSpace(ms, info.iMemSpaceRead, test);
+
+	test.Next(_L("Modify memory space\n"));
+	TestWriteAddressSpace(ms, info.iMemSpaceWrite, test);
+
+	{
+	const TInt addrSpaceThreadCount = 4;
+	const TInt iterations = 100;
+	test.Next(_L("Concurrent config space reads")); 
+	CPciAddressSpaceRead cfgSpaceRead(_L("Cfg Space Read"), iterations, device, cs, info.iCfgSpaceRead);
+	MultipleTestRun(test, cfgSpaceRead, addrSpaceThreadCount);
+
+	test.Next(_L("Concurrent memory space reads")); 
+	CPciAddressSpaceRead memSpaceRead(_L("Memory Space Read"), iterations, device, ms, info.iMemSpaceRead);
+	MultipleTestRun(test, memSpaceRead, addrSpaceThreadCount);
+	}
+
+	TInt testDChunkSize = 0x4000;
+	test.Next(_L("Open and Close DChunks\n"));	
+	TestOpenAndCloseDChunk(device,test,testDChunkSize);
+	
+	TInt testDPlatChunkSize = 0x2000;
+	test.Next(_L("Open and Close PlatHwChunks\n"));	
+	TestOpenAndClosePciPlatHwChunk(device,test,testDPlatChunkSize);
+
+	//TestPciMapppedChunk() fails for sizes greater than 4K.
+	//The issue is that a block of externally mapped memory must be
+	//naturally alligned in order to be accessible to the PCI bus (ie
+	//an 8k buffer would have to start at an address which is a
+	//multiple of 8k.
+	//
+	//Now we could fix this for sure on the kernel side, by making
+	//sure we only commit correctly aligned memory into the chunk (as
+	//the pci driver itself does),
+	//However, by using a 4k chunk, we know this will be on a page
+	//boundary so the alignment is correct (assuming the page size
+	//isn't changed). 	
+	TInt testMapppedChunkSize = 0x1000; 
+	test.Next(_L("Open and Close Pci Mappped Chunk\n"));	
+	TestPciMapppedChunk(device,test,testMapppedChunkSize);
+
+	test.Next(_L("Open and Close Pci Window Chunk\n"));	
+	TestPciWindowChunk(device,test);
+
+	const TInt numberOfThreads = info.iNumberOfBars;
+	test.Printf(_L("Open buffers concurrently, max supported = %d\n"), numberOfThreads);
+#ifndef __VC32__
+	TestBufferOpenConcurrency(device, test, numberOfThreads);
+#else
+	test.Printf(_L("TestBufferOpenConcurrency not implemented for WINS"), numberOfThreads);
+#endif
+
+	test.Next(_L("Test loop back"));	
+	TestLoopBack(device, test);
+
+	device.Close();
+	__KHEAP_MARKEND;
+
+	r = User::FreeLogicalDevice(KPciLdd);
+	test_KErrNone(r);
+
+	test.End();
+	test.Close();
+
+	__UHEAP_MARKEND;
+	return KErrNone;
+	}	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/naviengine/navienginebsp/ne1_tb/test/pci/t_pci.h	Wed Sep 15 13:26:16 2010 +0300
@@ -0,0 +1,254 @@
+// 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: This is the header file for the PCI driver test , so far implemented 
+//				only on the  Naviengine platform
+
+#ifndef __TPCI_TEST_H
+#define __TPCI_TEST_H
+
+#ifndef __KERNEL_MODE__
+#define __E32TEST_EXTENSION__
+#include <e32test.h>
+ #include <e32def_private.h>
+#endif // __KERNEL_MODE__
+
+_LIT(KPciLdd, "d_pci.ldd");
+_LIT(KPciLddFactory, "PCI_test_factory");
+_LIT(KPciTest, "PCI Test LDD");
+
+/**
+Test driver op-codes
+*/
+enum TPciTestCmd
+	{
+	EGetTestInfo,
+	EAccessConfigSpace,
+	EAccessMemorySpace,
+	EOpenPciDChunk,
+	EOpenPciPlatHwChunk,
+	EOpenPciMappedChunk,
+	EOpenPciWindowChunk,
+	ERunUnitTests
+	};
+
+/**
+Identifies a PCI Function (device) on the system
+*/
+struct TPciDevice
+	{
+	TPciDevice()
+		:iVendorId(0xFFFFFFFF), iDeviceId(0xFFFFFFFF), iInstance(0) {}
+
+	TPciDevice(TUint aVendorId, TUint aDeviceId, TInt aInstance=0)
+		:iVendorId(aVendorId), iDeviceId(aDeviceId), iInstance(aInstance) {}
+
+	TUint iVendorId;
+	TUint iDeviceId;
+	TInt iInstance; ///< Unit to open (there could be multiple devices on system)
+	};
+
+/**
+Used to send chunk size and recieve
+PCI address
+*/
+struct TPciChunkCreateInfo
+	{
+	TPciChunkCreateInfo()
+		:iSize(0), iPciAddress(NULL)
+		{
+		}
+
+	TPciChunkCreateInfo(TInt aSize, TUint& aPciAddress, TRequestStatus* aStatus=NULL)
+		:iSize(aSize), iPciAddress(&aPciAddress), iStatus(aStatus)
+		{
+		}
+	TInt iSize;
+	TUint* iPciAddress;
+	TRequestStatus* iStatus;
+	};	
+
+/**
+Information about the PSL required by the
+user side test
+*/
+struct TPciTestInfo
+	{
+	TPciDevice iDevice; ///< Probe for this
+
+	/**
+	Supplies the necessary information to test Read, Write, and
+	Modify for a word of PCI memory or configuration space
+	*/
+	struct TAddrSpaceTest
+		{
+		TAddrSpaceTest()
+			:iOffset(0), iExpectedValue(0), iReadOnlyMask(0)
+			{}
+
+		TAddrSpaceTest(TUint aOffset, TUint aExpectedValue, TUint aReadOnlyMask)
+			:iOffset(aOffset), iExpectedValue(aExpectedValue), iReadOnlyMask(aReadOnlyMask)
+			{}
+
+		/**
+		Returns a specified sub byte, or word from the whole dword
+		*/
+		inline TUint Expected(TInt aBitWidth, TInt aExtraOffset) const
+			{
+			//the right shift required to get field to bit 0
+			const TInt shift = 8 *((aExtraOffset + iOffset) % 4);
+			
+			const TUint mask = 0xFFFFFFFF >> (32-aBitWidth);
+			return (iExpectedValue >> shift) & mask;
+			}
+
+		const TUint iOffset;
+		const TUint iExpectedValue; ///< The initial value of word
+		const TUint iReadOnlyMask; ///< Mask of unwritable bits
+		//Future work, memory spaces should state a bar index
+		};
+
+
+	TAddrSpaceTest iCfgSpaceRead;
+	TAddrSpaceTest iCfgSpaceWrite;
+
+	TUint iMemSpaceIndex; ///< Memory space to select
+	TAddrSpaceTest iMemSpaceRead;
+	TAddrSpaceTest iMemSpaceWrite;
+
+	TInt iNumberOfBars; ///< Number of simultaneous mappings into PCI space
+	};
+
+class RPci;
+class TAddrSpace;
+/**
+This class encapsulates all the various read/write/and modify commands
+that can be carried out on a PCI memory space. The command is stored user
+side, and then executed on kernel side when KRun() is called.
+*/
+class TUserPciSpace
+	{
+public:
+	TUserPciSpace()
+		:iPci(NULL), iOperation(EInvalid), iBitWidth(0), iOffset(0),
+		iWriteValue(0), iClearMask(0), iSetMask(0)
+	{}
+	TUserPciSpace(RPci& aPci);
+	
+	/**
+	Perform the encapsulated read/write/or modify
+	@note Only run on kernel side
+	*/
+	TUint KRun(TAddrSpace& aAddrSpace);
+	
+	/**
+	Clone method is required so that multiple threads may
+	have their own copy of a TUserPciSpace (without knowing
+	its runtime type)
+	*/
+	virtual TUserPciSpace* Clone() const = 0;
+
+	TUint Read(TInt aBitWidth, TUint aOffset)
+		{
+		iOffset = aOffset;
+		iOperation = ERead;
+		iBitWidth = aBitWidth;
+
+		return Call();
+		}
+
+	void Write(TInt aBitWidth, TUint aOffset, TUint aValue)
+		{
+		iOffset = aOffset;
+		iOperation = EWrite;
+		iBitWidth = aBitWidth;
+		
+		iWriteValue = aValue;
+		Call();
+		}
+
+	void Modify(TInt aBitWidth, TUint aOffset, TUint aClearMask, TUint aSetMask)
+		{
+		iOffset = aOffset;
+		iOperation = EModify;
+		iBitWidth = aBitWidth;
+
+		iClearMask = aClearMask;
+		iSetMask = aSetMask;
+		Call();
+		}
+
+protected:
+	/**
+	Makes a request to iPci and passes a copy of this object to
+	the kernel side.
+	*/
+	virtual TUint Call() =0;
+
+	enum TOperation {EInvalid, ERead, EWrite, EModify};
+
+	/**
+	Pointer to a PCI device handle
+	*/
+	RPci* iPci;
+
+	TOperation iOperation; //!< Type of access to perform
+	TInt iBitWidth;
+	
+	TUint iOffset;
+	TUint32 iWriteValue;
+	TUint32 iClearMask;
+	TUint32 iSetMask;
+	};
+
+/**
+Grants access to a PCI device's (identified
+by aPci) config space from user side
+*/
+class TUserConfigSpace : public TUserPciSpace
+	{
+public:
+	TUserConfigSpace()
+		:TUserPciSpace()
+		{}
+	TUserConfigSpace(RPci& aPci);
+
+	virtual TUserPciSpace* Clone() const;
+private:
+	TUint Call();
+	};
+
+/**
+Grants access to some region of a PCI
+device's memory space. A PCI device(or function)
+may have up to 8 distinct memory spaces
+*/
+class TUserMemorySpace : public TUserPciSpace
+	{
+public:
+	TUserMemorySpace()
+		:TUserPciSpace(), iBarIndex(-1)
+		{}
+
+	TUserMemorySpace(RPci& aPci, TInt aBarIndex);	
+
+	virtual TUserPciSpace* Clone() const;
+	
+	inline TInt BarIndex() {return iBarIndex;}
+
+private:
+	TUint Call();
+
+	TInt iBarIndex; ///< Each PCI function may have up to 8 memory spaces
+	};
+
+#endif //__TPCI_TEST_H