Symbian3/PDK/Source/GUID-3F1E303E-2946-5D71-9D9B-9F4F5B1BC424.dita
author Dominic Pinkman <Dominic.Pinkman@Nokia.com>
Thu, 11 Mar 2010 18:02:22 +0000
changeset 3 46218c8b8afa
parent 1 25a17d01db0c
permissions -rw-r--r--
week 10 bug fix submission (SF PDK version): Bug 1892, Bug 1897, Bug 1319. Also 3 or 4 documents were found to contain code blocks with SFL, which has been fixed. Partial fix for broken links, links to Forum Nokia, and the 'Symbian platform' terminology issues.

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 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: 
-->
<!DOCTYPE concept
  PUBLIC "-//OASIS//DTD DITA Concept//EN" "concept.dtd">
<concept xml:lang="en" id="GUID-3F1E303E-2946-5D71-9D9B-9F4F5B1BC424"><title>driver1_pdd.cpp</title><prolog><metadata><keywords/></metadata></prolog><conbody><codeblock id="GUID-CC1D2B20-43E4-5605-9DA6-AB74D96D1F98" xml:space="preserve">// driver1_pdd.cpp
//
// Copyright (c) 2009 Nokia Ltd. All rights reserved.
//

/**
@file Example Pysical Device Driver
@publishedPartner
@released
*/

#include &lt;kern_priv.h&gt;
#include "driver1.h"
#include "driver1_dev.h"

// Name for PDD, must match LDD name with a '.' and distinguishing name appended
_LIT(KDriver1PddName,"DRIVER1.template");


class DDriver1Device : public DDriver1
    {
public:
    DDriver1Device(DDevice1PddFactory* aFactory);
    ~DDriver1Device();
    TInt DoCreate();
    // Inherited from DDriver1. These called by the LDD.
    virtual TInt BufferSize() const;
    virtual TInt Speed() const;
    virtual TInt SetSpeed(TInt aSpeed);
    virtual TInt SendData(const TDesC8&amp; aData);
    virtual void SendDataCancel();
    virtual TInt ReceiveData(TDes8&amp; aBuffer);
    virtual void ReceiveDataCancel();
private:
    static void SendDataTimerCallback(TAny* aPtr);
    void SendDataCallback();
    static void ReceiveDataTimerCallback(TAny* aPtr);
    void ReceiveDataCallback();
private:
    DDevice1PddFactory* iFactory;
    TInt iSpeed;
    NTimer iSendDataTimer;
    NTimer iReceiveDataTimer;
    TBuf8&lt;256&gt; iBuffer;
    TDes8* iReceiveBuffer;
    };



//
// DDevice1PddFactory
//

const TInt KDriver1ThreadPriority = 27;
_LIT(KDriver1Thread,"Driver1Thread");

/**
  Standard export function for PDDs. This creates a DPhysicalDevice derived object,
  in this case, our DDevice1PddFactory
*/
DECLARE_STANDARD_PDD()
    {
    DDevice1PddFactory* p = new DDevice1PddFactory;
    
    if (p)
    {
        // Allocate a kernel thread to run the DFC 
        TInt r = Kern::DynamicDfcQCreate(p-&gt;iDfcQ, KDriver1ThreadPriority, KDriver1Thread);

        if (r != KErrNone)
            { 
            delete p;
            return NULL;     
            }     
    }

    return p;
    }

DDevice1PddFactory::DDevice1PddFactory()
    {
    // Set version number for this device
    iVersion=RDriver1::VersionRequired();
    }

/**
  Second stage constructor for DPhysicalDevice derived objects.
  This must at least set a name for the driver object.

  @return KErrNone or standard error code.
*/
TInt DDevice1PddFactory::Install()
    {
    return SetName(&amp;KDriver1PddName);
    }

/**
  Returns the drivers capabilities. This is not used by the Symbian OS device driver framework
  but may be useful for the LDD to use.

  @param aDes Descriptor to write capabilities information into
*/
void DDevice1PddFactory::GetCaps(TDes8&amp; aDes) const
    {
    // Create a capabilities object
    DDriver1::TCaps caps;
    caps.iVersion = iVersion;
    // Zero the buffer
    TInt maxLen = aDes.MaxLength();
    aDes.FillZ(maxLen);
    // Copy cpabilities
    TInt size=sizeof(caps);
    if(size&gt;maxLen)
        size=maxLen;
    aDes.Copy((TUint8*)&amp;caps,size);
    }

/**
  Called by the kernel's device driver framework to create a Physical Channel.
  This is called in the context of the user thread (client) which requested the creation of a 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 Physical Channel
  @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 number of the Logical Channel which will use this Physical Channel 

  @return KErrNone or standard error code.
*/
TInt DDevice1PddFactory::Create(DBase*&amp; aChannel, TInt aUnit, const TDesC8* aInfo, const TVersion&amp; aVer)
    {
    // Ignore the parameters we aren't interested in...
    (void)aUnit;
    (void)aInfo;
    (void)aVer;

    // Create a new physical channel
    DDriver1Device* device=new DDriver1Device(this);
    aChannel=device;
    if (!device)
        return KErrNoMemory;
    return device-&gt;DoCreate();
    }

