sl@0: // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // sl@0: sl@0: /** sl@0: @file Example Logical Device Driver sl@0: @publishedPartner sl@0: @released sl@0: */ sl@0: sl@0: #include sl@0: #include "driver1.h" sl@0: #include "driver1_dev.h" sl@0: sl@0: _LIT(KDriver1PanicCategory,"Driver1"); sl@0: sl@0: sl@0: // sl@0: // DDriver1Factory sl@0: // sl@0: sl@0: /** sl@0: Standard export function for LDDs. This creates a DLogicalDevice derived object, sl@0: in this case, our DDriver1Factory sl@0: */ sl@0: DECLARE_STANDARD_LDD() sl@0: { sl@0: return new DDriver1Factory; sl@0: } sl@0: sl@0: /** sl@0: Constructor sl@0: */ sl@0: DDriver1Factory::DDriver1Factory() sl@0: { sl@0: // Set version number for this device sl@0: iVersion=RDriver1::VersionRequired(); sl@0: // Indicate that we work with a PDD sl@0: iParseMask=KDeviceAllowPhysicalDevice; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Second stage constructor for DDriver1Factory. sl@0: This must at least set a name for the driver object. sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DDriver1Factory::Install() sl@0: { sl@0: return SetName(&RDriver1::Name()); sl@0: } sl@0: sl@0: sl@0: /** sl@0: Destructor sl@0: */ sl@0: DDriver1Factory::~DDriver1Factory() sl@0: { sl@0: } sl@0: sl@0: sl@0: /** sl@0: Return the drivers capabilities. sl@0: Called in the response to an RDevice::GetCaps() request. sl@0: sl@0: @param aDes User-side descriptor to write capabilities information into sl@0: */ sl@0: void DDriver1Factory::GetCaps(TDes8& aDes) const sl@0: { sl@0: // Create a capabilities object sl@0: RDriver1::TCaps caps; sl@0: caps.iVersion = iVersion; sl@0: // Write it back to user memory sl@0: Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps)); sl@0: } sl@0: sl@0: /** sl@0: Called by the kernel's device driver framework to create a Logical Channel. sl@0: This is called in the context of the user thread (client) which requested the creation of a Logical Channel sl@0: (E.g. through a call to RBusLogicalChannel::DoCreate) sl@0: The thread is in a critical section. sl@0: sl@0: @param aChannel Set to point to the created Logical Channel sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DDriver1Factory::Create(DLogicalChannelBase*& aChannel) sl@0: { sl@0: aChannel=new DDriver1Channel; sl@0: if(!aChannel) sl@0: return KErrNoMemory; sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: // sl@0: // Logical Channel sl@0: // sl@0: sl@0: /** sl@0: Constructor sl@0: */ sl@0: DDriver1Channel::DDriver1Channel() sl@0: : iSendDataDfc(SendDataDfc, this, 1), // DFC is priority '1' sl@0: iReceiveDataDfc(ReceiveDataDfc, this, 1) // DFC is priority '1' sl@0: { sl@0: // Get pointer to client threads DThread object sl@0: iClient=&Kern::CurrentThread(); sl@0: sl@0: // Open a reference on client thread so it's control block can't dissapear until sl@0: // this driver has finished with it. sl@0: // Note, this call to Open can't fail since its the thread we are currently running in sl@0: iClient->Open(); sl@0: } sl@0: sl@0: /** sl@0: Second stage constructor called by the kernel's device driver framework. sl@0: This is called in the context of the user thread (client) which requested the creation of a Logical Channel sl@0: (E.g. through a call to RBusLogicalChannel::DoCreate) sl@0: The thread is in a critical section. sl@0: sl@0: @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate sl@0: @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate sl@0: @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate sl@0: sl@0: @return KErrNone if successful, otherwise one of the other system wide error codes. sl@0: */ sl@0: TInt DDriver1Channel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer) sl@0: { sl@0: // Check Platform Security capabilities of client thread (if required). sl@0: // sl@0: // Here we handle the simple case where: sl@0: // 1. The device driver can only have one client thread sl@0: // 2. The security policy is the binary all-or-nothing policy. sl@0: // E.g. "If you have the right capability you can do anything with the driver sl@0: // and if you don't have the capability you can't do anything" sl@0: // sl@0: // If only some functionality of the driver is restricted, then the security check should sl@0: // go elsewhere. E.g. in DoRequest/DoControl. In that case Kern::CurrentThreadHasCapability sl@0: // shouldn't be used because the 'current thread' isn't the client. sl@0: // sl@0: // In this example we do a check here for ECapability_None (which always passes)... sl@0: if(!Kern::CurrentThreadHasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by DRIVER1"))) sl@0: return KErrPermissionDenied; sl@0: sl@0: // Check version sl@0: if (!Kern::QueryVersionSupported(RDriver1::VersionRequired(),aVer)) sl@0: return KErrNotSupported; sl@0: sl@0: // Setup LDD for receiving client messages sl@0: SetDfcQ(((DDevice1PddFactory*)iPhysicalDevice)->iDfcQ); sl@0: iMsgQ.Receive(); sl@0: sl@0: // Associate DFCs with the same queue we set above to receive client messages on sl@0: iSendDataDfc.SetDfcQ(iDfcQ); sl@0: iReceiveDataDfc.SetDfcQ(iDfcQ); sl@0: sl@0: // Give PDD a pointer to this channel sl@0: Pdd()->iLdd=this; sl@0: sl@0: // Done sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Destructor sl@0: */ sl@0: DDriver1Channel::~DDriver1Channel() sl@0: { sl@0: // Cancel all processing that we may be doing sl@0: DoCancel(RDriver1::EAllRequests); sl@0: // Close our reference on the client thread sl@0: Kern::SafeClose((DObject*&)iClient,NULL); sl@0: } sl@0: sl@0: /** sl@0: Called when a user thread requests a handle to this channel. sl@0: */ sl@0: TInt DDriver1Channel::RequestUserHandle(DThread* aThread, TOwnerType aType) sl@0: { sl@0: // Make sure that only our client can get a handle sl@0: if (aType!=EOwnerThread || aThread!=iClient) sl@0: return KErrAccessDenied; sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Process a message for this logical channel. sl@0: This function is called in the context of a DFC thread. sl@0: sl@0: @param aMessage The message to process. sl@0: The iValue member of this distinguishes the message type: sl@0: iValue==ECloseMsg, channel close message sl@0: iValue==KMaxTInt, a 'DoCancel' message sl@0: iValue>=0, a 'DoControl' message with function number equal to iValue sl@0: iValue<0, a 'DoRequest' message with function number equal to ~iValue sl@0: */ sl@0: void DDriver1Channel::HandleMsg(TMessageBase* aMsg) sl@0: { sl@0: TThreadMessage& m=*(TThreadMessage*)aMsg; sl@0: sl@0: // Get message type sl@0: TInt id=m.iValue; sl@0: sl@0: // Decode the message type and dispatch it to the relevent handler function... sl@0: sl@0: if (id==(TInt)ECloseMsg) sl@0: { sl@0: // Channel Close sl@0: DoCancel(RDriver1::EAllRequests); sl@0: m.Complete(KErrNone, EFalse); sl@0: return; sl@0: } sl@0: sl@0: if (id==KMaxTInt) sl@0: { sl@0: // DoCancel sl@0: DoCancel(m.Int0()); sl@0: m.Complete(KErrNone,ETrue); sl@0: return; sl@0: } sl@0: sl@0: if (id<0) sl@0: { sl@0: // DoRequest sl@0: TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); sl@0: TInt r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2()); sl@0: if (r!=KErrNone) sl@0: Kern::RequestComplete(iClient,pS,r); sl@0: m.Complete(KErrNone,ETrue); sl@0: } sl@0: else sl@0: { sl@0: // DoControl sl@0: TInt r=DoControl(id,m.Ptr0(),m.Ptr1()); sl@0: m.Complete(r,ETrue); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Process synchronous 'control' requests sl@0: */ sl@0: TInt DDriver1Channel::DoControl(TInt aFunction, TAny* a1, TAny* a2) sl@0: { sl@0: (void)a2; // a2 not used in this example sl@0: sl@0: TInt r; sl@0: sl@0: switch (aFunction) sl@0: { sl@0: case RDriver1::EGetConfig: sl@0: r = GetConfig((TDes8*)a1); sl@0: break; sl@0: sl@0: case RDriver1::ESetConfig: sl@0: r = SetConfig((const TDesC8*)a1); sl@0: break; sl@0: sl@0: default: sl@0: r = KErrNotSupported; sl@0: break; sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Process asynchronous requests. sl@0: */ sl@0: TInt DDriver1Channel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2) sl@0: { sl@0: (void)a2; // a2 not used in this example sl@0: sl@0: TInt r; sl@0: sl@0: switch(aReqNo) sl@0: { sl@0: case RDriver1::ESendData: sl@0: r=SendData(aStatus,(const TDesC8*)a1); sl@0: break; sl@0: sl@0: case RDriver1::EReceiveData: sl@0: // Example Platform Security capability check which tests the sl@0: // client for ECapability_None (which always passes)... sl@0: if(iClient->HasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by DRIVER1"))) sl@0: r=ReceiveData(aStatus,(TDes8*)a1); sl@0: else sl@0: r=KErrPermissionDenied; sl@0: break; sl@0: sl@0: default: sl@0: r = KErrNotSupported; sl@0: break; sl@0: } sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Process cancelling of asynchronous requests. sl@0: */ sl@0: void DDriver1Channel::DoCancel(TUint aMask) sl@0: { sl@0: if(aMask&(1<BufferSize()) sl@0: return KErrArgument; sl@0: sl@0: if(config.iMaxSendDataSize && config.iMaxSendDataSize!=iSendDataBuffer.MaxSize()) sl@0: return KErrArgument; sl@0: sl@0: if(config.iMaxReceiveDataSize && config.iMaxReceiveDataSize!=iReceiveDataBuffer.MaxSize()) sl@0: return KErrArgument; sl@0: sl@0: r=Pdd()->SetSpeed(config.iSpeed); sl@0: if(r!=KErrNone) sl@0: return r; sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: Fill a TConfig with the drivers current configuration. sl@0: */ sl@0: void DDriver1Channel::CurrentConfig(RDriver1::TConfig& aConfig) sl@0: { sl@0: aConfig.iSpeed = Pdd()->Speed(); sl@0: aConfig.iPddBufferSize = Pdd()->BufferSize(); sl@0: aConfig.iMaxSendDataSize = iSendDataBuffer.MaxSize(); sl@0: aConfig.iMaxReceiveDataSize = iReceiveDataBuffer.MaxSize(); sl@0: } sl@0: sl@0: // sl@0: // Methods for processing 'SendData' sl@0: // sl@0: sl@0: /** sl@0: Start processing a SendData request. sl@0: */ sl@0: TInt DDriver1Channel::SendData(TRequestStatus* aStatus,const TDesC8* aData) sl@0: { sl@0: // Check that a 'SendData' isn't already in progress sl@0: if(iSendDataStatus) sl@0: { sl@0: Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KDriver1PanicCategory); sl@0: return KErrInUse; sl@0: } sl@0: sl@0: // Read data from client into our buffer sl@0: TInt r=Kern::ThreadDesRead(iClient,aData,iSendDataBuffer,0); sl@0: if(r!=KErrNone) sl@0: return r; sl@0: sl@0: // Give data to PDD so that it can do the work sl@0: r=Pdd()->SendData(iSendDataBuffer); sl@0: if(r!=KErrNone) sl@0: return r; sl@0: sl@0: // Save the client request status and return sl@0: iSendDataStatus = aStatus; sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Cancel a SendData request. sl@0: */ sl@0: void DDriver1Channel::SendDataCancel() sl@0: { sl@0: if(iSendDataStatus) sl@0: { sl@0: // Tell PDD to stop processing the request sl@0: Pdd()->SendDataCancel(); sl@0: // Cancel DFC sl@0: iSendDataDfc.Cancel(); sl@0: // Complete clients request sl@0: Kern::RequestComplete(iClient,iSendDataStatus,KErrCancel); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Called by PDD from ISR to indicate that a SendData operation has completed. sl@0: */ sl@0: void DDriver1Channel::SendDataComplete(TInt aResult) sl@0: { sl@0: // Save result code sl@0: iSendDataResult = aResult; sl@0: // Queue DFC sl@0: iSendDataDfc.Add(); sl@0: } sl@0: sl@0: /** sl@0: DFC callback which gets triggered after the PDD has signalled that SendData completed. sl@0: This just casts aPtr and calls DoSendDataComplete(). sl@0: */ sl@0: void DDriver1Channel::SendDataDfc(TAny* aPtr) sl@0: { sl@0: ((DDriver1Channel*)aPtr)->DoSendDataComplete(); sl@0: } sl@0: sl@0: /** sl@0: Called from a DFC after the PDD has signalled that SendData completed. sl@0: */ sl@0: void DDriver1Channel::DoSendDataComplete() sl@0: { sl@0: TInt result = iSendDataResult; sl@0: // Complete clients request sl@0: Kern::RequestComplete(iClient,iSendDataStatus,result); sl@0: } sl@0: sl@0: // sl@0: // Methods for processing 'ReceiveData' sl@0: // sl@0: sl@0: /** sl@0: Start processing a ReceiveData request. sl@0: */ sl@0: TInt DDriver1Channel::ReceiveData(TRequestStatus* aStatus,TDes8* aPtr) sl@0: { sl@0: // Check that a 'ReceiveData' isn't already in progress sl@0: if(iReceiveDataStatus) sl@0: { sl@0: Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KDriver1PanicCategory); sl@0: return KErrInUse; sl@0: } sl@0: sl@0: // Ask PDD for data sl@0: TInt r=Pdd()->ReceiveData(iReceiveDataBuffer); sl@0: if(r!=KErrNone) sl@0: return r; sl@0: sl@0: // Save the client request status and descriptor before returning sl@0: iReceiveDataStatus = aStatus; sl@0: iReceiveDataDescriptor = aPtr; sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Cancel a ReceiveData request. sl@0: */ sl@0: void DDriver1Channel::ReceiveDataCancel() sl@0: { sl@0: if(iReceiveDataStatus) sl@0: { sl@0: // Tell PDD to stop processing the request sl@0: Pdd()->ReceiveDataCancel(); sl@0: // Cancel DFC sl@0: iReceiveDataDfc.Cancel(); sl@0: // Finished with client descriptor, so NULL it to help detect coding errors sl@0: iReceiveDataDescriptor = NULL; sl@0: // Complete clients request sl@0: Kern::RequestComplete(iClient,iReceiveDataStatus,KErrCancel); sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Called by PDD from ISR to indicate that a ReceiveData operation has completed. sl@0: */ sl@0: void DDriver1Channel::ReceiveDataComplete(TInt aResult) sl@0: { sl@0: // Save result code sl@0: iReceiveDataResult = aResult; sl@0: // Queue DFC sl@0: iReceiveDataDfc.Add(); sl@0: } sl@0: sl@0: /** sl@0: DFC Callback which gets triggered after the PDD has signalled that ReceiveData completed. sl@0: This just casts aPtr and calls DoReceiveDataComplete(). sl@0: */ sl@0: void DDriver1Channel::ReceiveDataDfc(TAny* aPtr) sl@0: { sl@0: ((DDriver1Channel*)aPtr)->DoReceiveDataComplete(); sl@0: } sl@0: sl@0: /** sl@0: Called from a DFC after the PDD has signalled that ReceiveData completed. sl@0: */ sl@0: void DDriver1Channel::DoReceiveDataComplete() sl@0: { sl@0: // Write data to client from our buffer sl@0: TInt result=Kern::ThreadDesWrite(iClient,iReceiveDataDescriptor,iReceiveDataBuffer,0); sl@0: sl@0: // Finished with client descriptor, so NULL it to help detect coding errors sl@0: iReceiveDataDescriptor = NULL; sl@0: sl@0: // Use result code from PDD if it was an error sl@0: if(iReceiveDataResult!=KErrNone) sl@0: result = iReceiveDataResult; sl@0: sl@0: // Complete clients request sl@0: Kern::RequestComplete(iClient,iReceiveDataStatus,result); sl@0: } sl@0: