Configuring Function Driver Controller Templates

This section explains how to configure the parts of the Function Driver Controller (FDC) template.

Basic Procedure

Symbian provides templates for Function Driver Controllers. You need to do the following to configure the templates:

  1. Copy the template files

  2. Change the names

  3. Change the UIDs

  4. Change data fields as required

  5. Implement the functions.

Copy the template files

Copy the template files from the following location:sf/os/shortlinksrv/usbmgmt/usbmgr/host/fdf/reference/reffdc/

Note: There is no template for creating FDIs because FDIs will usually be a plugin to an existing system framework and each implementation would be too different for a template to be useful. For information on FDIs, see Writing a Function Driver Implementation.

The file structure is that of a simple ECOM plugin, with an MMP file, an ECOM plugin resource (.rss) file and implementation proxy table, and a concrete class derived from CFdcPlugin.

Change the names

Rename directories, files and classes as appropriate, in particular reffdc and CRefFdc.

Change the UIDs

You need to change the DLL UID and the implementation UID. Obtain two new UIDs from the usual sources for this.

Change the DLL UID in the following places:

  • The MMP file, as UID3 (this is the second UID on the UID line)

  • The RSS file, in the dll_uid line.

The implementation UID is used in the following places:

  • The RSS file, in the implementation_uid line

  • The <main>.cpp, in the IMPLEMENTATION_PROXY_ENTRY table.

Change data fields as required

In the RSS file, change the display_name field to a string that is suitable for your Function Driver Controller. The FDF will log this when it starts up and when it offers the Function Driver Controller control of interfaces on a new device.

In the RSS file, change the default_data field. The FDF will use this field to identify Function Drivers for interfaces. It is important to get this field right.

The default_data field can be one of the following two formats:

  • <IC><ISC><IP>

  • <IC><ISC>.

The angle-bracket delimited fields above are defined in the table below.

Tag Textual description USB spec form Variable part of field contents

<IC>

Interface Class

bInterfaceClass

0x%02x

<ISC>

Interface Subclass

bInterfaceSubClass

0x%02x

<IP>

Interface Protocol

bInterfaceProtocol

0x%02x

Note: Each field consists of the tag name (omitting the angle brackets) followed by the relevant value concatenated directly in the C language hex format.

A Function Driver that uses the default_data format <IC><ISC><IP> may be thought of as a protocol-specific driver. It will only be offered interfaces by the FDF if an interface is found exactly matching the given interface class, subclass and protocol.

A Function Driver that uses the default_data format <IC><ISC> may be thought of as a generic driver. It will be offered interfaces matching the given interface class and subclass, regardless of their interface protocol setting. In accordance with the USB Common Class Specification v1.0, the handing of interfaces to ‘protocol-specific’ drivers happens before offering any left-over interfaces to ‘generic’ drivers.

This is an example default_data field: IC0x01ISC0x01. This field indicates that the function driver is intended for all interfaces with the AUDIO interface class code (0x01) and AUDIOCONTROL interface subclass code (0x01). If a device is attached with such an interface, the Function Driver Controller may be given an opportunity to take control of interfaces on the device. (This assumes that no other FD has taken control of them first.)

The following shows the ECOM plug-in resource file for such a Function Driver Controller:

// Copyright (c) Symbian Software Ltd 2007. All rights reserved.

/** @file
@internalComponent
*/

#include <ecom/RegistryInfo.rh>
#include <usbhost/internal/fdcplugin.hrh>

RESOURCE REGISTRY_INFO theInfo
    {
    dll_uid = 0x10281A75;
    interfaces =
        {
        INTERFACE_INFO
            {
            interface_uid = KFdcEcomInterfaceUid;
            implementations =
                {
                IMPLEMENTATION_INFO
                    {
                    implementation_uid = 0x10282B47;
                    version_no = 1;
                    display_name = "Audio FDC";
                    default_data = "IC0x01ISC0x01";
                    opaque_data = "";
                    },
                };
            }
        };
    }

The designer must understand the USB Class-specific Function structure and Class codes. When the FDF tries to identify an FD for an interface, it tries to match the interface’s class, subclass and protocol against the default_data fields of the installed Function Driver Controllers. Given this, the FD designer will want to match the first interface of the Function. In the case of the Audio Class for instance, this will be the Audio Control interface.

