Understanding Function Driver Controllers

This section looks at example code in the Function Driver Controller (FDC) template and in a mass storage FDC implementation of the template.

Basic Procedure

An Function Driver Controller needs to complete the following tasks:

  1. Create a session between the Function Driver Controller and Function Driver Implementation

  2. Claim a token for an interface

  3. Gather descriptors

  4. Create a data structure of the descriptors

  5. Pass the token and data structure to Function Driver Implementation.

Creating a session and connecting to the Function Driver Implementation

In this code example (provided in the template), NewL() calls ContructL().

CRefFdc* CRefFdc::NewL(MFdcPluginObserver& aObserver)
    {
    CRefFdc* self = new(ELeave) CRefFdc(aObserver);
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }

ConstructL() needs to set up a private channel between the Function Driver Controller and the Function Driver Implementation. The following example is provided in a mass storage FDC implementation. In it the mass storage FDC sets up a connection with the mount manager.

void CRefFdc::ConstructL()
    {
    //Set up the connection with mount manager
    TInt error = iMsmmSession.Connect();
 //Handle errors
 }

Gathering information and passing it to the FDI

When the FDF discovers a device is attached, it calls Mfi1newFunction(), which does the following:

  1. Claims a token for the interface offered (from the FDF) and gets various strings from the device

  2. Creates a data structure containing all the information that the Function Driver Implementation needs

  3. Passes the token and data to the Function Driver Implementation.

The following example code shows a token being claimed for a mass storage device FDC:

    // Mass Storage FDC only claims one interface.
    TUint32 token = Observer().TokenForInterface(aInterfaces[0]);
    if (token == 0)
        {
        return KErrGeneral;
        }

This example code shows descriptors being collected and stored in a data structure a mass storage device FDC:

    //Get the languages that is supported by this device.
...
    //Get Serial number from string descriptor
...
        //Get Product string descriptor
...
        //Get Manufacturer string descriptor
...
        //Send information
    
    data->iConfigurationNumber   = aDeviceDescriptor.NumConfigurations();
    data->iBcdDevice             = aDeviceDescriptor.DeviceBcd();
    data->iDeviceId              = aDeviceId;
    data->iProductId             = aDeviceDescriptor.ProductId();
    data->iVendorId              = aDeviceDescriptor.VendorId();
 data->iHNPSupported          = aOtgDescriptor.HNPSupported();
 data->iSRPSupported          = aOtgDescriptor.SRPSupported();

It uses the session created in ContsructL() and tells it to pass a Function with the data structure and, most importantly, the token it claimed. The token is passed to the FDI. This example code for a mass storage FDC uses the session connected to earlier and passes the information:

    TRAP(error, addret = iMsmmSession.AddFunctionL(*data, aInterfaces[0], token));
    
    delete data;

From here the FDI sets up a session with the host driver and takes over the interface, allowing it to make data transfers. For information on implementing FDIs, see Writing a Function Driver Implementation.

To close down, a device identifier gets passed to the session created earlier and the session removes the device from its records.