diff -r 675a964f4eb5 -r 35751d3474b7 cryptoplugins/cryptospiplugins/test/h4drv/crypto_h4/cryptoldd.cpp --- /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 +#include +#include "cryptoldd.h" +#include +#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<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 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