First public contribution.
1 // Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
2 // All rights reserved.
3 // This component and the accompanying materials are made available
4 // under the terms of the License "Eclipse Public License v1.0"
5 // which accompanies this distribution, and is available
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
8 // Initial Contributors:
9 // Nokia Corporation - initial contribution.
17 @file Example Logical Device Driver
22 #include <kernel/kern_priv.h>
24 #include "driver1_dev.h"
26 _LIT(KDriver1PanicCategory,"Driver1");
34 Standard export function for LDDs. This creates a DLogicalDevice derived object,
35 in this case, our DDriver1Factory
37 DECLARE_STANDARD_LDD()
39 return new DDriver1Factory;
45 DDriver1Factory::DDriver1Factory()
47 // Set version number for this device
48 iVersion=RDriver1::VersionRequired();
49 // Indicate that we work with a PDD
50 iParseMask=KDeviceAllowPhysicalDevice;
55 Second stage constructor for DDriver1Factory.
56 This must at least set a name for the driver object.
58 @return KErrNone if successful, otherwise one of the other system wide error codes.
60 TInt DDriver1Factory::Install()
62 return SetName(&RDriver1::Name());
69 DDriver1Factory::~DDriver1Factory()
75 Return the drivers capabilities.
76 Called in the response to an RDevice::GetCaps() request.
78 @param aDes User-side descriptor to write capabilities information into
80 void DDriver1Factory::GetCaps(TDes8& aDes) const
82 // Create a capabilities object
84 caps.iVersion = iVersion;
85 // Write it back to user memory
86 Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
90 Called by the kernel's device driver framework to create a Logical Channel.
91 This is called in the context of the user thread (client) which requested the creation of a Logical Channel
92 (E.g. through a call to RBusLogicalChannel::DoCreate)
93 The thread is in a critical section.
95 @param aChannel Set to point to the created Logical Channel
97 @return KErrNone if successful, otherwise one of the other system wide error codes.
99 TInt DDriver1Factory::Create(DLogicalChannelBase*& aChannel)
101 aChannel=new DDriver1Channel;
115 DDriver1Channel::DDriver1Channel()
116 : iSendDataDfc(SendDataDfc, this, 1), // DFC is priority '1'
117 iReceiveDataDfc(ReceiveDataDfc, this, 1) // DFC is priority '1'
119 // Get pointer to client threads DThread object
120 iClient=&Kern::CurrentThread();
122 // Open a reference on client thread so it's control block can't dissapear until
123 // this driver has finished with it.
124 // Note, this call to Open can't fail since its the thread we are currently running in
129 Second stage constructor called by the kernel's device driver framework.
130 This is called in the context of the user thread (client) which requested the creation of a Logical Channel
131 (E.g. through a call to RBusLogicalChannel::DoCreate)
132 The thread is in a critical section.
134 @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
135 @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
136 @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate
138 @return KErrNone if successful, otherwise one of the other system wide error codes.
140 TInt DDriver1Channel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
142 // Check Platform Security capabilities of client thread (if required).
144 // Here we handle the simple case where:
145 // 1. The device driver can only have one client thread
146 // 2. The security policy is the binary all-or-nothing policy.
147 // E.g. "If you have the right capability you can do anything with the driver
148 // and if you don't have the capability you can't do anything"
150 // If only some functionality of the driver is restricted, then the security check should
151 // go elsewhere. E.g. in DoRequest/DoControl. In that case Kern::CurrentThreadHasCapability
152 // shouldn't be used because the 'current thread' isn't the client.
154 // In this example we do a check here for ECapability_None (which always passes)...
155 if(!Kern::CurrentThreadHasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by DRIVER1")))
156 return KErrPermissionDenied;
159 if (!Kern::QueryVersionSupported(RDriver1::VersionRequired(),aVer))
160 return KErrNotSupported;
162 // Setup LDD for receiving client messages
163 SetDfcQ(((DDevice1PddFactory*)iPhysicalDevice)->iDfcQ);
166 // Associate DFCs with the same queue we set above to receive client messages on
167 iSendDataDfc.SetDfcQ(iDfcQ);
168 iReceiveDataDfc.SetDfcQ(iDfcQ);
170 // Give PDD a pointer to this channel
180 DDriver1Channel::~DDriver1Channel()
182 // Cancel all processing that we may be doing
183 DoCancel(RDriver1::EAllRequests);
184 // Close our reference on the client thread
185 Kern::SafeClose((DObject*&)iClient,NULL);
189 Called when a user thread requests a handle to this channel.
191 TInt DDriver1Channel::RequestUserHandle(DThread* aThread, TOwnerType aType)
193 // Make sure that only our client can get a handle
194 if (aType!=EOwnerThread || aThread!=iClient)
195 return KErrAccessDenied;
200 Process a message for this logical channel.
201 This function is called in the context of a DFC thread.
203 @param aMessage The message to process.
204 The iValue member of this distinguishes the message type:
205 iValue==ECloseMsg, channel close message
206 iValue==KMaxTInt, a 'DoCancel' message
207 iValue>=0, a 'DoControl' message with function number equal to iValue
208 iValue<0, a 'DoRequest' message with function number equal to ~iValue
210 void DDriver1Channel::HandleMsg(TMessageBase* aMsg)
212 TThreadMessage& m=*(TThreadMessage*)aMsg;
217 // Decode the message type and dispatch it to the relevent handler function...
219 if (id==(TInt)ECloseMsg)
222 DoCancel(RDriver1::EAllRequests);
223 m.Complete(KErrNone, EFalse);
231 m.Complete(KErrNone,ETrue);
238 TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
239 TInt r=DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
241 Kern::RequestComplete(iClient,pS,r);
242 m.Complete(KErrNone,ETrue);
247 TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
253 Process synchronous 'control' requests
255 TInt DDriver1Channel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
257 (void)a2; // a2 not used in this example
263 case RDriver1::EGetConfig:
264 r = GetConfig((TDes8*)a1);
267 case RDriver1::ESetConfig:
268 r = SetConfig((const TDesC8*)a1);
272 r = KErrNotSupported;
280 Process asynchronous requests.
282 TInt DDriver1Channel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
284 (void)a2; // a2 not used in this example
290 case RDriver1::ESendData:
291 r=SendData(aStatus,(const TDesC8*)a1);
294 case RDriver1::EReceiveData:
295 // Example Platform Security capability check which tests the
296 // client for ECapability_None (which always passes)...
297 if(iClient->HasCapability(ECapability_None,__PLATSEC_DIAGNOSTIC_STRING("Checked by DRIVER1")))
298 r=ReceiveData(aStatus,(TDes8*)a1);
300 r=KErrPermissionDenied;
304 r = KErrNotSupported;
312 Process cancelling of asynchronous requests.
314 void DDriver1Channel::DoCancel(TUint aMask)
316 if(aMask&(1<<RDriver1::ESendData))
318 if(aMask&(1<<RDriver1::EReceiveData))
323 // Methods for processing configuration control messages
327 Process a GetConfig control message. This writes the current driver configuration to a
328 RDriver1::TConfigBuf supplied by the client.
330 TInt DDriver1Channel::GetConfig(TDes8* aConfigBuf)
332 // Create a structure giving the current configuration
333 RDriver1::TConfig config;
334 CurrentConfig(config);
336 // Write the config to the client
337 TPtrC8 ptr((const TUint8*)&config,sizeof(config));
338 return Kern::ThreadDesWrite(iClient,aConfigBuf,ptr,0,KTruncateToMaxLength,NULL);
342 Process a SetConfig control message. This sets the driver configuration using a
343 RDriver1::TConfigBuf supplied by the client.
345 TInt DDriver1Channel::SetConfig(const TDesC8* aConfigBuf)
347 // Don't allow configuration changes whilst we're busy
348 if(iSendDataStatus || iReceiveDataStatus)
351 // Create a config structure.
352 RDriver1::TConfig config;
353 CurrentConfig(config);
355 // Note: We have filled config with the current settings, this is to allow
356 // backwards compatibility when a client gives us an old (and shorter) version
357 // of the config structure.
359 // Read the config structure from client
360 TPtr8 ptr((TUint8*)&config,sizeof(config));
361 TInt r=Kern::ThreadDesRead(iClient,aConfigBuf,ptr,0);
365 // Use config data to setup the driver. Checking that parameters which aren't settable
366 // either contain the correct values or are zero (meaning 'default')
367 if(config.iPddBufferSize && config.iPddBufferSize!=Pdd()->BufferSize())
370 if(config.iMaxSendDataSize && config.iMaxSendDataSize!=iSendDataBuffer.MaxSize())
373 if(config.iMaxReceiveDataSize && config.iMaxReceiveDataSize!=iReceiveDataBuffer.MaxSize())
376 r=Pdd()->SetSpeed(config.iSpeed);
384 Fill a TConfig with the drivers current configuration.
386 void DDriver1Channel::CurrentConfig(RDriver1::TConfig& aConfig)
388 aConfig.iSpeed = Pdd()->Speed();
389 aConfig.iPddBufferSize = Pdd()->BufferSize();
390 aConfig.iMaxSendDataSize = iSendDataBuffer.MaxSize();
391 aConfig.iMaxReceiveDataSize = iReceiveDataBuffer.MaxSize();
395 // Methods for processing 'SendData'
399 Start processing a SendData request.
401 TInt DDriver1Channel::SendData(TRequestStatus* aStatus,const TDesC8* aData)
403 // Check that a 'SendData' isn't already in progress
406 Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KDriver1PanicCategory);
410 // Read data from client into our buffer
411 TInt r=Kern::ThreadDesRead(iClient,aData,iSendDataBuffer,0);
415 // Give data to PDD so that it can do the work
416 r=Pdd()->SendData(iSendDataBuffer);
420 // Save the client request status and return
421 iSendDataStatus = aStatus;
426 Cancel a SendData request.
428 void DDriver1Channel::SendDataCancel()
432 // Tell PDD to stop processing the request
433 Pdd()->SendDataCancel();
435 iSendDataDfc.Cancel();
436 // Complete clients request
437 Kern::RequestComplete(iClient,iSendDataStatus,KErrCancel);
442 Called by PDD from ISR to indicate that a SendData operation has completed.
444 void DDriver1Channel::SendDataComplete(TInt aResult)
447 iSendDataResult = aResult;
453 DFC callback which gets triggered after the PDD has signalled that SendData completed.
454 This just casts aPtr and calls DoSendDataComplete().
456 void DDriver1Channel::SendDataDfc(TAny* aPtr)
458 ((DDriver1Channel*)aPtr)->DoSendDataComplete();
462 Called from a DFC after the PDD has signalled that SendData completed.
464 void DDriver1Channel::DoSendDataComplete()
466 TInt result = iSendDataResult;
467 // Complete clients request
468 Kern::RequestComplete(iClient,iSendDataStatus,result);
472 // Methods for processing 'ReceiveData'
476 Start processing a ReceiveData request.
478 TInt DDriver1Channel::ReceiveData(TRequestStatus* aStatus,TDes8* aPtr)
480 // Check that a 'ReceiveData' isn't already in progress
481 if(iReceiveDataStatus)
483 Kern::ThreadKill(iClient,EExitPanic,ERequestAlreadyPending,KDriver1PanicCategory);
488 TInt r=Pdd()->ReceiveData(iReceiveDataBuffer);
492 // Save the client request status and descriptor before returning
493 iReceiveDataStatus = aStatus;
494 iReceiveDataDescriptor = aPtr;
499 Cancel a ReceiveData request.
501 void DDriver1Channel::ReceiveDataCancel()
503 if(iReceiveDataStatus)
505 // Tell PDD to stop processing the request
506 Pdd()->ReceiveDataCancel();
508 iReceiveDataDfc.Cancel();
509 // Finished with client descriptor, so NULL it to help detect coding errors
510 iReceiveDataDescriptor = NULL;
511 // Complete clients request
512 Kern::RequestComplete(iClient,iReceiveDataStatus,KErrCancel);
517 Called by PDD from ISR to indicate that a ReceiveData operation has completed.
519 void DDriver1Channel::ReceiveDataComplete(TInt aResult)
522 iReceiveDataResult = aResult;
524 iReceiveDataDfc.Add();
528 DFC Callback which gets triggered after the PDD has signalled that ReceiveData completed.
529 This just casts aPtr and calls DoReceiveDataComplete().
531 void DDriver1Channel::ReceiveDataDfc(TAny* aPtr)
533 ((DDriver1Channel*)aPtr)->DoReceiveDataComplete();
537 Called from a DFC after the PDD has signalled that ReceiveData completed.
539 void DDriver1Channel::DoReceiveDataComplete()
541 // Write data to client from our buffer
542 TInt result=Kern::ThreadDesWrite(iClient,iReceiveDataDescriptor,iReceiveDataBuffer,0);
544 // Finished with client descriptor, so NULL it to help detect coding errors
545 iReceiveDataDescriptor = NULL;
547 // Use result code from PDD if it was an error
548 if(iReceiveDataResult!=KErrNone)
549 result = iReceiveDataResult;
551 // Complete clients request
552 Kern::RequestComplete(iClient,iReceiveDataStatus,result);