diff -r 000000000000 -r a41df078684a kerneltest/e32test/examples/convert1/convert1_ldd.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/kerneltest/e32test/examples/convert1/convert1_ldd.cpp Mon Oct 19 15:55:17 2009 +0100 @@ -0,0 +1,982 @@ +// Copyright (c) 2005-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: +// its implementation. +// +// + +/** + @file An example data converter device driver which uses Shared Chunks in + @publishedPartner + @prototype 9.1 +*/ + +#include +#include +#include "convert1.h" +#include "convert1_dev.h" + + +#if 0 // Set true for tracing +#define TRACE(x) x +#else +#define TRACE(x) +#endif + + +_LIT(KConvert1PanicCategory,"CONVERT1"); + + +// +// DConvert1Factory +// + +/** + Number of hardware 'resources' available to driver. + E.g. the number of simultaneous channels it can support. +*/ +const TInt KTotalConvert1Resources = 4; + +/** + A resource ID representing no resources +*/ +const TInt KNullConvert1ResourceId = -1; + +/** + Standard export function for LDDs. This creates a DLogicalDevice derived object, + in this case, our DConvert1Factory +*/ +DECLARE_STANDARD_LDD() + { + return new DConvert1Factory; + } + +/** + Constructor +*/ +DConvert1Factory::DConvert1Factory() + { + // Set version number for this device + iVersion=RConvert1::VersionRequired(); + // Indicate that do support units or a PDD + iParseMask=0; + // Mark all resources available + iResourceFlags = (1<ClaimResource(iResourceId); + if(r!=KErrNone) + return r; + + // Set client thread with which channel will be used by + iClient = &Kern::CurrentThread(); + + // Done + return KErrNone; + } + +/** + Destructor +*/ +DConvert1Channel::~DConvert1Channel() + { + // Cancel outsatnding requests + DoCancel(RConvert1::EAllRequests); + + // Release hardware resource which we own + iFactory->ReleaseResource(iResourceId); + } + +/** + Called when a user thread requests a handle to this channel. +*/ +TInt DConvert1Channel::RequestUserHandle(DThread* aThread, TOwnerType aType) + { + // Make sure that only our client can get a handle + if (aType!=EOwnerThread || aThread!=iClient) + return KErrAccessDenied; + return KErrNone; + } + +/** + Process a request on this logical channel. + + @param aReqNo Request number: + ==KMaxTInt, a 'DoCancel' message + >=0, a 'DoControl' message with function number equal to iValue + <0, a 'DoRequest' message with function number equal to ~iValue + @param a1 First argument. For DoRequest requests this is a pointer to the TRequestStatus. + @param a2 Second argument. For DoRequest this is a pointer to the 2 actual TAny* arguments. + + @return Result. Ignored by device driver framework for DoRequest requests. +*/ +TInt DConvert1Channel::Request(TInt aReqNo, TAny* a1, TAny* a2) + { + // Decode the message type and dispatch it to the relevent handler function... + if ((TUint)aReqNo<(TUint)KMaxTInt) + return DoControl(aReqNo,a1,a2); + if(aReqNo==KMaxTInt) + return DoCancel((TInt)a1); + return DoRequest(aReqNo,a1,a2); + } + +/** + Process synchronous 'control' requests +*/ +TInt DConvert1Channel::DoControl(TInt aFunction, TAny* a1, TAny* a2) + { + TRACE(Kern::Printf(">DConvert1Channel::DoControl fn=%d\n",aFunction);) + + TInt r = KErrNotSupported; + switch (aFunction) + { + case RConvert1::EGetConfig: + r = GetConfig((TDes8*)a1); + break; + + case RConvert1::ESetConfig: + r = SetConfig((const TDesC8*)a1,(RConvert1::TBufferInfo*)a2); + break; + + case RConvert1::EConvertDes: + ConvertDes((const TDesC8*)a1,(TRequestStatus*)a2); + break; + + case RConvert1::EConvertChunk: + ConvertChunk((const RConvert1::TConvertArgs*)a1,(TRequestStatus*)a2); + break; + + case RConvert1::EConvertInChunk: + ConvertInChunk((TInt)a1,(TRequestStatus*)a2); + break; + } + + TRACE(Kern::Printf("DConvert1Channel::DoRequest req=%d\n",aNotReqNo);) + + // Get arguments + TAny* a[2]; + kumemget32(a,a2,sizeof(a)); + TRequestStatus* status=(TRequestStatus*)a1; + TInt reqNo = ~aNotReqNo; + + // Do the request + TInt r; + switch(reqNo) + { + case RConvert1::EConvertDes: + case RConvert1::EConvertChunk: + case RConvert1::EConvertInChunk: + // Not used because we do these asyncronous request as a + // DoControl rather than a DoRequest for performance reasons. + + default: + r = KErrNotSupported; + break; + } + + // Complete request if there was an error + if (r!=KErrNone) + Kern::RequestComplete(&Kern::CurrentThread(),status,r); + + TRACE(Kern::Printf("DConvert1Channel::DoCancel mask=%08x\n",aMask);) + + if(aMask&( (1<=TUint(iInBuffer.iMaxSize)) + { + r = KErrArgument; + goto done; + } + + // Start the convert + iSource = &iInBuffer; + iConvertRequestStatus = aRequestStatus; + DoConvertStart(iInBuffer.iChunkOffset,aSize); + r = KErrNone; + +done: + // Complete request if there was an error + if (r!=KErrNone) + Kern::RequestComplete(&Kern::CurrentThread(),aRequestStatus,r); + } + +/** + Signal ConvertData request completed +*/ +void DConvert1Channel::ConvertCancel() + { + // Tell hardware to stop + DoConvertCancel(); + + // Complete client request + NKern::ThreadEnterCS(); + ConvertComplete(KErrCancel); + NKern::ThreadLeaveCS(); + } + +/** + DFC callback called after data has been converted. +*/ +void DConvert1Channel::ConvertDfcTrampoline(TAny* aSelf) + { + // Just call non-static method + ((DConvert1Channel*)aSelf)->ConvertDfc(); + } + +/** + DFC callback called after data has been converted +*/ +void DConvert1Channel::ConvertDfc() + { + TRACE(Kern::Printf(">DConvert1Channel::ConvertDfc\n");) + + // The result value will be the chunk offset of the data we've converted + TInt result = iOutBuffer.iChunkOffset; + ConvertComplete(result); + + TRACE(Kern::Printf("iMaxSize) + return KErrTooBig; + + NKern::ThreadEnterCS(); + + // Attempt to open chunk + iChunk = Kern::OpenSharedChunk(NULL,aAddress,aWrite,iChunkOffset); + if(!iChunk) + r = KErrArgument; + else + { + // Get physical addresses + r = SetPhysicalAddresses(aSize); + if(r!=KErrNone) + Close(); + } + + NKern::ThreadLeaveCS(); + + return r; + } + +/** + Open a specified shared chunk +*/ +TInt DChunkBuffer::Open(TInt aChunkHandle, TInt aOffset, TInt aSize, TBool aWrite) + { + TInt r; + + // Check size + if(aSize>iMaxSize) + return KErrTooBig; + iChunkOffset = aOffset; + + NKern::ThreadEnterCS(); + + // Attempt to open chunk + iChunk = Kern::OpenSharedChunk(NULL,aChunkHandle,aWrite); + if(!iChunk) + r = KErrArgument; + else + { + // Get physical addresses + r = SetPhysicalAddresses(aSize); + if(r!=KErrNone) + Close(); + } + + NKern::ThreadLeaveCS(); + + return r; + } + +/** + Close chunk +*/ +void DChunkBuffer::Close() + { + __ASSERT_CRITICAL; + if(iChunk) + { + Kern::ChunkClose(iChunk); + iChunk = NULL; + } + } + +/** + Fill buffer by copying data from the given user address +*/ +TInt DChunkBuffer::Copy(TAny* aAddress, TInt aSize) + { + // Check size + if(aSize>iMaxSize) + return KErrTooBig; + + // Copy data + kumemget((TAny*)(iChunkBase+iChunkOffset),aAddress,aSize); + + return KErrNone; + } + +/** + Setup physical address info for memory in the buffer +*/ +TInt DChunkBuffer::SetPhysicalAddresses(TInt aSize) + { + // Assert that the iPhysicalPages array already allocated will be big enough + __NK_ASSERT_DEBUG(aSize<=iMaxSize); + + // Get physical addresses + TLinAddr kaddr; + TInt r=Kern::ChunkPhysicalAddress(iChunk,iChunkOffset,aSize,kaddr,iChunkMapAttr,iPhysicalAddress,iPhysicalPages); + // r = 0 or 1 on success. (1 meaning the physical pages are not contiguous) + if(r>=0) + { + iChunkBase = kaddr-iChunkOffset; // Calculate start of chunk in kernel process address space + r = KErrNone; + } + return r; + } + +// +// Program converter hardware +// + +/** + Initialise hardware to start converting data. + Input data is in iSource. + Output data to be placed in iOutBuffer. +*/ +void DConvert1Channel::DoConvertStart(TInt aOffset,TInt aSize) + { + // For this example test... + + TRACE(Kern::Printf("DConvert1Channel::DoConvertStart\n");) + + // 'Convert' data by xoring with 1 + TUint8* src = (TUint8*)iSource->iChunkBase+iSource->iChunkOffset+aOffset; + TUint8* end = src+aSize; + TUint8* dst = (TUint8*)iOutBuffer.iChunkBase+iOutBuffer.iChunkOffset; + while(src