/**
  Called by the kernel's device driver framework to check if this PDD is suitable for use with a Logical Channel.
  This is called in the context of the user thread (client) which requested the creation of a 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 number of the Logical Channel which will use this Physical Channel 

  @return KErrNone or standard error code.
*/
TInt DDevice1PddFactory::Validate(TInt aUnit, const TDesC8* aInfo, const TVersion&amp; aVer)
    {
    // Check version numbers
    if ((!Kern::QueryVersionSupported(iVersion,aVer)) || (!Kern::QueryVersionSupported(aVer,TVersion(EMinimumLddMajorVersion,EMinimumLddMinorVersion,EMinimumLddBuild))))
        return KErrNotSupported;

    // We don't support units
    if (aUnit != -1)
        return KErrNotSupported;

    // Ignore extra info, (this could be used for validation purposes)
    // Note, aInof is a pointer to a descriptor in user memory, therefore safe methods should
    // be used for reading its contents. E.g. using Kern::KUDesGet()
    (void)aInfo;

    // OK
    return KErrNone;
    }

/**
  Destructor
*/
DDevice1PddFactory::~DDevice1PddFactory()
    {
    if (iDfcQ)
        iDfcQ-&gt;Destroy();
    }

//
// DDriver1Device
//

DDriver1Device::DDriver1Device(DDevice1PddFactory* aFactory)
    :    iFactory(aFactory),
        iSpeed(100000),  // 100000us (100ms) per byte
        iSendDataTimer(SendDataTimerCallback,this),
        iReceiveDataTimer(ReceiveDataTimerCallback,this)
    {
    }

DDriver1Device::~DDriver1Device()
    {
    // Driver no longer using hardware resources
    NKern::LockedDec(iFactory-&gt;iHardwareInUse);
    }

TInt DDriver1Device::DoCreate()
    {
    // Claim the hardware resources by incrementing iHardwareInUse.
    // Must do this before any other failure can happen in this function so that
    // the destructor can safely decrement iHardwareInUse.
    //
    // This method of ensuring hardware is only in use by one driver at a time
    // wouldn't be needed if the driver claimed real hardware resources which
    // could only be used once. E.g. binding to an interrupt.
    if(NKern::LockedInc(iFactory-&gt;iHardwareInUse))
        return KErrInUse;

    // Other setup goes here

    return KErrNone;
    }

TInt DDriver1Device::BufferSize() const
    {
    return iBuffer.MaxSize();
    }

TInt DDriver1Device::Speed() const
    {
    return iSpeed;
    }

TInt DDriver1Device::SetSpeed(TInt aSpeed)
    {
    if(aSpeed&lt;=0)
        return KErrArgument;
    iSpeed = aSpeed;
    return KErrNone;
    }

TInt DDriver1Device::SendData(const TDesC8&amp; aData)
    {
    // Save the last part of the data to 'send', we will pretend to 'receive' this later
    iBuffer=aData.Right(iBuffer.MaxSize());
    // Pretend to send the data by waiting for iSpeed micro-seconds per byte...
    iSendDataTimer.OneShot(aData.Size()*iSpeed/NKern::TickPeriod());

    return KErrNone;
    }

void DDriver1Device::SendDataCancel()
    {
    // Stop the timer we were using to pretend we were processing the send
    iSendDataTimer.Cancel();
    }

void DDriver1Device::SendDataTimerCallback(TAny* aPtr)
    {
    // Just forward callback to non-static callback function
    ((DDriver1Device*)aPtr)-&gt;SendDataCallback();
    }

void DDriver1Device::SendDataCallback()
    {
    // Tell LDD we've done
    iLdd-&gt;SendDataComplete(KErrNone);
    }

TInt DDriver1Device::ReceiveData(TDes8&amp; aBuffer)
    {
    // Save a pointer to the buffer we need to put the 'recevied' data in
    iReceiveBuffer=&amp;aBuffer;
    // Pretend to receive the data by waiting for iSpeed micro-seconds per byte...
    iReceiveDataTimer.OneShot(iBuffer.Size()*iSpeed/NKern::TickPeriod());

    return KErrNone;
    }

void DDriver1Device::ReceiveDataCancel()
    {
    // Stop the timer we were using to pretend we were processing the receive
    iReceiveDataTimer.Cancel();
    }

void DDriver1Device::ReceiveDataTimerCallback(TAny* aPtr)
    {
    // Just forward callback to non-static callback function
    ((DDriver1Device*)aPtr)-&gt;ReceiveDataCallback();
    }

void DDriver1Device::ReceiveDataCallback()
    {
    // Pretend the data we have received is that saved in iBuffer when we last did a send
    *iReceiveBuffer=iBuffer;
    // Tell LDD we've done
    iLdd-&gt;ReceiveDataComplete(KErrNone);
    }
</codeblock> </conbody></concept>