cryptoplugins/cryptospiplugins/test/h4drv/crypto_h4/cryptoldd.cpp
changeset 8 35751d3474b7
child 15 da2ae96f639b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cryptoplugins/cryptospiplugins/test/h4drv/crypto_h4/cryptoldd.cpp	Thu Sep 10 14:01:51 2009 +0300
@@ -0,0 +1,1036 @@
+/*
+* 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
+ @released
+*/
+#include <kernel/kern_priv.h>
+#include <cryptodriver.h>
+#include "cryptoldd.h"
+#include <keyhandle.h>
+#include "kmskext.h"
+
+DECLARE_STANDARD_LDD()
+    {
+    return new DCryptoLddChannelFactory;
+    }
+
+//#define HW_PERF_CHECK
+
+_LIT(KCryptoPanicCategory,"DCrypto");
+
+/**
+  Constructor
+*/
+DCryptoLddChannelFactory::DCryptoLddChannelFactory()
+	{
+	TRACE_FUNCTION("DCryptoLddChannelFactory");
+	// Set version number for this device
+    iVersion=RCryptoDriver::VersionRequired();
+	// Auto load a PDD
+    iParseMask=KDeviceAllowPhysicalDevice;
+	}
+
+/**
+  Destructor
+*/
+DCryptoLddChannelFactory::~DCryptoLddChannelFactory()
+	{
+	TRACE_FUNCTION("~DCryptoLddChannelFactory");
+	TraceFunction::DumpCounts();
+	}
+
+
+/**
+  Second stage constructor for DCryptoLddChannelFactory.
+  This must at least set a name for the driver object.
+
+  @return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCryptoLddChannelFactory::Install()
+	{
+	TRACE_FUNCTION("Install");
+    return SetName(&RCryptoDriver::Name());
+	}
+
+/**
+  Return the drivers capabilities.
+  Called in the response to an RDevice::GetCaps() request.
+
+  @param aDes Descriptor into which capabilities information is to be written.
+*/
+void DCryptoLddChannelFactory::GetCaps(TDes8& aDes) const
+	{
+	TRACE_FUNCTION("GetCaps");
+    // Create a capabilities object
+    RCryptoDriver::TCaps caps;
+	caps.iVersion = iVersion;
+
+	// We do not have a handle to the PDD, and it might not have been
+	// loaded yet, so we can't ask it for its capabilities...
+
+    // Write it back to user memory
+    Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
+ 	return;
+	}
+
+/**
+  Called by the kernel's device driver framework to create a Logical Channel.
+  This is called in the context of the user thread (client) which requested the creation
+  of the Logical Channel (e.g. through a call to RBusLogicalChannel::DoCreate).
+  The thread is in a critical section.
+
+  @param aChannel Set to point to the created Logical Channel
+
+  @return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCryptoLddChannelFactory::Create(DLogicalChannelBase*& aChannel)
+	{
+	TRACE_FUNCTION("Create");
+    aChannel=new DCryptoLddChannel;
+    if(!aChannel)
+        return KErrNoMemory;
+
+    return KErrNone;
+	}
+
+
+//
+// Logical Channel
+//
+
+/**
+  Constructor
+*/
+DCryptoLddChannel::DCryptoLddChannel()
+    : iLddChanRandom(*this),
+	  iLddChanAes(*this)
+	{
+	TRACE_FUNCTION("DCryptoLddChannel");
+    // Get pointer to client thread's DThread object
+    iClient=&Kern::CurrentThread();
+
+    // Open a reference on client thread so its control block can't disappear until
+    // this driver has finished with it.
+    // Note, this call to Open() can't fail since it is the thread we are currently running in.
+    iClient->Open();
+    }
+
+
+/**
+  Destructor
+*/
+DCryptoLddChannel::~DCryptoLddChannel()
+    {
+	TRACE_FUNCTION("~DCryptoLddChannel");
+    // Cancel all processing that we may be doing
+    DoCancel(RCryptoDriver::EAllRequests);
+    // Close our reference on the client thread
+    Kern::SafeClose((DObject*&)iClient,NULL);
+    }
+
+
+/**
+  Second stage constructor called by the kernel's device driver framework.
+  This is called in the context of the user thread (client) which requested the creation
+  of the Logical Channel (e.g. through a call to RBusLogicalChannel::DoCreate())
+  The thread is in a critical section.
+
+  @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate()
+  @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate()
+  @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate()
+
+  @return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DCryptoLddChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
+    {
+	TRACE_FUNCTION("DoCreate");
+    // Check Platform Security capabilities of client thread (if required).
+    //
+    // Here we handle the simple case where:
+    // 1. The device driver can only have one client thread
+    // 2. The security policy is the binary all-or-nothing policy.
+    // E.g. "If you have the right capability you can do anything with the driver
+    // and if you don't have the capability you can't do anything"
+    // 
+    // If only some functionality of the driver is restricted, then the security check should
+    // go elsewhere. E.g. in DoRequest/DoControl. In that case Kern::CurrentThreadHasCapability
+    // shouldn't be used because the 'current thread' isn't the client.
+    //
+    // In this example we do a check here for ECapability_None (which always passes)...
+    if(!Kern::CurrentThreadHasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by DRIVER1")))
+        return KErrPermissionDenied;
+     
+    // Check version
+    if (!Kern::QueryVersionSupported(RCryptoDriver::VersionRequired(),aVer))
+        return KErrNotSupported;
+
+     // Give PDD a pointer to this channel
+    PddChan()->iCryptoLddChannel = this;
+
+    // Setup LDD for receiving client messages.
+    SetDfcQ(PddChan()->DfcQue());
+    iMsgQ.Receive();
+
+    // Done
+    return KErrNone;
+    }
+
+
+/**
+  Called when a user thread requests a handle to this channel.
+*/
+TInt DCryptoLddChannel::RequestUserHandle(DThread* aThread, TOwnerType aType)
+    {
+	TRACE_FUNCTION("RequestUserHandle");
+    // Make sure that only our client can get a handle
+    if (aType!=EOwnerThread || aThread!=iClient)
+        return KErrAccessDenied;
+    return KErrNone;
+    }
+
+
+/**
+  Process a message for this logical channel.
+  This function is called in the context of a DFC thread.
+
+  @param aMessage The message to process.
+     The iValue member of this distinguishes the message type:
+     iValue==ECloseMsg, channel close message
+     iValue==KMaxTInt, a 'DoCancel' message
+     iValue>=0, a 'DoControl' message with function number equal to iValue
+     iValue<0, a 'DoRequest' message with function number equal to ~iValue
+*/
+void DCryptoLddChannel::HandleMsg(TMessageBase* aMsg)
+    {
+	TRACE_FUNCTION("HandleMsg");
+    TThreadMessage& m=*(TThreadMessage*)aMsg;
+
+    // Get message type
+    TInt id=m.iValue;
+
+    // Decode the message type and dispatch it to the relevent handler function...
+    
+    if (id==(TInt)ECloseMsg)
+        {
+        // Channel Close
+        DoCancel(RCryptoDriver::EAllRequests);
+        m.Complete(KErrNone, EFalse);
+        return;
+        }
+
+    if (id==KMaxTInt)
+        {
+        // DoCancel
+        DoCancel(m.Int0());
+        m.Complete(KErrNone,ETrue);
+        return;
+        }
+
+    if (id<0)
+        {
+        // DoRequest
+        TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+        TInt r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
+        if (r!=KErrNone)
+            Kern::RequestComplete(iClient,pS,r);
+        m.Complete(KErrNone,ETrue);
+        }
+    else
+        {
+        // DoControl
+        TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
+        m.Complete(r,ETrue);
+        }
+    }
+
+/**
+  Process synchronous 'control' requests
+*/
+TInt DCryptoLddChannel::DoControl(TInt aFunction, TAny* a1, TAny *)
+    {
+	TRACE_FUNCTION("DoControl");
+    TInt r;
+
+    switch (aFunction)
+        {
+        case RCryptoDriver::EGetHwVersions:
+            r = GetHwVersions((TDes8*)a1);
+            break;
+
+        case RCryptoDriver::EGetConfig:
+            r = GetConfig((TDes8*)a1);
+            break;
+
+        case RCryptoDriver::ESetConfig:
+            r = SetConfig((const TDesC8*)a1);
+            break;
+
+        case RCryptoDriver::EAesSetConfig:
+            r = iLddChanAes.SetAesConfig((const TDesC8*)a1);
+            break;
+
+        default:
+            r=KErrNotSupported;
+            break;
+        }
+
+    return r;
+    }
+
+
+/**
+  Process asynchronous requests
+*/
+TInt DCryptoLddChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+    {
+	TRACE_FUNCTION("DoRequest");
+    (void)a2; // a2 not used in this example
+
+    TInt r;
+
+    switch(aReqNo)
+        {
+        case RCryptoDriver::ERandom:
+			r=iLddChanRandom.Random(aStatus,(TDes8*)a1);
+            break;
+
+        case RCryptoDriver::EAesWrite:
+			r=iLddChanAes.AesWrite(aStatus,(TDesC8*)a1);
+            break;
+
+        case RCryptoDriver::EAesRead:
+			r=iLddChanAes.AesRead(aStatus,(TDes8*)a1, (TUint32)a2);
+            break;
+
+        default:
+            r=KErrNotSupported;
+            break;
+        }
+
+    return r;
+    }
+
+
+/**
+  Process cancelling of asynchronous requests
+*/
+void DCryptoLddChannel::DoCancel(TUint aMask)
+    {
+	TRACE_FUNCTION("DoCancel");
+    if(aMask&(1<<RCryptoDriver::ERandom))
+		{
+		iLddChanRandom.RandomCancel();
+		}
+	
+    if(aMask&(1<<RCryptoDriver::EAesRead))
+		{
+        iLddChanAes.CancelRead();
+		}
+
+    if(aMask&(1<<RCryptoDriver::EAesWrite))
+		{
+        iLddChanAes.CancelWrite();
+		}
+	
+    }
+
+
+/**
+  Process a GetHwVersions control message. This writes the crypto h/w versions to a
+  RCryptoDriver::THwVersionsBuf supplied by the client.
+*/
+TInt DCryptoLddChannel::GetHwVersions(TDes8* aHwVersionsBuf) const
+    {
+	TRACE_FUNCTION("GetHwVersions");
+    // Create a structure giving the current configuration
+    RCryptoDriver::THwVersions versions;
+	
+	PddChan()->GetHwVersions(versions);
+
+    // Write the config to the client
+    TPtrC8 ptr((const TUint8*)&versions,sizeof(versions));
+    return Kern::ThreadDesWrite(iClient,aHwVersionsBuf,ptr,0,KTruncateToMaxLength,NULL);
+    }
+
+//
+// Functions for processing configuration control messages
+//
+
+/**
+  Process a GetConfig control message. This writes the current driver configuration to a
+  RCryptoDriver::TConfigBuf supplied by the client.
+*/
+TInt DCryptoLddChannel::GetConfig(TDes8* aConfigBuf) const
+    {
+	TRACE_FUNCTION("GetConfig");
+    // Create a structure giving the current configuration
+    RCryptoDriver::TConfig config;
+    CurrentConfig(config);
+
+    // Write the config to the client
+    TPtrC8 ptr((const TUint8*)&config,sizeof(config));
+    return Kern::ThreadDesWrite(iClient,aConfigBuf,ptr,0,KTruncateToMaxLength,NULL);
+    }
+
+/**
+  Process a SetConfig control message. This sets the driver configuration using a
+  RCryptoDriver::TConfigBuf supplied by the client.
+*/
+TInt DCryptoLddChannel::SetConfig(const TDesC8* aConfigBuf)
+    {
+	TRACE_FUNCTION("SetConfig");
+    // Don't allow configuration changes whilst we're busy
+	//    if(iSendDataStatus || iReceiveDataStatus)
+	//        return KErrInUse;
+
+    // Create a config structure.
+    RCryptoDriver::TConfig config;
+    CurrentConfig(config);
+
+    // Note: We have filled config with the current settings, this is to allow
+    // backwards compatibility when a client gives us an old (and shorter) version
+    // of the config structure.
+
+    // Read the config structure from client
+    TPtr8 ptr((TUint8*)&config,sizeof(config));
+    TInt r=Kern::ThreadDesRead(iClient,aConfigBuf,ptr,0);
+    if(r!=KErrNone)
+        return r;
+
+    // Use config data to setup the driver. Checking that parameters which aren't settable
+    // either contain the correct values or are zero (meaning 'default')
+	r=PddChan()->SetFakeDriverSetting(config.iFakeDriverSetting);
+    if(r!=KErrNone)
+        return r;
+
+    return r;
+    }
+
+
+/**
+  Fill a TConfig with the driver's current configuration.
+*/
+void DCryptoLddChannel::CurrentConfig(RCryptoDriver::TConfig& aConfig) const
+    {
+	TRACE_FUNCTION("TConfig");
+    aConfig.iFakeDriverSetting = PddChan()->FakeDriverSetting();
+    }
+
+
+
+//
+// Functions for processing 'Random'
+//
+
+DLddChanRandom::DLddChanRandom(DCryptoLddChannel &aParent)
+	: iParent(aParent)
+	{
+	TRACE_FUNCTION("DLddChanRandom");
+	}
+
+
+/**
+  Start processing a Random request.
+*/
+TInt DLddChanRandom::Random(TRequestStatus* aStatus,TDes8* aPtr)
+    {
+	TRACE_FUNCTION("Random");
+    // Check that a 'Random' isn't already in progress
+    if(iRandomStatus)
+        {
+        Kern::ThreadKill(iParent.iClient,EExitPanic,ERequestAlreadyPending,KCryptoPanicCategory);
+        return KErrInUse;
+        }
+
+	// We only support a single outstanding Random request in this LDD
+	// channel, but the PDD supports multiple requests.
+
+    // Save the client request status and descriptor
+    iRandomStatus = aStatus;
+    iRandomDescriptor = aPtr;
+
+	// Retrieve user request length (ie. CURRENT length of user descriptor) into iRequestLength
+	TInt tmp;
+	TUint8 *tmp2;
+	TInt r=Kern::ThreadGetDesInfo(iParent.iClient, iRandomDescriptor, iRequestLength, tmp, tmp2, ETrue);
+	if(r != KErrNone)
+		{
+		return r;
+ 		}
+
+	// Set current offset into user descriptor
+	iCurrentIndex = 0;
+
+	iJob = iParent.PddChan()->GetJobRandom();
+
+	// Setup PDD job
+	iJob->SetDetails(&iParent.LddFactory()->iJSRandom, this, iRequestLength);
+	// Register it, which will also (maybe later) call DoSlice to run it
+	iParent.LddFactory()->iJSRandom.ScheduleJob(iJob);
+		
+	return KErrNone;
+    }
+
+
+
+TInt DLddChanRandom::DataRequired()
+	{
+	TRACE_FUNCTION("DataRequired");
+	return KErrNone; // We never pass data to the h/w...
+	}
+
+TInt DLddChanRandom::DataAvailable()
+	{
+	TRACE_FUNCTION("DataAvailable");
+	//	Kern::Printf("DLddChanRandom::DataAvailable()");
+	TInt r = KErrNone;
+	
+	TUint8 *buf;
+	TUint32 bufLen;
+	TBool check = ETrue;
+	while(check)
+		{
+		iJob->GetFromPddBuffer(buf, bufLen, check);
+		if(bufLen)
+			{
+			TInt required = iRequestLength - iCurrentIndex;
+			TInt toTransfer = bufLen;
+			if(toTransfer > required)
+				{
+				toTransfer = required;
+				}
+			// Copy the current buffer to user land
+			TPtr8 des(buf, toTransfer, toTransfer);
+			r=Kern::ThreadDesWrite(iParent.iClient, iRandomDescriptor, des, iCurrentIndex);
+			if(r != KErrNone)
+				{
+				break;
+				}
+			
+			// Update our index into the user descriptor
+			iCurrentIndex += toTransfer;
+
+			// Update h/w with number of bytes actually read
+			iJob->BytesReadFromPdd(toTransfer);
+
+			if(toTransfer != bufLen)
+				{
+				// We did not read all the available data, so do not
+				// re-query h/w
+				check = EFalse;
+				}
+			}
+		};
+
+	return r;
+	}
+
+void DLddChanRandom::JobComplete(TInt aResult)
+	{
+	TRACE_FUNCTION("JobComplete");
+	if(iRandomStatus)
+		{
+		// Finished with client descriptor, so NULL it to help detect coding errors
+		iRandomDescriptor = NULL;
+		// Complete client's request
+		Kern::RequestComplete(iParent.iClient,iRandomStatus, aResult);
+		}
+	}
+
+
+/**
+  Cancel a Random request.
+*/
+void DLddChanRandom::RandomCancel()
+    {
+	TRACE_FUNCTION("RandomCancel");
+    if(iRandomStatus)
+        {
+        // Tell PDD to stop processing the request
+        iParent.LddFactory()->iJSRandom.DeScheduleJob(iParent.PddChan()->GetJobRandom());
+        // Finished with client descriptor, so NULL it to help detect coding errors
+        iRandomDescriptor = NULL;
+        // Complete clients request
+        Kern::RequestComplete(iParent.iClient,iRandomStatus,KErrCancel);
+        }
+    }
+
+//
+// Functions for processing 'Aes'
+//
+
+DLddChanAes::DLddChanAes(DCryptoLddChannel &aParent)
+	: iParent(aParent)
+	{
+	TRACE_FUNCTION("DLddChanAes");
+	}
+
+
+TInt DLddChanAes::SetAesConfig(const TDesC8* aConfigBuf)
+	{
+	TRACE_FUNCTION("SetAesConfig");
+	// Note we need to validate arguments kernel side otherwise
+	// someone could easily crash the kernel...
+
+	RCryptoDriver::TAesConfig config;
+    // Read the config structure from client
+    TPtr8 ptr((TUint8*)&config,sizeof(config));
+    TInt r=Kern::ThreadDesRead(iParent.iClient,aConfigBuf,ptr,0);
+    if(r!=KErrNone)
+		{
+		return r;
+		}
+
+	//	Kern::Printf("iEncrypt = 0x%x",config.iEncrypt);
+	//	Kern::Printf("iMode = 0x%x",config.iMode);
+	//	Kern::Printf("iKey = 0x%x",config.iKey);
+	//	Kern::Printf("iIV = 0x%x",config.iIV);
+
+
+	// Remember direction
+	iEncrypt = config.iEncrypt;
+
+	// Remember mode
+	iMode = config.iMode;
+
+	//
+	// Handle key
+	//
+
+	// Retrieve user key length into iKeyLengthBytes
+	TInt tmp;
+	TUint8 *tmp2;
+	r=Kern::ThreadGetDesInfo(iParent.iClient, (TAny *)config.iKey, iKeyLengthBytes, tmp, tmp2, EFalse);
+    if(r!=KErrNone)
+		{
+		return r;
+		}
+
+	HBuf8 *embeddedKeyData = 0;
+	if(iKeyLengthBytes == 4)
+		{
+		// Some form of embedded key so value is a 32 bit handle
+		TPckgBuf<TKeyHandle> keyHandlePkg;	
+		
+		r=Kern::ThreadDesRead(iParent.iClient, (TAny *)config.iKey, keyHandlePkg, 0);
+		if(r != KErrNone)
+			{
+			return r;
+			}
+
+		TKeyHandle &keyHandle = keyHandlePkg();
+
+		r = HwKeyStore::ExtractKey(iParent.iClient->iOwningProcess, keyHandle, 0 /*operation*/, embeddedKeyData);
+		if(r != KErrNone)
+			{
+			return r;
+			}
+
+		// Update key length
+		iKeyLengthBytes = embeddedKeyData->Length();
+		}
+
+	switch(iKeyLengthBytes)
+		{
+		case 16: // 128 bits
+			break;
+		case 24: // 192 bits
+			break;
+		case 32: // 256 bits
+			break;
+		default: // Illegal length
+			if(embeddedKeyData) delete embeddedKeyData;
+			return KErrArgument;
+		}
+
+	// Make sure iJob is valid before we use it
+	iJob = iParent.PddChan()->GetJobAes();
+
+	TUint8 *keyBuffer = iJob->GetKeyBuffer();
+	TPtr8 des(keyBuffer, iKeyLengthBytes);
+
+	if(embeddedKeyData)
+		{
+		// Copy embedded key to PDD
+		des = *embeddedKeyData;
+		delete embeddedKeyData;
+		embeddedKeyData = 0;
+		}
+	else
+		{
+		// Retrieve key from user
+		r=Kern::ThreadDesRead(iParent.iClient, (TAny *)config.iKey, des, 0);
+		if(r != KErrNone)
+			{
+			return r;
+			}
+		}
+	
+		
+	//
+	// Handle IV
+	//
+
+	// Retrieve IV length
+	TInt ivLength;
+	r=Kern::ThreadGetDesInfo(iParent.iClient, (TAny *)config.iIV, ivLength, tmp, tmp2, EFalse);
+	//	Kern::Printf("DLddChanAes::SetAesConfig r=%d 5",r);
+	if(r != KErrNone)
+		{
+		return r;
+		}
+	
+	if((ivLength != 0) && (ivLength != 16))
+		{
+		return KErrArgument;
+		}
+
+	if(ivLength == 16)
+		{
+		TUint8 *ivBuffer = iJob->GetIVBuffer();
+		TPtr8 des(ivBuffer, 16);
+		r=Kern::ThreadDesRead(iParent.iClient, (TAny *)config.iIV, des, 0);
+		if(r != KErrNone)
+			{
+			return r;
+			}
+		}
+
+
+	// Set details
+	r = iJob->SetDetails(&iParent.LddFactory()->iJSAes, this, iEncrypt, iKeyLengthBytes, iMode);
+	if(r != KErrNone)
+		{
+		return r;
+		}
+	
+	return KErrNone;
+	}
+
+/**
+  Start processing a Aes request.
+*/
+TInt DLddChanAes::AesWrite(TRequestStatus* aStatus, TDesC8* aPtr)
+    {
+	TRACE_FUNCTION("AesWrite");
+	//	Kern::Printf("DLddChanAes::AesWrite");
+    // Check that an Aes Write isn't already in progress
+    if(iAesWriteStatus)
+        {
+        Kern::ThreadKill(iParent.iClient,EExitPanic,ERequestAlreadyPending,KCryptoPanicCategory);
+        return KErrInUse;
+        }
+
+	// We only support a single outstanding Aes Write request in this LDD
+	// channel, but the PDD supports multiple requests.
+
+    // Save the client request status and descriptor
+    iAesWriteStatus = aStatus;
+    iAesWriteDescriptor = aPtr;
+
+
+	// Retrieve user request length (ie. current length of user descriptor) into iRequestLength
+	TInt maxLen;
+	TUint8 *aesWriteDescriptorBufferRaw;
+	TInt r=Kern::ThreadGetDesInfo(iParent.iClient, iAesWriteDescriptor, iWriteRequestLength, maxLen, aesWriteDescriptorBufferRaw, EFalse);
+	if(r != KErrNone)
+		{
+		iAesWriteStatus = 0;
+		return r;
+ 		}
+
+	// Set current offset into user descriptor
+	iCurrentUserWriteIndex = 0;
+
+	// Make sure iJob is valid before we use it
+	iJob = iParent.PddChan()->GetJobAes();
+
+
+#ifdef HW_PERF_CHECK
+	iJob->HwPerfCheck();
+#else
+	// Feed some data to the PDD
+	r = DataRequired(); // Fake PDD callback to get data from us.
+	if(r != KErrNone)
+		{
+		iAesWriteStatus = 0;
+		return r;
+ 		}
+
+	// Make sure job is not stalled, and maybe (re)add to job list.
+	iJob->Resume();
+#endif
+	
+	return KErrNone;
+    }
+
+
+TInt DLddChanAes::AesRead(TRequestStatus* aStatus, TDes8* aPtr, TUint32 aLength)
+    {
+	TRACE_FUNCTION("AesRead");
+	//	Kern::Printf("DLddChanAes::AesRead");
+    // Check that an Aes Read isn't already in progress
+    if(iAesReadStatus)
+        {
+        Kern::ThreadKill(iParent.iClient,EExitPanic,ERequestAlreadyPending,KCryptoPanicCategory);
+        return KErrInUse;
+        }
+
+	// We only support a single outstanding Aes Read request in this LDD
+	// channel, but the PDD supports multiple requests.
+
+    // Save the client request status and descriptor
+    iAesReadStatus = aStatus;
+    iAesReadDescriptor = aPtr;
+	iReadRequestLength = aLength;
+
+	// Retrieve user request length (ie. current length of user descriptor) into iRequestLength
+	//	TInt iOriginalUserReadDescLength;
+	TUint8 *aesReadDescriptorBufferRaw;
+	TInt maxLen;
+	TInt r=Kern::ThreadGetDesInfo(iParent.iClient, iAesReadDescriptor, iOriginalUserReadDescLength, maxLen, aesReadDescriptorBufferRaw, ETrue);
+	if(r != KErrNone)
+		{
+		iAesReadStatus = 0;
+		return r;
+ 		}
+
+	if(iReadRequestLength > (maxLen - iOriginalUserReadDescLength))
+		{
+		return KErrArgument;
+		}
+
+	// Set current offset into user descriptor
+	iCurrentUserReadIndex = 0;
+
+	// Tell PDD our request length so it can optimse returning the data to us.
+	iJob->NotifyReadRequestLength(iReadRequestLength);
+	
+
+#ifndef HW_PERF_CHECK
+	// Make sure iJob is valid before we use it
+	iJob = iParent.PddChan()->GetJobAes();
+
+	// Process any data already available
+	r = DataAvailable(); // Fake PDD callback to read data from PDD
+	if(r != KErrNone)
+		{
+		iAesReadStatus = 0;
+		return r;
+ 		}
+
+	// Make sure job is not stalled (and maybe re-add to job list) We
+	// do this even if we completely satisified the read from the PDD
+	// buffer because a write might be waiting for space in the
+	// buffer...
+	iJob->Resume();
+#endif
+
+	return KErrNone;
+	}
+
+
+
+TInt DLddChanAes::DataRequired()
+	{
+	TRACE_FUNCTION("DataRequired");
+	//	Kern::Printf("DLddChanAes::DataRequired");
+	if(!iAesWriteStatus)
+		{
+		return KErrNone;
+		}
+	
+	TBool moreSpace = ETrue;
+	TInt toWrite = (iWriteRequestLength - iCurrentUserWriteIndex);
+	while(toWrite && moreSpace)
+		{
+		// Get details of PDD write buffer
+		TUint8 *pddBuf; // always valid, though pddBufLen might be 0
+		TUint32 pddBufLen; // maybe 0
+		iJob->GetToPddBuffer(pddBuf, pddBufLen, moreSpace);
+
+		if(toWrite > pddBufLen)
+			{
+			toWrite = pddBufLen;
+			}
+
+		// Make sure there is some data to write
+		if(toWrite == 0)
+			{
+			break;
+			}
+
+		TPtr8 des(pddBuf, toWrite);
+		TInt r=Kern::ThreadDesRead(iParent.iClient, iAesWriteDescriptor, des, iCurrentUserWriteIndex);
+		//TInt r = 0;
+		if(r!=KErrNone)
+			return r;
+		iCurrentUserWriteIndex += toWrite;
+		// Tell the PDD how many bytes we wrote to it.
+		// If we wrote data, and the job was not already queued, the
+		// PDD will call ScheduleJob for it.
+		iJob->BytesWrittenToPdd(toWrite);
+
+		// Update count of bytes left to write
+		toWrite = (iWriteRequestLength - iCurrentUserWriteIndex);
+		};
+
+	if((iWriteRequestLength - iCurrentUserWriteIndex) <= 0)
+		{
+		// Write request is complete
+		// Finished with client descriptor, so NULL it to help detect coding errors
+		iAesWriteDescriptor = NULL;
+		// Complete client's request
+		Kern::RequestComplete(iParent.iClient,iAesWriteStatus, KErrNone);
+		return KErrNone;
+		}
+
+	return KErrNone;
+	}
+
+TInt DLddChanAes::DataAvailable()
+	{
+	TRACE_FUNCTION("DataAvailable");
+	//	Kern::Printf("DLddChanAes::DataAvailable()");
+
+	if(!iAesReadStatus)
+		{
+		return KErrNone;
+		}
+
+	TInt r = KErrNone;
+
+	TUint8 *buf;
+	TUint32 bufLen;
+	TBool check = ETrue;
+	while(check)
+		{
+		iJob->GetFromPddBuffer(buf, bufLen, check);
+		if(bufLen)
+			{
+			TInt required = iReadRequestLength - iCurrentUserReadIndex;
+			TInt toTransfer = bufLen;
+			if(toTransfer > required)
+				{
+				toTransfer = required;
+				}
+			// Copy the current buffer to user land
+			TPtr8 des(buf, toTransfer, toTransfer);
+			r=Kern::ThreadDesWrite(iParent.iClient, iAesReadDescriptor, des, iOriginalUserReadDescLength + iCurrentUserReadIndex);
+			//r  = 0;
+			if(r != KErrNone)
+				{
+				break;
+				}
+			
+			// Update our index into the user descriptor
+			iCurrentUserReadIndex += toTransfer;
+
+			// Update h/w with number of bytes actually read
+			iJob->BytesReadFromPdd(toTransfer);
+
+			if(toTransfer != bufLen)
+				{
+				// We did not read all the available data, so do not
+				// re-query h/w
+				check = EFalse;
+				}
+			}
+		};
+
+	if((iReadRequestLength - iCurrentUserReadIndex) <= 0)
+		{
+		// Read request is complete
+		// Finished with client descriptor, so NULL it to help detect coding errors
+		iAesReadDescriptor = NULL;
+		// Complete client's request
+		Kern::RequestComplete(iParent.iClient,iAesReadStatus, KErrNone);
+		return KErrNone;
+		}
+
+	return KErrNone;
+	}
+
+
+
+
+
+/**
+  Called by PDD from a DFC to indicate that a Aes operation has completed.
+*/
+void DLddChanAes::JobComplete(TInt aResult)
+	{
+	TRACE_FUNCTION("JobComplete");
+	// Normally not used for AES, instead the job keeps running and
+	// DataAvailable/DataRequired complete the AesRead/AesWrite
+	// requests.
+	// 
+	// Will be called if xfer to/from user space fails (or if another
+	// fatal error occurs).
+    if(iAesReadStatus)
+        {
+        // Finished with client descriptor, so NULL it to help detect coding errors
+        iAesReadDescriptor = NULL;
+        // Complete clients request (nb following call set iAesReadStatus to 0)
+        Kern::RequestComplete(iParent.iClient,iAesReadStatus, aResult);
+        }
+    if(iAesWriteStatus)
+        {
+        // Finished with client descriptor, so NULL it to help detect coding errors
+        iAesWriteDescriptor = NULL;
+        // Complete clients request (nb following call set iAesWriteStatus to 0)
+        Kern::RequestComplete(iParent.iClient,iAesWriteStatus, aResult);
+        }
+	}
+
+
+
+/**
+  Cancel a Aes Read request.
+*/
+void DLddChanAes::CancelRead()
+    {
+	TRACE_FUNCTION("CancelRead");
+    if(iAesReadStatus)
+        {
+        // Finished with client descriptor, so NULL it to help detect coding errors
+        iAesReadDescriptor = NULL;
+        // Complete clients request (nb following call set iAesReadStatus to 0)
+        Kern::RequestComplete(iParent.iClient,iAesReadStatus,KErrCancel);
+        }
+    }
+
+/**
+  Cancel a Aes Write request.
+*/
+void DLddChanAes::CancelWrite()
+    {
+	TRACE_FUNCTION("CancelWrite");
+    if(iAesWriteStatus)
+        {
+        // Finished with client descriptor, so NULL it to help detect coding errors
+        iAesWriteDescriptor = NULL;
+        // Complete clients request (nb following call set iAesWriteStatus to 0)
+        Kern::RequestComplete(iParent.iClient,iAesWriteStatus,KErrCancel);
+        }
+    }
+
+// End of file