Writing a Policy Plug-in for Mass Storage Function Drivers

This tutorial explains how to write a policy plug-in for Mass Storage Function Drivers.

Introduction

In this tutorial, you find out how to write a policy plug-in for Mass Storage Function Drivers. By writing a policy plug-in, you can set which drive letters to map the logical mass storage unit to and you can provide the errors to report to users.

For reference code, see src/usb/host/functiondrivers/ms/msmm/referencepolicyplugin....

Basic procedure

The high level steps to using the reference code for a policy plug-in are shown here:

  1. Change file names, UIDs and data fields

  2. Implement the functions

    • Write a function to retrieve the available drive letters

    • Write a function that saves the latest mount information to the Central Repository

    • Write a function to send error notifications

  3. Set the mount manager policy definitions.

Detailed steps

Change file names, UIDs and data fields

Rename the files listed here and the classes in the files. In this example we call our policy plug-in MyMSMMPolicyPlugin.

Reference name Example name UIDs to change Data fields to change

\group\referencepolicyplugin.mmp

\group\MyMSMMPolicyPlugin.mmp

The DLL UID (the second UID on the UID line).

N/A

inc\referenceplugin.hrh

inc\MyMSMMPolicyPlugin.hrh

The implementation UID, change KUidMsmmPolicyPluginImp to the concrete UID for your plugin.

N/A

inc\referencepolicyplugin.h

inc\MyMSMMPolicyPlugin.h

N/A

N/A

data\10285c46.rss

data\<your_plugin_uid3>.rss.rss

The DLL UID in the dll_uid line.

display_name and default_data is reserved for future. (You can change them to any meaningful strings that are suitable for your plugin.)

data\10285c46.txt

data\<your_plugin_uid3>.rss.txt

N/A

N/A

src\referencepolicyplugin.cpp

src\MyMSMMPolicyPlugin.cpp

N/A

N/A

Also change the implementation UID in the ‘proxy’.cpp, in the IMPLEMENTATION_PROXY_ENTRY table.

Edit bld.inf to include MyMSMMPolicyPlugin.mmp in your new group directory, in the usual way.

Implement the functions

The examples here show the implementation of the main functions in the reference code. See the full reference code for the supporting functions.

Write a function to retrieve the available drive letters

The RetrieveDriveLetterL() function allocates a proper drive letter for a newly available logical unit.

It retrieves the licensee's allowed drive letter range. It retrieves the licensee's forbidden drive letter list and removes forbidden letters from the list.

It finds which drive letters are already used and saved to history. It removes these drive letters from the candidate list. If no drive letter is available after that, it uses the first available used drive letter in the licensee permitted drive list.

It retrieves mounting records from the history and tries to find a record of the logical unit that is currently trying to mount. If a logical unit mounts for the first time, it is allocated the first drive letter from the defined range that is not currently being used by another logical unit or that hasn't been allocated to another logical unit in the saved mount information. If a logical unit has previously mounted, it mounts to the same unit again unless that drive letter is being used by another logical unit. If it cannot be mounted to the same letter, another letter is selected from the defined range.

void MyMSMMPolicyPlugin::RetrieveDriveLetterL(TText& aDriveName,
        const TPolicyRequestData& aData)
    {
    TDriveList availableNames;
    FilterFsForbiddenDriveListL(availableNames);

    if (!availableNames.Length())
        {
        // Not any drive letter available
        User::Leave(KErrNotFound);
        }

    // When a particular Logical Unit is mounted for the first time,
    // the reference policy plug-in tries to allocate an 
    // available and unused drive letter to it. Only if such a drive letter
    // can not be found, it uses the first one in the available name list.
    
    // Initialize aDriveName by the first available drive letter
    aDriveName = availableNames[0];
    // Find first such drive letter from available letter list. If it can
    // be found, it will be used.
    FindFirstNotUsedDriveLetter(availableNames, aDriveName);    
    // Search history record
    TInt historyIndex = SearchHistoryByLogicUnit(aData);
    if (KErrNotFound != historyIndex)
        {
        // Find a match in history
        const TPolicyMountRecord& history = *iHistory[historyIndex];
        TInt location = availableNames.Locate(TChar(history.iDriveName));
        if (KErrNotFound != location)
            {
            // And it is available now. reference policy plug-in allocates it to the 
            // logical unit currently mounted.
            aDriveName = history.iDriveName;
            }
        }
    }

