Factory Implementation

Describes how to implement a factory.

The Serial Port Driver PDD must provide a factory class to create channels. The purpose of the PDD factory is to create the physical channel. For the Uart, this is defined by the DDriverComm class, which is derived from DPhysicalDevice. The class is defined in the Uart source code:

class DDriverComm : public DPhysicalDevice
    {
public:
    DDriverComm();
    virtual TInt Install();
    virtual void GetCaps(TDes8 &aDes) const;
    virtual TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion &aVer);
    virtual TInt Validate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer);
    };

This implements the four virtual functions that the base class defines, as well as a default constructor.

Install()

Install() sets the driver name. The name is the way that the physical device is identified. The name is the same as the LDD name, but followed by a dot and a short string to represent the physical device. If you have similar existing source, just copy from there. The function is implemented as:

TInt DDriverComm::Install()
    {
    return SetName(&KPddName);
    }

In the template port, the name is the string Comm.Template.

See also DPhysicalDevice::Install()

GetCaps()

GetCaps() returns the capabilities of the physical driver factory (not the driver object). Since driver factories all produce polymorphic objects there is no point in differentiating between them so the function should ignore the passed in descriptor reference. The driver object’s capabilities are returned by the DComm derived Caps() function.

GetCaps() can be implemented as a stub function, i.e.:

Void DDriverComm::GetCaps(TDes8&  /* aDes */)
    {
    }

See also DPhysicalDevice::GetCaps()

Validate()

Validate() verifies that the physical driver version is compatible with the caller’s version. This function can be copied in its entirety from any current driver source. It also checks that the unit number used to create a physical channel object is valid, typically checking that the number lies within a valid range.

TInt DDriverComm::Validate(TInt aUnit, const TDesC8* /*anInfo*/, const TVersion& aVer)
    {
    if (
        (!Kern::QueryVersionSupported(iVersion,aVer)) || 
        (!Kern::QueryVersionSupported(aVer,TVersion(KMinimumLddMajorVersion,KMinimumLddMinorVersion,KMinimumLddBuild)))
       )
    return KErrNotSupported;
    if (aUnit<UART_UNIT_OFFSET || aUnit>=(UART_TOTAL_NUMBER_UNITS+UART_UNIT_OFFSET))
        return KErrNotSupported;
    return KErrNone;
    }

Note that iVersion is a data member in the base class DPhysicalDevice.

See also:

Create()

Create() creates and returns a pointer to the physical channel object through the DBase *& type argument. In the case of serial device drivers, a physical channel is an instance of a class derived from DComm, which is itself derived from DBase.

Implementing this function may involve:

  • setting up any port related hardware; for example, defining GPIO pins as UART port I/O

  • initialising the UART device itself; for example, enabling UART clock sources

  • binding any interrupt resources to the UART Interrupt Service Routine (ISR).

The function sets a reference argument to point to the newly instantiated physical channel object, but returns an error code if object allocation or initialisation fails, i.e. the call to the physical channel object’s DoCreate() function fails. Error codes are returned to the caller.

This code is typical, and can be copied from any current source.

TInt DDriverComm::Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion& aVer)
    {
    DCommXXX* pD=new DCommXXX;
    aChannel=pD;
    TInt r=KErrNoMemory;
    if (pD)
        r=pD->DoCreate(aUnit,anInfo);
    return r;
    }

where DCommXXX is a DComm derived class.

Customisation depends on the functions in the DCommXXX::DoCreate() function.