Starting USB Services

This document tells you how to start USB services using the USB Manager library.

Purpose

USB services are started by function calls to the USB Manager. There are two methods of starting USB services. One is an "intelligent" method, which does not perform a re-start if USB services are already running. The other performs a "forced" start even if USB services are already running (this will potentially involve an interruption to a currently running user service).

We recommend you always use the "intelligent" method because it protects USB services against un-necessary interruption and because only the "intelligent" method allows you to pass a personality to the function that starts USB services. The personality stores the configuration of the Symbian phone's USB peripheral stack (see Using USB personalities).

Intended Audience

This document is for Symbian licensees who are implementing USB services, including host and On-The-Go (OTG) services, on a Symbian device.

Required Background

For details of, and links to, the USB and On-The-Go (OTG) specifications on the USB Implementers Forum website, see The USB Manager library.

You also need to understand Symbian's concepts of asynchronous programming and active objects.

Setup and Configuration Requirements

Make sure you:

  • include in the ROM all class controllers for the types of peripheral device you intend the Symbian platform phone to present itself as to USB hosts;

  • make available one or more USB personalities to support the types of peripheral that you intend the Symbian platform phone to present itself as to USB hosts (see Using USB personalities). When you build the ROM, your USBMAN.RSC personality file needs to go into the following target directory: Z:\PRIVATE\101fe1db.