The designer must decide how specific the FD is to be. For a Class which uses different interface protocol settings, perhaps the driver is protocol-specific, in which case the default_data field will specify interface class, subclass and protocol. If the FD is protocol-agnostic, the default_data field can specify interface class and subclass only. Note that in this latter case a matching protocol-specific driver will be preferred (over the protocol-agnostic driver) in accordance with the requirements of the USB Common Class Specification v1.0.

Implement the functions

Mfi1NewFunction

You need to carry out the following two tasks when you implement Mfi1NewFunction:

  1. Claim interfaces

    The FDC must claim the first interface in the offered interface array and all other interfaces that belong to the same single Function as that interface. Mfi1NewFunction() must always perform this task, regardless of any other error condition in the FD. This task is critical for telling the FDF how the Class in question defines Functions.

  2. Take control of the interfaces

    The second task is to return an error from the Function Driver Controller's attempt to take control of the interfaces. The designer of the Function Driver decides what to include in this task. If an error is returned, the FDF will present the error to the USB Manager as a ‘driver loading’ notification'.

    Note: The error presented to the USB Manager might not be the same error – it may not have been the only FD to return an error for this device.

    This is a facility which the FDF provides to FDs. Without this facility, the FD itself would have to communicate with the UI to satisfy the ‘no silent failures’ requirement. Once Mfi1NewFunction() has returned, of course, any failures which occur in the FD must be notified to the UI in a subsystem-specific way without the help of the FDF. For this reason, it is suggested that the implementation of Mfi1NewFunction() do the following things, synchronously:

    1. The API used to claim interfaces (TokenForInterface) supplies tokens for those interfaces. These tokens should be collected. Collecting the tokens in a dynamic array may fail, so the Function Driver Controller may arrange a pre-existing fixed size array big enough to hold all the tokens for one function, if this is possible.

      Warning: If a supplied token has a value equal to 0, steps (2) and (3) should not be attempted because it means that the device has been physically or electrically disconnected.

    2. Pass the interface tokens to the FDI, using whatever FDI-specific mechanism, which may fail.

    3. Make sure that the FDI has opened RUsbInterface handles on the interfaces using the given tokens. This may fail due to out-of-memory.

    4. Remember the ID of the device the interfaces are from. If an unlimited number of simultaneous devices is supported, this may also fail.

The device ID is supplied in Mfi1NewFunction so that the device can be identified at detachment time (Mfi1DeviceDetached), and so that the string descriptor APIs can be used.

The configuration descriptor is supplied in Mfi1NewFunction so that the FD can walk the configuration bundle and identify those interfaces making up a single function.

Note: Only those interfaces in aInterfaces are actually offered in this call to Mfi1NewFunction().

The device descriptor is supplied. This is not currently useful to writers of FDs. Writers of FDs may not fail to claim interfaces because they don’t like the device class, VID, PID or other information supplied in the device descriptor. In future, if driver loading on the basis of device class/subclass is implemented, FDs may need to check the device protocol setting at Mfi1NewFunction() time. The device descriptor is provided now for this future possibility.

Mfi1DeviceDetached

The FD must close interfaces handles which were opened as a result of the corresponding Mfi1NewFunction() call. ‘Corresponding’ means ‘with the same device ID’. Note that more than one Mfi1NewFunction() call may arise from a single device. At most only one Mfi1DeviceDetached() call is made per Function Driver Controller per device detachment.

It may make sense for any other allocation done at Mfi1NewFunction() time to be cleaned up here too.

The device ID becomes invalid. The FD may not use any of the FDF API string descriptor APIs in Mfi1DeviceDetached(). Any string descriptors needed should have been obtained and remembered before this.

String descriptor APIs

The Function Driver Controller may use the following functions to obtain string descriptors from the device:

  • IMPORT_C TInt GetSupportedLanguages(TUint aDeviceId, RArray<TUint>& aLangIds);

  • IMPORT_C TInt GetManufacturerStringDescriptor(TUint aDeviceId, TUint aLangId, TName& aString);

  • IMPORT_C TInt GetProductStringDescriptor(TUint aDeviceId, TUint aLangId, TName& aString);

  • IMPORT_C TInt GetSerialNumberStringDescriptor(TUint aDeviceId, TUint aLangId, TName& aString);

These may only be called between entry to Mfi1NewFunction and entry to Mfi1DeviceDetached (for a given device ID).