Write a function that saves the latest mount information to the Central Repository

The SaveLatestMountInfoL() saves the latest mount information to the Central Repository.

It first searches for a record of the currently mounted logical unit in the history. If a record is found, it is refreshed with the new drive letter. If a record is not found, a new record is appended.

void MyMSMMPolicyPlugin::SaveLatestMountInfoL(
        const TPolicyMountRecord& aData)
    {
    if (iMaxHistoryRecCount == 0) // This policy disable history
        {
        return;
        }
    
    TPolicyMountRecord* historyRecord = 
            new (ELeave) TPolicyMountRecord(aData);
    CleanupStack::PushL(historyRecord);
    TInt historyIndex = SearchHistoryByLogicUnit(aData.iLogicUnit);
    if (KErrNotFound == historyIndex)
        {
        // No matched record exist
        if (iHistory.Count() == iMaxHistoryRecCount)
            {
            // Remove the oldest entity
            delete iHistory[0];
            iHistory.Remove(0);
            }
        }
    else
        {
        // Remove the replaced entity
        delete iHistory[historyIndex];
        iHistory.Remove(historyIndex);
        }
    iHistory.AppendL(historyRecord); // Push the new entity
    CleanupStack::Pop(historyRecord);

    TUint32 historyRecordUid = KFirstHistoryUid;
    User::LeaveIfError(iRepository->Set(KHistoryCountUid, iHistory.Count()));
    for (TInt index = 0; index < iHistory.Count(); index++)
        {
        TPckg<TPolicyMountRecord> historyPckg(*iHistory[index]);
        User::LeaveIfError(iRepository->Set(historyRecordUid++, historyPckg));
        }
    }

Write a function to send error notifications

The SendErrorNotificationL() function sends error information to the extended error notifier of the MSMM.

It stores all incoming error notification data into an extendable queue. Because this function is designed to be a synchronous version, an extendable queue avoids losing error data.


void CReferencePolicyPlugin::SendErrorNotificationL(
        const THostMsErrData& aErrData)
    {
    iNotificationMan->SendErrorNotificationL(aErrData);
    }

CMsmmPolicyNotificationManager starts and sends an error notification data to the extended notifier by calling the notifier interface StartNotifierAndGetResponse().

void CMsmmPolicyNotificationManager::SendNotification()
    {
    iNotifier.StartNotifierAndGetResponse(
        iStatus, KMountPolicyNotifierUid, iErrorQueue[0], iResponse);
    SetActive();
    }

Note: In this reference plug-in, a response is not expected from user, but a concrete policy plugin may want to get the response from user.

Set the mount manager policy definitions

You configure the mount manager policy definitions to be saved in the Central Repository in the TXT file. Each item in the file is broken down as follows:

  • The first value is its key (an index value)

  • The second value is the type of this variant

  • The third value is the default value for initalizing

  • The last value is meta data (reserved for future).

  1. Define the drive letters available for use by Mass Storage Function Drivers.

    # A range of drive letters available to be used for Mass Storage drives.
    # The first and last available letter shall be stored.
    0x00010000 string8 "DX" 0
  2. Define the drive letters forbidden for use by Mass Storage Function Drivers.

    #    A list of drive letters forbidden by licensee.
    0x00010001 string8 "E" 0
  3. Define the maximum number of mounting history records.

    # Max mounting history recorded amount. Currently the reference policy 
    # plugin sets it to 5.
    0x00010002 int    5 0
  4. Set the On-The-Go suspend interval time.

    # OTG capable suspend time. Currently the reference policy 
    # plugin sets it to 5 seconds.
    0x00010003 int 5 0
  5. Set the media polling interval time.

    # Media polling time. Currently the reference policy 
    # plugin sets it to 1 second.
    0x00010004 int 1 0
  6. This value stores the current number of mounting history records. By default it is initialised to zero. The first mounting history record goes from Key 0x00010101 (see below).

    # The mounting history record.
    0x00010100 int    0 0
  7. Define the numbering system of history records.

    # The mounting history records.
    # This is the first record.
    # New records will be appended after this using a UID that increases by 1.
    # For instance, the second record will have the UID 0x00010102.
    0x00010101 string8 "" 0