If the device you are devloping code for supports USB host/OTG services, you must make sure you:

  • include the executable usbsvrotg.exe in the ROM (see Enabling the USB Manager library's host/OTG functions);

  • include the Symbian low-level USB host/OTG stack in the ROM (the documentation for this stack is provided separately with the software when you purchase Symbian's USB host/OTG stack);

  • implement a USB control application from which to execute the start and stop functionality. (A Symbian example implementation, which you can use for guidance, is provided at the following location: sf/os/shortlinksrv/usbmgmt/usbmgrtest/usbcontrolapp. Future releases of the documentation will include a full guide to implementing the USB control application.)

  • make the application that starts and stops USB services the USB control application (thereby locking all other applications out of the USB Manager library's control functionality). For information about how to do this, see Locking applications out of the USB Manager.

Using the USB Manager to start USB services

Basic Procedure

The high-level steps involved in starting USB services are shown here:

  1. Create a USB Manager session by using the RUsb::Connect() function.

  2. If the Symbian platform phone supports OTG, then make the application that will start USB services the USB control application (see Locking applications out of the USB Manager).

  3. Handle the different conditions under which USB services will be started.

  4. Start USB services. There are two ways to start USB services:

    • Intelligent start (this is Symbian's recommended method)

    • Forced start

USB starting conditions

For information about the conditions that you need to use as triggers for starting USB services, see The conditions for starting USB services.

Steps for starting USB services

The steps for starting USB services are shown here:

  1. Set up a connection between the USB Manager client interface and the USB server by calling the RUsb::Connect() function:

    RUsb usb;
    User::LeaveIfError(usb.Connect());    
  2. Handle the conditions for starting USB services (see The conditions for starting USB services).

  3. Perform either an "intelligent" start or a "forced" start of USB services:

    • Intelligent start:RUsb::TryStart(aPersonalityId, iStatus) starts USB services with a personality specified. (This is Symbian's recommended way of starting USB services.) This function only has an effect if USB services are currently in an idle state:

      //usb is a connected RUsb session
      TRequestStatus status;
      usb.TryStart(personalityId, status);
      User::WaitForRequest(status);
      if ( status != KErrNone )
        {
          // Handle an error
        }

      Note: There is no synchronous version of the RUsb::TryStart() function.

    • Forced start:RUsb::Start() starts USB services with no personality specified. (This is not the recommended way to start USB services.) This function executes even if USB services are already running (forced start). If you are using this function, you need to have a default USB configuration provided in an accompanying resource file (see Using USB personalities).

      //usb is a connected RUsb session
      TRequestStatus status;
      usb.Start(status);
      User::WaitForRequest(status);
      if ( status != KErrNone )
        {
          // Handle an error
        }

      There are both synchronous and asynchronous veresions of the RUsb::Start() function.

Starting USB on a peripheral-only phone

The following sample code illustrates a possible implementation for starting USB services in a non-OTG phone (in other words, a phone that is only configured to perform as a USB peripheral). The program starts USB services if a cable is connected. It tests for this by using the RUsb::GetDeviceState() function (see Monitoring the phone's status as a USB peripheral device).

RUsb usb;
User::LeaveIfError(usb.Connect());
…
                                     //Get notified of changes in device state
TRequestStatus status;               //Create a status indicator for an anysnchronous request 
TUsbDeviceState deviceState;            //create a variable to store the device state in   
usb.DeviceStateNotification(eventMask, deviceState,    status); //Request device state notification
User::WaitForRequest(status);        //Suspend program flow until state notification call returns
if ( status != KErrNone )
  {
    // Handle an error
  }

if ( deviceState != 0 )              //If device state is anything other than undefined, then a cable is 
                                     //attached and you need to start USB services.   
   
    //Insert code for deciding which personality to select

   {
            usb.TryStart(personalityID, status);  // Start USB services
         User::WaitForRequest(status);
         if ( status != KErrNone )
            {
            // Handle an error
            }
      }
…

For information about how to examine the USB personalities available on a Symbian platform phone (for example, in order to select one that supports particular device classes), see Discovering details of USB personalities.

The value set by the RUsb::DeviceStateNotification() function for the deviceState variable above is of type TUsbDeviceState, which is an Enum. If the device state is EUsbDeviceStateUndefined, then no USB cable is plugged into the phone and USB services can be stopped and the session to the USB Manager closed. If it is anything else, then a cable is plugged into the phone and USB services need to be started. For more information about the phone's USB device state, see Monitoring the phone's status as a USB peripheral device.

Note: The example above uses an asynchronous request for purposes of illustration. However, you will probably need to wrap the RUsb::DeviceStateNotification() request in an active object. (For more information about these Symbian concepts, see Asynchronous programming and Active objects.)

Starting USB on an OTG phone

This section takes you through some code fragments that demonstrate some of the tasks involved in starting USB services on an OTG phone.

It begins by opening a USB Manager session. (Note that the USB Manager sessions must only be closed after USB services have been stopped and before the USB control application shuts down.)

//    This is an OTG-specific example

RUsb usb;
User::LeaveIfError(usb.Connect());                   // Open a USB session    
                                            // (this session must be closed before the application exits)

The next task is to lock any other applications out of the USB Manager's control functions (see Locking applications out of USB Manager).

TInt err = usb.SetCtlSessionMode(ETrue);    //    Request ‘control’ mode
                 //    The application does this early to ensure that other applications
                                               //    cannot interfere with the management of USB services.

if(err)                                        
 }
    //    Handle error
    }

After this, the code needs to perform monitoring tasks in respect of ID-pin, VBus, and OTG state by using the USB Manager's publish-and-subscribe keys. For information about performing these tasks, see Monitoring VBus, ID-pin, OTG state and bus activity.

When the phone is in any of the conditions for starting USB services (see The conditions for starting USB services), it starts USB services by calling Symbian's recommended RUsb::TryStart() function.

... 

//
//    The control application has made the decision to activate USB services
//
//    There are three possibilities:
//    1) The phone is an A-Device that wants to activate itself as a USB host
//    2) The phone is a B-Device that wants to activate itself as a USB host
//    3) The phone is a B-Device that wants to activate itself as a USB peripheral 
//        (perhaps because it has detected VBus being raised by a remote host).
//
//    In all these cases, the control application must start USB services first
//

TBool hostRoleDesired = //    ETrue for the first two cases above, EFalse for the third case
TRequestStatus status;

//Insert code for deciding which personality to select

usb.TryStart(personalityId, status);    // Start USB services
User::WaitForRequest(status);
if ( status != KErrNone )
    {
    // Handle an error    
    }

//    If TryStart was successful (status == KErrNone), then USB services have now started,
//    and this phone is ready to act as a USB peripheral (but not yet as a USB host).

For information about how to examine the USB personalities available on a Symbian platform phone (for example, in order to select one that supports particular device classes), see Discovering details of USB personalities.

If the phone is currently in any of the starting conditions that require it to activate itself as a USB host (these are conditions 1 and 2 in the sample code above, but for more information see The conditions for starting USB services), then the USB control application must next enable host function driver loading (see Enabling host-driver loading); otherwise it will not be able to load drivers for the peripherals that attach to it. The following code fragment shows how to enable function driver loading:

if (hostRoleDesired)
    {
    //    Before making the request to become host, the application must enable 
    //  function driver loading, which is disabled by default.
    err = usb.EnableFunctionDriverLoading();
    if(err)
        {
        //    Handle error            
        }

After this, the application can attempt to take control of the bus and become the USB host; it does this by calling the RUsb::BusRequest() function (see Controlling when the phone is the USB host).

 //    The control application attempts to make the phone become USB host by calling BusRequest().
    //    This function is sensitive to the current state of the device, and when possible it
    //    takes whatever action (raising VBus or initiating SRP or HNP) is required to bring the  
    //    phone into the role of USB host.
    //
    //    The return code from the function does not indicate whether taking on the host
    //    role is possible, only whether the USB Manager has received the request correctly.
    //    The control application must monitor changes in the OTG state (using the publish-and-subscribe 
    //    keys) to determine whether the switch to the host role was successful.
    //
    err = usb.BusRequest();
    if(err)
        {
        //    Handle error            
        }

    //    The application can monitor for the attachment, configuration and detachment of 
    //    USB peripherals by using the HostEventNotification() function if it successfully enters     
    //    the host role.

    TDeviceInformation deviceInformation;           
                                                   // Register for device attachment notification
    usb.HostEventNotification(status, deviceInformation);
    User::WaitForRequest(status);

    //    The HostEventNotification() request needs be repeated whenever it returns.
   
...
usb.TryStop();
usb.Close();         // Close the session to the USB Manager before shutting down the control application
                     // and after stopping USB services.

Once the USB control application has successfully caused the phone to become the USB host, the application can start to monitor for the attachment, detachment, and driver-load status of USB peripherals. It does this by making asynchronous calls to the RUsb::HostEventNotification() function. This is also illustrated in the sample code above. For more information about this, see Monitoring USB peripheral attachment and detachment.

The following sample code illustrates part of another possible implementation for starting USB services in an OTG phone. This sample code fragment for a control application simply starts USB services in the case where ID-pin is present.

RUsb usb;
User::LeaveIfError(usb.Connect());

err = usb.SetCtlSessionMode(ETrue);                    // Request ‘control’ mode
if (err != KErrNone)
    {
    // handle error
    }

...                                                    

RProperty idPinProp;                                  //Create an ID-pin property object and attach to it
User::LeaveIfError(idPinProp.Attach(KUidUsbManCategory, KUsbOtgIdPinPresentProperty)); 

TRequestStatus status;
idPinProp.Subscribe(status);                          //Subscribe for notification next time the status changes
User::WaitForRequest(status);
   if ( status != KErrNone )
     {
      //Handle error    
     }

                                                      //Get the ID-pin publish-and-subscribe value
TBool idPinPresent;
                                                       
TInt err = idPinProp.Get(KUidUsbManCategory, KUsbOtgIdPinPresentProperty, idPinPresent);
if (err != KErrNone)
    {
    // Handle error and possibly return
    }
else
    {
      idPinProp.Subscribe(status);                    //Re-subscribe for notification of next change to ID-pin status
      User::WaitForRequest(status);
      if ( status != KErrNone )
        {
          //Handle error    
        }
           
      if ( idPinPresent )
        {
           usb.TryStart(personalityID, status);        // Start USB services
           User::WaitForRequest(status);
           if ( status != KErrNone )
             {
               // Handle error
             }
           err = usb.EnableFunctionDriverLoading();    // Enable host function driver loading
               //Handle possible error
              err = usb.BusRequest();                     // Attempt to make the phone become the USB host
                                                       // (you only need to call BusRequest() in the 
                                                       // absence of HNP/SRP)
               //Handle possible error
                                                                   
            //    The control application can monitor for the attachment, configuration and detachment of 
            //    USB peripherals by using the HostEventNotification() function if it successfully enters     
               //    the host role.

         TDeviceInformation deviceInformation;         // Register for device attachment notification        
                                                   
            usb.HostEventNotification(status, deviceInformation);
            User::WaitForRequest(status);
         if ( status != KErrNone )
            {
            // Handle error
            }

           //    The HostEventNotification() request needs be repeated whenever it returns.
    }
...
usb.Close();         // Close the session to the USB Manager before shutting down the control application
                     // and after stopping USB services.

Note: The example above uses asynchronous programming. However, you will probably need to use an active object to handle the monitoring of the USB Manager's publish-and-subscribe keys and also the monitoring of host events, both of which require continuous re-queuing. (For more information about these Symbian concepts, see Asynchronous programming and Active objects.)