Host Functions

Introduction

This chapter covers the support provided by the USB library for the USB controller in host mode. In order to simplify the application and the addition of new devices and device classes, the USB library provides a layered interface to the USB host controller. At the top layer of the USB library there are application interfaces that provide easy access to the various types of peripherals that are supported by the USB library. Below this layer are the USB host controller’s device interfaces that handle the specifics of each type of device and how to communicate with the USB host class driver. The USB host class drivers handle the basics of dealing with whole classes of devices like HID and Mass Storage Class devices. The USB host class driver layer communicates with the lowest level of the USB library which is the USB host controller driver. This lowest level directly accesses DriverLib functions to provide communications with the USB device that is connected. This communication is provided by callbacks or direct APIs that is discussed in the rest of this chapter. Much like the USB library’s device programming interface, the host interface has the following layers:

  • Device APIs (Mouse, Keyboard, Filesystem)

  • USB Class Driver APIs (HID, Mass Storage, Hub)

  • USB Host Controller APIs

  • DriverLib USB Driver APIs

USB Host Block Diagram

Fig. 8 USB Host Block Diagram

File Structure

Source code and headers for the host specific USB functions can be found in the host directory of the USB library tree, typically source/ti/usblib/msp432e4/host.

Filename

Description

usbhost.h

The header file containing host mode function prototypes and data types offered by the USB library.

usbhostenum.c

The source code for the USB host enumeration functions offered by the library.

usbhaudio.c

The source code for the USB host Audio class driver.

usbhaudio.h

The header file containing Audio class definitions specific to hosts supporting this class of device.

usbhhid.c

The source code for the USB host HID class driver.

usbhhid.h

The header file containing the definitions needed to interact with the USB host HID class driver.

usbhhub.c

The source code for the USB host Hub class driver.

usbhhub.h

The header file containing the definitions needed to interact with the USB host Hub class driver.

usbhhidkeyboard.c

The source code for the USB host HID class keyboard device.

usbhhidkeyboard.h

The header file containing the definitions needed to interact with the USB host HID class keyboard device.

usbhhidmouse.c

The source code for the USB host HID class mouse device.

usbhhidmouse.h

The header file containing the definitions needed to interact with the USB host HID class mouse device.

usbhmsc.c

The source code for the USB host Mass Storage class driver.

usbhmsc.h

The header file containing Mass Storage class definitions specific to hosts supporting this class of device.

usbhscsi.c

The source code for a high level SCSI interface which calls the host Mass Storage class driver.

usbhcdc.c

The source code for the USB host CDC class

usbhcdc.h

The header file containing the definitions needed to interact with the USB host CDC class

usbhcdcserial.c

The source code for the USB host CDC serial class

usbhcdcserial.h

The header file containing the definitions needed to interact with the USB host CDC serial device

Host Controller Driver

The USB library host controller driver provides an interface to the host controller’s hardware register interface. This is the lowest level of the driver interface and it interacts directly with the DriverLib USB APIs. The host controller driver provides all of the functionality necessary to provide enumeration of devices regardless of the type of device that is connected. This portion of the enumeration code only enumerates the device and allows the higher level drivers to actually handle normal device operations. To allow the application to conserve code and data memory, the host controller driver provides a method to allow applications to only include the host class drivers that are needed for each type of USB device. This allows an application to handle multiple classes of devices but only include the USB library code that the application needs to communicate with the devices that the application supports. While the host controller driver handles the enumeration of devices it relies on USB pipes, that are allocated by the higher level class drivers, as the direct communications method with a devices end points.

Enumeration

The USB host controller driver handles all of the details necessary to discover and enumerate any USB device. The USB host controller driver only performs enumeration and relies on the host class drivers to perform any other communications with USB devices including the allocation of the endpoints for the device. Most of the code used to enumerate devices is run in interrupt context and is contained in the enumeration handler. In order to complete the enumeration process, the host controller driver also requires that the application periodically call the USBHCDMain() function. When a host class driver or an application needs access to endpoint 0 of a device, it uses the USBHCDControlTransfer() interface to send data to the device or receive data from the device. During the enumeration process the host controller driver searches a list of host class drivers provided by the application in the USBHCDRegisterDrivers() call. The details of this structure are covered in the host class drivers section of this document. If the host controller driver finds a host class driver that matches the class of the enumerated device, it calls the open function for that host class driver. If no host class driver is found the host controller driver ignores the device and there is no notification to the application. The host controller driver or the host class driver can provide callbacks up through the USB library to inform the application of enumeration events. The host class drivers are responsible for configuring the USB pipes based on the type of device that is discovered. The application is notified of events in two ways: one is from the host class driver for the connected device and the other is from a non-device specific event driver. The class specific events come from the host class driver, while the generic connection, power and other non-device class specific events come from the host event driver if it is included in the application. The section “USB Events Driver” covers the host events driver, the valid events and how to include the host events driver in an application.

USB Host Configurable Features

Like the USB device mode the USB host mode provides the application with the ability to set certain run-time global features of the USB library. The application uses the USBHCDFeatureSet() to set the configurable features of the USB host library. These features include USB clocking, enabling an external phy, and setting various power settings for the USB host library.

USB Host PLL Feature

One of the most important features used by applications informs the USB library of the of how the application has configured the main PLL. On MS class devices the USB clock is derived from the main PLL and the USB library sets up its own clock based on the value provided by the application. The USBLIB_FEATURE_USBPLL is only used on MSP432E4 class devices and defaults to 480 MHz. If the PLL is operating at a value other than 480 MHz then the application is required to call the USBHCDFeatureSet() function with the USBLIB_FEATURE_USBPLL feature to provide the PLL frequency to the USB library. The following is an example of setting the PLL frequency to a value other than the default 480 MHz.

uint32_t ui32PLLFrequency;

ui32PLLFrequency = 320000000;

//
// Inform the USB library that the system is running using a 320 MHz PLL.
//
USBHCDFeatureSet(0, USBLIB_FEATURE_USBPLL, &ui32PLLFrequency);

USB Host System Clock Feature

The USB library needs to know the actual operating frequency of the system clock in order to provide some rough delays that the USB library uses for some of the USB signaling. The application provides the system clock frequency using the USBLIB_FEATURE_CPUCLK feature setting. The default for this value is 120 MHz for MSP432E4 class devices. If the processor is operating at something other than one of these frequencies then the application must call the USBHCDFeatureSet() function with the USBLIB_FEATURE_CPUCLK feature to provide the actual system clock frequency.

uint32_t ui32SysClock;

ui32SysClock = 60000000;

//
// Inform the USB library that the system is running at 60 MHz.
//
USBHCDFeatureSet(0, USBLIB_FEATURE_CPUCLK, &ui32SysClock);

USB Host ULPI Feature

The MSP432E4 class devices support using an external ULPI USB phy to allow the host to communicate with high speed devices. This feature is enabled by setting the USBLIB_FEATURE_USBULPI option combined with the desired speed. From the applications perspective this has no affect to normal USB operation other than the necessity to properly enable the USB external phy pins. The following are the possible configuration options when using ULPI:

  • USBLIB_FEATURE_ULPI_NONE - Disable ULPI and use the internal phy (default).

  • USBLIB_FEATURE_ULPI_HS - Use an externally connected ULPI phy at high-speed.

  • USBLIB_FEATURE_ULPI_FS - Use an externally connected ULPI phy at full-speed.

The following is an example of configuring the USB library to use and external phy operating in high speed mode.

uint32_t ui32ULPI;

ui32ULPI = USBLIB_FEATURE_ULPI_HS;

//
// Enable the use of an external USB ULPI connected phy.
//
USBHCDFeatureSet(0, USBLIB_FEATURE_USBULPI, &ui32ULPI);

USB HOST LPM Feature

The MSP432E4 class devices added the ability to use the USB LPM feature. This feature is not enabled by default and therefore must be enabled by the application if it wishes to use any LPM features. Once LPM is enabled, the application can use the USB library to issue an LPM suspend transaction to a device by calling the USBHCDLPMSleep() function and wake devices using the USBHCDLPMResume() function. There are only two options for LPM which allow the feature to be enabled or disabled with the following values:

  • USBLIB_FEATURE_LPM_DIS - Disable LPM transactions (default).

  • USBLIB_FEATURE_LPM_EN - Enable sending and receiving LPM transactions.

The following is an example of configuring the USB library enable LPM mode.

uint32_t ui32LPMFeature;

ui32LPMFeature = USBLIB_FEATURE_LPM_EN;

//
// Enable LPM transactions.
//
USBHCDFeatureSet(0, USBLIB_FEATURE_LPM, &ui32LPMFeature);

USB Pipes

The host controller driver layer uses interfaces called USB pipes as the primary method of communications with USB devices. These USB pipes can be dynamically allocated or statically allocated by the USB class drivers during enumeration. The USB pipes are usually only used within the USB library or by host class drivers and are not usually directly accessed by applications. The USB pipes are allocated and freed by calling the USBHCDPipeAlloc() and USBHCDPipeFree() functions and are initially configured by calling the USBHCDPipeConfig(). The USBHCDPipeAlloc() and USBHCDPipeConfig() functions are used during USB device enumeration to allocate USB pipes to specific endpoints of the USB device. On disconnect, the USBHCDPipeFree() function is called to free up the USB pipe for use by a new USB device. While in use, the USB pipes can provide status and perform read and write operations. Calling USBHCDPipeStatus() allows a host class driver to check the status of a pipe. However most access to the USB pipes occurs through USBHCDPipeWrite() and USBHCDPipeRead() and the callback function provided when the USB pipe was allocated. These are used to read or write to endpoints on USB devices on endpoints other than the control endpoint on endpoint 0. Since endpoint 0 is shared with all devices, the host controller interface does not use USB pipes for communications over endpoint 0 and instead uses the USBHCDControlTransfer() function.

Control Transactions

All USB control transactions are handled through the USBHCDControlTransfer() function. This function is primarily used inside the host controller driver itself during enumeration, however some devices may require using control transactions through endpoint 0. The HID class drivers are a good example of a USB class driver that uses control transactions to send data to a USB device. The USBHCDControlTransfer() function should not be called from within interrupt context as control transfers are a blocking operation that relies on interrupts to proceed. Since most callbacks occur in interrupt context, any calls to USBHCDControlTransfer() should be deferred until running outside the callback event. The USB host HID keyboard example is a good example of performing a control transaction outside of a callback function.

Interrupt Handling

All interrupt handling is done by the USB library host controller driver and most callbacks are done in interrupt context and like interrupt handlers should defer any real processing of events to occur outside the interrupt context. The callbacks are used to notify the upper layers of events that occur during enumeration or during normal operation. Because most of enumeration code is handled by interrupt handlers the enumeration code does require that the application call the USBHCDMain() function in order to progress through the enumeration states without running all code in interrupt context.

Host Class Driver

The host class drivers provide access to devices that use a common USB class interface. The USB library currently supports the following two USB class drivers: Mass Storage Class(MSC) and Human Interface Device(HID). In order to use these class drivers, the application must provide a list of the host class drivers that it uses by calling the USBHCDRegisterDrivers() function. The g_USBHIDClassDriver structure defines the interface for the Host HID class driver and the g_USBHostMSCClassDriver structure defines the interface for the Host MSC class driver.

The host class driver provides interfaces at its bottom layer to the USB host controller driver and device specific interfaces at it’s top layer. The lower layer interface to the USB host controller interface is the same for all USB host class drivers while the device interface layer on top is common to all USB host device interface of a given class. Thus the top layer of the of the MSC class driver does not need to match the top layer of the HID class driver, however the lower layer must be the same for both. Aside from enumeration, all communication with the host class driver is through its endpoint pipes. The host class driver parses and allocate any endpoints that it needs by calling the USBHCDPipeAlloc() and USBHCDPipeConfig() functions. These USB pipes provide the methods to read/write and get callback notification from the USB host controller driver layer.

USB Events Driver

The USB host library includes a method to receive non-device class specific events in the application by using a USB event driver. This driver can be included in applications by declaring an instance of the USB event driver using the DECLARE_EVENT_DRIVER() macro and then adding the variable that is declared to the list of drivers supported by the application. This event driver allows applications to notify users that an unsupported device has been inserted or to provide notification that a power fault has occurred and power may have been shut off, depending on the settings provided to the USBHCDPowerConfigInit() function. Depending on configuration the following events can occur:

  • USB_EVENT_CONNECTED - indicates that a support device has been connected.

  • USB_EVENT_UNKNOWN_CONNECTED - indicates that an unsupported device has been connected.

  • USB_EVENT_DISCONNECTED - indicates that an unsupported device has been disconnected.

  • USB_EVENT_POWER_FAULT - indicates that a power fault has occurred.

  • USB_EVENT_POWER_ENABLE - indicates that power should be enabled by the application since it has requested to manually control the power.

  • USB_EVENT_POWER_DISABLE - indicates that power should be enabled by the application since it has requested to manually control the power.

  • USB_EVENT_SOF - indicates that a SOF event has occurred(default disabled).

The USB host library provides the ability to enable or disable any of these events by calling the USBHCDEventEnable() or USBHCDEventDisable() functions. All events except the USB_EVENT_SOF are enabled by default when the USB host library is initialized. The USB_EVENT_SOF event is left disabled by default to avoid the excess overhead because this event occurs once per millisecond.

Because the USB events driver reuses the interrupt handler callback that is used for a normal host controller drivers, the application is required to cast the void pointer that is passed in to the function to a pointer to a tEventInfo structure. The following code example shows a basic implementation of a USB library event driver callback function.

Because the USB events driver reuses the interrupt handler callback that is used for a normal host controller drivers, the application is required to cast the void pointer that is passed in to the function to a pointer to a tEventInfo structure. The following code example shows a basic implementation of a USB library event driver callback function.

//
// Declare the driver.
//
DECLARE_EVENT_DRIVER(g_sEventDriver, 0, 0, USBHCDEvents)

void
USBHCDEvents(void *pvData)
{
    tEventInfo *psEventInfo;

    //
    // Cast this pointer to its actual type.
    //
    psEventInfo = (tEventInfo *)pvData;

    switch(psEventInfo->ui32Event)
    {
        //
        // Unknown device connected.
        //
        case USB_EVENT_CONNECTED:
        {
            ...

            break;
        }

        //
        // Unknown device disconnected.
        //
        case USB_EVENT_DISCONNECTED:
        {
            ...

            break;
        }

        //
        // Power Fault detected.
        //
        case USB_EVENT_POWER_FAULT:
        {
            ...

            break;
        }

        default:
        {
            break;
        }
    }
}

Hub Class Driver

The USB Hub class driver provides support for a USB hub device that allows the USB controller to communicate with multiple USB devices. The maximum number of devices that are supported is controlled by the MAX_USB_DEVICES definition in usblib.h. The value defined by MAX_USB_DEVICES defaults to 5, meaning that the USB library supports one hub and four other devices. Cascaded USB hubs are not supported because the USB library only supports a single instance of a USB hub. The application-level interface to the USB hub class consists of only an initialization function and requires no additional application-level changes to handle any of the supported USB classes. When USB hub support is enabled, non-hub devices can still be directly connected to the USB controller with no special handling by the application. The next section covers the application interfaces to the USB hub class and the memory requirements when enabling the USB hub support.

The application layer of the USB hub class driver provides functions that an application uses to configure or disable the USB hub class driver. To initialize the USB hub class driver, the application must call USBHHubOpen() and provide it with a memory pool suitable to hold the configuration descriptors of the maximum number of attached devices and a hub instance structure. The memory pool allocation is very similar to how an application provides memory to the USBHCDInit() function with the exception that that the amount of memory should be multiplied by the number of devices supported. This memory pool size should be the expected maximum configuration descriptor size multiplied by MAX_USB_DEVICES. The application also provides a tHubInstance structure that holds private instance data that should not be accessed by the application. In order to release an instance of a hub class driver, the application must call USBHHubClose(). This call to USBHHubClose() is only made if the application is shutting down the USB interface or when in OTG mode, switching roles from host to device.

//*****************************************************************************
//
// The size of the host controller's memory pool in bytes.
//
//*****************************************************************************
#define HCD_MEMORY_SIZE         128

//*****************************************************************************
//
// The memory pool to provide to the Host controller driver.
//
//*****************************************************************************
uint8_t g_pui8HCDPool[HCD_MEMORY_SIZE];

//*****************************************************************************
//
// The size of the host controller's memory pool in bytes.
//
//*****************************************************************************
#define HUB_POOL_SIZE           (HCD_MEMORY_SIZE * MAX_USB_DEVICES)

//*****************************************************************************
//
// The memory pool to provide to the hub driver.  This pool is used to hold the
// configuration descriptors of the devices attached to the hub.  It must be
// sized to be at least
// (MAX_USB_DEVICES * (largest expected configuration descriptor)) bytes.
//
//*****************************************************************************
uint8_t g_pui8HubPool[HUB_POOL_SIZE];

//*****************************************************************************
//
// The instance data for the hub, which is internal data and should not be
// accessed by the application.
//
//*****************************************************************************
tHubInstance g_sHubInstance;

//*****************************************************************************
//
// The global that holds all of the host drivers in use in the application.
// In this case, the Mass Storage, HID, and Hub class drivers are present.
//
//*****************************************************************************
static tUSBHostClassDriver const * const g_ppsHostClassDrivers[] =
{
    &g_sUSBHostMSCClassDriver,
    &g_sUSBHIDClassDriver,
    &g_sUSBHubClassDriver,
    &g_sUSBEventDriver
};

//*****************************************************************************
//
// The global that holds the number of class drivers in the
// g_ppsHostClassDrivers list.
//
//*****************************************************************************
static const uint32_t g_ui32NumHostClassDrivers =
    sizeof(g_ppsHostClassDrivers) / sizeof(tUSBHostClassDriver *);

//
// Initialize the USB stack mode to host.
//
USBStackModeSet(0, USB_MODE_HOST, 0);

//
// Register the host class drivers.
//
USBHCDRegisterDrivers(0, g_ppsHostClassDrivers, g_ui32NumHostClassDrivers);

//
// Open the Keyboard and Mass storage interfaces.
//
KeyboardOpen();
MSCOpen();

//
// Open a hub instance and provide it with the memory required to hold
// configuration descriptors for each attached device and the private hub
// instance data.
//
USBHHubOpen(HubCallback);

//
// Initialize the power configuration by configuring the power enable signal
// to be active high and not enabling the power fault.
//
USBHCDPowerConfigInit(0, USBHCD_VBUS_AUTO_HIGH | USBHCD_VBUS_FILTER);

//
// Initialize the USB controller for OTG operation with a 2ms polling
// rate.
//
HCDInit(0, g_pui8HCDPool, HCD_MEMORY_SIZE);

while(1)
{
    HCDMain();
}

HID Class Driver

The HID class driver provides access to any type of HID class by leaving the details of the HID device to the layer above the HID class driver. The top layer of the HID class driver provides common functions to open or close an instance of a HID device, read a device’s report descriptor so that it can be parsed by the HID device code, and get and set reports on a HID device. The lower level interface that is connected to the host controller driver is specified in the g_USBHIDClassDriver structure. This structure is used to register the HID class driver with the host class driver so that it is called when a HID device is connected and enumerated. The functions in the g_USBHIDClassDriver structure should never be called directly by and application or a host class driver as they are reserved for access by the host controller driver.

In the following example the generic HID class driver is registered with the USB host controller driver and then a call is made to open an instance of a mouse class device. Typically the call to USBHHIDOpen() is made from within a device class interface while the USBHCDRegisterDrivers() call is made from the main application. For instance the USBHHIDOpen() for the mouse device provided with the USB library is made in the USBHMouseOpen() function which is part of the USB mouse interface.

At the top layer of the HID class driver, the driver has a device class interface for used by various HID devices. In order for the HID class driver to recognize a device, the device class is responsible for calling the USBHHIDOpen(). This call specifies the type of device and a callback for this device type so that any events related to this device type can be passed back to the device class driver. The defined classes are in the type defined values in the tHIDSubClassProtocol type and are passed into the USBHHIDOpen() call via the eDeviceType parameter. In order to release an instance of a HID class driver, the HID device class or application must call the USBHHIDClose() to allow a new or different type of device to be connected. In the examples provided in the USB library the report descriptors are retrieved but are not used as the examples rely on the “boot” mode of the USB keyboard and mouse to fix the format of the report descriptors. This is accomplished by using the USBHHIDSetReport() interface to force the device into its boot protocol mode. As this could be limiting or not available in other types of applications or devices, the USBHHIDGetReportDescriptor() provides the ability of a generic HID device to query the device for its report descriptor(s). The last two remaining HID interfaces, USBHHIDSetReport() and USBHHIDGetReport(), provide access to the HID reports.

const tUSBHostClassDriver * const g_ppsUSBHostClassDrivers[] =
 {
     &g_USBHIDClassDriver
 };

 //
 // Register the host class drivers.
 //
 USBHCDRegisterDrivers(0, g_ppsUSBHostClassDrivers, 1);

 ...

 //
 // Open an instance of a HID mouse class driver.
 //
 psMouseInstance = USBHHIDOpen(USBH_HID_DEV_MOUSE,
                               USBHMouseCallback,
                               (void *)&g_sUSBHMouse);

Once a HID device has been opened the first callback it receives is a USB_EVENT_CONNECTED event, indicating that a HID device of the type passed into the USBHHIDOpen() has been connected and the USB library host controller driver has completed enumeration of the device. When the HID device has been removed a USB_EVENT_DISCONNECTED event occurs. When shutting down or to release a device, the application should call USBHHIDClose() to disable callbacks. This does not actually power down the device but it stops the driver from calling the application. During normal operation the host class driver receives USB_EVENT_SCHEDULER and USB_EVENT_RX_AVAILABLE events. The USB_EVENT_SCHEDULER indicates that the HID class driver should schedule a new request if it is ready to do so. This done by calling USBJHCDPipeSchedule() to request that a new IN request is made on the given Interrupt IN pipe. When the USB_EVENT_RX_AVAILABLE occurs this indicates that new data is available due to completion of the previous request for data on the Interrupt IN pipe. The USB_EVENT_RX_AVAILABLE is passed on the device class interface to allow it to request the data via a call to USBHHIDGetReport(). It is up to the device class driver to interpret the data in the report structure that is returned. In some cases, like the keyboard example, the device class may also need to call the host class driver to issue a set report to send data to the device. This is done by calling the USBHHIDSetReport() interface of the host class driver. This sends data to the device by using the correct USB OUT pipe.

Mass Storage Class Driver

The mass storage host class driver provides access to devices that support the mass storage class protocol. The most common of these devices are USB flash drives. This host class driver provides a simple block based interface to the devices that can be matched up with an application’s file system. A USB host class driver for mass storage devices is included with the USB library. It provides a simple block based interface that can be used with an application’s file system as it provides direct block interface to mass storage devices based on logical block address.

The mass storage host class driver provides an application API for access to USB flash drives. The API provided is meant to match with file systems that need block based read/write access to flash drives. The USBHMSCBlockRead() and USBHMSCBlockWrite() functions provide the block read and block write device access. These function performs block operations at the size specified by the flash drive. Since some flash drives require some setup time after enumeration before they are ready for drive access, the mass storage class driver provides the USBHMSCDriveReady() function to check if the drive is ready for normal operation.

The mass storage host class driver also provides an interface to the USB library host controller driver to complete enumeration of mass storage class devices. The mass storage class driver information is held in the global structure g_USBMSCClassDriver. This structure should only be referenced by the application and the function pointers in this structure should never called directly by anything other than the host controller driver. The USBHMSCOpen() and USBHMSCClose() provide the interface for the host controller’s enumeration code to call when a mass storage class device is detected or removed. It is up to the mass storage host class driver to provide a callback to the file system or application for notification of the drive being removed or added. To make the the mass storage class driver visible to the host controller driver it must be added in the list of drivers provided in the USBHCDRegisterDrivers() function call. The class enumeration constant is set to USB_CLASS_MASS_STORAGE so any devices enumerating with value loads this class driver.

This next section covers how an application or file system interacts with the host mass storage class driver provided with the USB library. The application or file system must register the mass storage class driver with a call to USBHCDRegisterDrivers() with the g_USBHostMSCClassDriver as a member of the array passed in to the call. Once the host mass storage class driver has been registered, the application must call USBHMSCDriveOpen() to allow the application or file system to be called when a new mass storage device is connected or disconnected or any other mass storage class event occurs.

const tUSBHostClassDriver * const g_ppsUSBHostClassDrivers[] =
{
    &g_sUSBHostMSCClassDriver
};

//
// Register the host class drivers.
//
USBHCDRegisterDrivers(0, g_ppsUSBHostClassDrivers, 1);

//
// Initialize the mass storage class driver on controller 0 with the
// MSCCallback() function as the callback for events.
//
USBHMSCDriveOpen(0, MSCCallback);

The first callback is a USB_EVENT_CONNECTED event, indicating that a mass storage class flash drive was inserted and the USB library host stack has completed enumeration of the device. This does not indicate that the flash drive is ready for read/write operations but that is has been detected. The USBHMSCDriveReady() function should be called to determine when the flash drive is ready for read/write operations. When the device has been removed an USB_EVENT_DISCONNECTED event occurs. When shutting down, the application should call USBHMSCDriveClose() to disable callbacks. This does not actually power down the mass storage device but it stops the driver from calling the application.

Once the USBHMSCDriveReady() call indicates that the flash drive is ready, the application can use the USBHMSCBlockRead() and USBHMSCBlockWrite() functions to access the device. These are block based functions that use the logical block address to indicate which block to access. It is important to note that the size passed in to these functions is in blocks and not bytes and that the most common block size is 512 bytes. These calls always read or write a full block so space must be allocated appropriately. The following example shows calls for both reading and writing blocks from the mass storage class device.

//
// Read 1 block starting at logical block 0.
//
USBHMSCBlockRead(ui32MSCDevice, 0, pui8Buffer, 1);

//
// Write 2 blocks starting at logical block 500.
//
USBHMSCBlockWrite(ui32MSCDevice, 500, pui8Buffer, 2);

Since most mass storage class device adhere to the SCSI protocol for block based calls, the USB library provides SCSI functions for the mass storage class driver to communicate with flash drives. The commands and data pass over the USB pipes provided by the host controller driver. The only types of mass storage class devices that are supported are devices that use the SCSI protocol. Since flash drives only support a limited subset of the SCSI protocol, only the SCSI functions needed by mass storage class to mount and access flash drives are implemented. The USBHSCSIRead10() and USBHSCSIWrite10() functions are the two functions used for reading and writing to the mass storage class devices. The remaining SCSI functions are used to get information about the mass storage devices like the size of the blocks on the device and the number of blocks present. Others are used for error handling or testing if the device is ready for a new command.

Audio Class Driver

The USB audio host class driver provides access to devices that support the USB audio class protocol. This driver provides access to both audio in and audio out interfaces. The application opens an instance of the audio device by calling USBHostAudioOpen() and providing a callback function to receive events notifications when an audio device has been enumerated and is ready for normal operation, or when an active audio device has been disconnected. The application should not access any other APIs that use the interface returned from the USBHostAudioOpen() function until an USBH_AUDIO_EVENT_OPEN event is received and not after a USBH_AUDIO_EVENT_CLOSE event is received. When the application no longer needs the audio interface it can call USBHostAudioClose() to stop the audio device and no longer be notified of changes to the audio device. Audio output is handled by providing buffers to the host audio driver by calling USBHostAudioPlay() and including a callback function for the buffer. The buffers are returned to the application by the callback to the application provided in the USBHostAudioPlay(). This allows the application to gain control while the audio is being scheduled for output. The audio input is handled by providing buffers to the host audio driver by calling USBHostAudioRecord() and passing in a buffer callback as well. Buffers are then scheduled to be filled by the USB controller and returned to the application by the callback function that the application provided in the USBHostAudioRecord() call. The next section provides more detail and examples for each application level API.

The USB host audio application interface provides a basic method for controlling audio output, input and some volume control. Since the USB host audio provides only a small amount of buffering, it is up to the application to provide adequate buffering based on it’s other functions to keep the audio stream from starving for data.

The USB host audio driver requires some initial configuration by the application that is outside of the USB audio driver’s control. The first of these is to enable the uDMA controller and configure a DMA control table that includes the USB DMA channels. The application must also register the USB host audio driver by calling USBHCDRegisterDrivers() with the g_USBHostAudioClassDriver structure pointer in the list of supported drivers. Finally the application must create an instance of the USB host audio device by calling the USBHostAudioOpen() function and provide it with a callback for basic USB audio events, saving the value returned for use with other APIs.

//
// The instance data for the USB host audio driver.
//
uint32_t g_psAudioInstance = 0;

//
// The control table used by the uDMA controller.  This table must be aligned
// to a 1024 byte boundary.  When using USB with uDMA if it is only used for
// USB then only first 6 channels are needed.
//
// Note: If other DMA channels are used then the table must be large enough
// to hold all channels in use.
//
tDMAControlTable g_psDMAControlTable[6];

//
// The global that holds all of the host drivers in use in the application.
// In this case, only the host audio class is loaded.
//
static tUSBHostClassDriver const * const g_ppsHostClassDrivers[] =
{
    &g_sUSBHostAudioClassDriver,
    &g_sUSBEventDriver
};

    ...

    //
    // Enable the uDMA controller and set up the control table base.
    //
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    uDMAEnable();
    uDMAControlBaseSet(g_psDMAControlTable);

    //
    // Register the host class drivers.
    //
    USBHCDRegisterDrivers(0, g_ppsHostClassDrivers, g_ui32NumHostClassDrivers);

    //
    // Open an instance of the mass storage class driver.
    //
    g_psAudioInstance = USBHostAudioOpen(0, AudioCallback);

    ...

Audio output is handled by setting the format of the audio stream and then by calling the USBHostAudioPlay() function to provide new buffers to the audio device. The callback function that is provided with this call returns the buffers when the driver is no longer using them. In order for audio output to start, the application must first set the audio format with a successful call to USBHostAudioFormatSet(). If the format was not supported by the audio device then this function returns a non-zero value and USBHostAudioPlay() should not be called until a valid format is selected. Once a valid format is set the application should provide audio data to the host audio driver by calling USBHostAudioPlay() and then always waiting for the callback to indicate that the buffer has been released. Calling the USBHostAudioPlay() function before the previous buffer has been released can cause the previous transfer to be interrupted or canceled. Since the USB host audio driver provides limited buffering it is up to the application to have data ready for output. The application can safely call USBHostAudioPlay() function directly from the callback function to provide a new buffer to the USB audio device.

void AudioOutCallback(void *pvBuffer, uint32_t ui32Param, uint32_t ui32Event)
{
    //
    // Check if this was a buffer free event and provide a new buffer to the
    // host audio driver.
    //
    if(ui32Event == USB_EVENT_TX_COMPLETE)
    {
        USBHostAudioPlay(psAudioInstance, pNewBuffer, ui32Size,
                         AudioOutCallback));
    }

}

void AudioPlay(void)
{
    //
    // Wait for USBH_AUDIO_EVENT_OPEN event.
    //

    ...

    //
    // Set the audio format to 48KHz 16 bit stereo output.
    //
    USBHostAudioFormatSet(psAudioInstance, 48000, 16, 2,
                          USBH_AUDIO_FORMAT_OUT);

    ...

    //
    // Start the output of the first buffer and let the callback start the
    // remaining buffers.
    //
    USBHostAudioPlay(psAudioInstance, pBuffer, ui32Size, AudioOutCallback));

    //
    // Handle filling returned buffers.
    //

    ...
}

Audio input is handled by setting the format of the audio stream and then by calling the USBHostAudioRecord() function to provide a new buffer to be filled by the host audio driver. The callback function that is provided with this call returns the buffer when the audio driver has new data available. In order for audio input to start, the application must first set the audio input format with a successful call to USBHostAudioFormatSet(). If the format was not supported by the audio device then this function returns a non-zero value. USBHostAudioRecord() should not be called until a valid format is selected. Once a valid format is set the application should provide an audio buffer to the host audio driver by calling USBHostAudioRecord() and wait for the callback to indicate that the buffer has been filled. Calling the USBHostAudioRecord() function before the previous buffer has been filled can cause the previous input transfer to be interrupted or lost. Since the USB host audio driver provides limited buffering it is up to the application to handle the input buffers and provide new buffers. The application can safely call USBHostAudioRecord() function directly from the callback function to provide a new buffer to the USB audio device, however the same buffer should not be passed back until it has been processed or the host audio driver may overwrite the data.

void AudioInCallback(tUSBHostAudioInstance *psAudioInstance, uint32_t ui32Event,
                     uint32_t ui32Param, void *pvMsgData)
{
    //
    // Check if this was a buffer full event and provide a new buffer to the
    // host audio driver.
    //
    if(ui32Event == USB_EVENT_RX_AVAILABLE)
    {
        USBHostAudioRecord(psAudioInstance, pNewBuffer, ui32Size,
                           AudioInCallback));
    }

}

void AudioRecord(void)
{
    //
    // Wait for USBH_AUDIO_EVENT_OPEN event.
    //

    ...

    //
    // Set the audio format to 48KHz 16 bit stereo output.
    //
    USBHostAudioFormatSet(psAudioInstance, 48000, 16, 2,
                          USBH_AUDIO_FORMAT_IN);

    ...

    //
    // Start the input of the first buffer and let the callback start the
    // remaining buffers.
    //
    USBHostAudioRecord(psAudioInstance, pBuffer, ui32Size, AudioInCallback));

    //
    // Handle filling returned buffers.
    //

    ...
}

Implementing Custom Host Class Drivers

This next section covers how to implement a custom host class driver and how the host controller driver finds the driver. All host class drivers must provide their own driver interface that is visible to the host controller driver. As with the host class drivers that are included with the USB library, this means exposing a driver interface of the type tUSBClassDriver. In the example below the USBGenericOpen() function is called when the host controller driver enumerates a device that matches the USB_CLASS_SOMECLASS interface class. The USBGenericClose() function is called when the device of this class is removed. The following example shows a definition of a custom host class driver.

tUSBClassDriver sUSBGenericClassDriver =
{
    USB_CLASS_SOMECLASS,
    USBGenericOpen,
    USBGenericClose,
    USBGenericIntHandler
};

The ulInterfaceClass member of the tUSBClassDriver structure is the class read from the device’s interface descriptor during enumeration. This number is used to as the primary search value for a host class driver. If a device is connected that matches this structure member then that host class driver is loaded. The pfnOpen member of the tUSBClassDriver structure is called when a device with a matching interface class is detected. This function should do whatever is necessary to handle device detection and initial configuration of the device, this includes allocating any USB pipes that the device may need for communications. This requires parsing the endpoint descriptors for a device’s endpoints and then allocating the USB pipes based on the types and number of endpoints discover. The host class drivers provided with the USB library demonstrate how to parse and allocate USB pipes. This call is not at made interrupt level so it can be interrupted by other USB events. Anything that must be done immediately before any other communications with the device should be done in the pfnOpen function. The pfnOpen member should should return a handle that is passed to the remaining functions pfnClose and pfnIntHandler. This handle should enable the host class driver to differentiate between different instances of the same type of device. The value returned can be any value as the USB library simply returns it unmodified to the other host class driver functions. The pfnClose structure member is called when the device that was created with pfnOpen call is removed from the system. All driver clean up should be done in the pfnClose call as no more calls are made to the host class driver. If the host class driver needs to respond to USB interrupts, an optional pfnIntHandler function pointer is provided. This function runs at interrupt time and called for any interrupt that occurs due to this device or for generic USB events. This function is not required and should only be implemented if it is necessary. It is completely up to the custom USB host class driver to determine it’s own upper layer interface to applications or to other device interface layers. With the addition of hub support, the application interface layer should take into account multiple instances of a device class if multiple instances of devices are supported.

Host Device Interface

The USB library provides a set of host examples for a HID mouse, a HID keyboard, a mass storage device and a CDC serial device. The next few sections discusses each briefly and explain how their interfaces can be used by an application.

Mouse Device

The HID mouse device interface is controlled mainly through a callback function that is provided as part of the call to open the mouse device interface. In order to open an instance of the mouse device the application calls USBHMouseOpen() and passes in a callback function as well as some buffer data for use by the mouse device. The buffer provided is used internally by the mouse device and should not be used by the application. Once the device has been opened, the application should wait for a USB_EVENT_CONNECTED event to indicate that a mouse has been successfully detected and enumerated. At this point the application should call the USBHMouseInit() function to initialize the actual device that is connected. After this, the application can expect to start receiving the following events via the callback that was provided in the USBHMouseOpen() call: USBH_EVENT_HID_MS_PRESS, USBH_EVENT_HID_MS_REL, USBH_EVENT_HID_MS_X, or USBH_EVENT_HID_MS_Y.

USBH_EVENT_HID_MS_PRESS

The ui32MsgParam parameter has one of the following values HID_MOUSE_BUTTON_1, HID_MOUSE_BUTTON_2, HID_MOUSE_BUTTON_3 indicating which buttons have changed to the pressed state.

USBH_EVENT_HID_MS_REL

The ui32MsgParam parameter has one of the following values HID_MOUSE_BUTTON_1, HID_MOUSE_BUTTON_2, HID_MOUSE_BUTTON_3 indicating which buttons have changed to the released state.

USBH_EVENT_HID_MS_X

The ui32MsgParam parameter has an 8 bit signed value indicating the delta in the X direction since the last update.

USBH_EVENT_HID_MS_Y

The ui32MsgParam parameter has an 8 bit signed value indicating the delta in the Y direction since the last update.

When the application is done using the mouse device it can call USBHMouseClose() to release the instance of the mouse device and free up the buffer that it passed to the mouse device.

Keyboard Device

Like the mouse, the HID keyboard device interface is controlled mainly through a callback function that is provided as part of the call to open the keyboard device interface. In order to open an instance of the keyboard device the application calls USBHKeyboardOpen() and passes in a callback function as well as some buffer data for use by the keyboard device. The buffer provided is used internally by the keyboard device and should not be used by the application. Once the device has been opened, the application should wait for a USB_EVENT_CONNECTED event to indicate that a keyboard has been successfully detected and enumerated. At this point the application should call the USBHKeyboardInit() function to initialize the actual keyboard device that is connected. After this, the application can expect to receive the following events via the callback that was provided in the USBHKeyboardOpen() call: USBH_EVENT_HID_KB_PRESS, USBH_EVENT_HID_KB_REL, or USBH_EVENT_HID_KB_MOD.

USBH_EVENT_HID_KB_PRESS

The ui32MsgParam parameter has the USB usage identifier for the key that has been pressed. It is up to the application to map this usage identifier to an actual printable character using the USBHKeyboardUsageToChar() function, or it can simple respond to the key press without echoing the key to any output device. It should be noted that “special” keys like the Caps Lock key require notifying the actual keyboard device that the host application has detected that the key has been pressed.

USBH_EVENT_HID_KB_REL

The ui32MsgParam parameter has the USB usage identifier for the key that has been released.

USBH_EVENT_HID_KB_MOD

The ui32MsgParam parameter has the current state of all of the modifier keys on the connected keyboard. This value is a bit mapped representation of the modifier keys that can have any of the following bits set: * HID_KEYB_LEFT_CTRL * HID_KEYB_LEFT_SHIFT * HID_KEYB_LEFT_ALT * HID_KEYB_LEFT_GUI * HID_KEYB_RIGHT_CTRL * HID_KEYB_RIGHT_SHIFT * HID_KEYB_RIGHT_ALT * HID_KEYB_RIGHT_GUI

Host Programming Examples

The USB library provides examples for three host applications that can access mass storage devices and HID keyboard and mouse devices. These next sections cover the basics of each of these three applications and how they interact with the USB library.

Application Initialization

The USB library host stack initialization is handled in the USBHCDInit() function. This function should be called after registering class drivers using USBHCDRegisterDrivers() and, optionally, configuring power pins using USBHCDPowerConfigInit(). Both of these functions are described later.

The USBHCDInit() function takes three parameters, the first of which specifies which USB controller to initialize. This value is a zero based index of the host controller to initialize. The next two parameters specify a memory pool for use by the host controller driver. The size of this buffer should be at least large enough to hold a typical configuration descriptor for devices that are going to be supported. This value is system dependent so it is left to the application to set the size, however it should never be less than 32 bytes and in most cases should be at least 64 bytes. If there is not enough memory to load a configuration descriptor from a device, the device is not recognized by USB library’s host controller driver. The USB library also provides a method to shut down an instance of the host controller driver by calling the USBHCDTerm() function. The USBHCDTerm() function should be called any time the application wants to shut down the USB host controller in order to disable it, or possibly switch modes in the case of a dual role controller.

The USB library assumes that the power pin configuration has an active high signal for controlling the external power. If this is not the case or if the application wants control over the power fault logic provided by the library, then the application should call the USBHCDPowerConfigInit() function before calling USBHCDInit() in order to properly configure the power control pins. The polarity of the power pin, the polarity of the the power fault pin and any actions taken in response to a power fault are all controlled by passing a combination of sets of values in the ulPwrConfig parameter. See the documentation for the USBHCDPowerConfigInit() function for more details on this function.

Application Interface

The USB library host stack requires some portion of the code to not run in the interrupt handler so it provides the USBHCDMain() function that must be called periodically in the main application. This can be as a result of a timer tick or just once per main loop in a simple application. It should not be called in an interrupt handler. Calling the function too often is harmless as it simply returns if the USB host stack has nothing to do. Calling USBHCDMain() too infrequently can cause enumeration to take longer than normal. It is up to the application to prioritize the importance of USB communications by calling USBHCDMain() at a rate that is reasonable to the application.

All support devices must have a host class driver loaded in order to communicate with each type of device that is supported. The details of interacting with these host class drivers is explained in the host class driver sections that follow in this document.

Application Termination

When the application needs to shut down the host controller it needs to shutdown all host class drivers and then shut down the host controller itself. This gives the host class drivers a chance to close cleanly by calling each host class driver’s close function. Then the USBHCDTerm() function should be called to shut down the host controller. This sequence leaves the USB controller and the USB library stack in a state so that it is ready to be re-initialized or in order to switch USB mode from host to device.

Example Application Setup

The following example shows the basic setup code needed for any application that is using the USB library in host mode. The g_pui8HCDPool array which is passed in to the USBHCDInit() is used as heap memory for by the USB library and thus the memory should not be used by the application. In this example, the g_ppsHostClassDrivers array holds both HID and MSC class drivers making it possible for both types of devices to be supported. However if the application only needs to include the classes that it needs to support in order to save code and memory space. The pin and peripheral configuration is left to the application as the USB pins may not always be on the same physical pins for every part supported by the USB library. The macros provided in the pin_map.h file included with DriverLib can be used to indicate which pin and peripheral to use for a given part. See the DriverLib documentation on pin mapping for more details on how it provides mapping of peripherals to pins on devices. The USBHCDRegisterDrivers() call passes in the static array of supported USB host class drivers that are supported by the application. As shown in the example, the application should always call the USB device interfaces open routines before calling USBHCDInit() since this call enables the USB host controller and start enumerating any connected device. If the device interface has not been called it may miss the connection notification and could miss some state information that occurred before the device interface was ready.

//*****************************************************************************
//
// The size of the host controller's memory pool in bytes.
//
//*****************************************************************************
#define HCD_MEMORY_SIZE         128

//*****************************************************************************
//
// The memory pool to provide to the Host controller driver.
//
//*****************************************************************************
uint8_t g_pui8HCDPool[HCD_MEMORY_SIZE];

//*****************************************************************************
//
// The global that holds all of the host drivers in use in the application.
// In this case, only the Keyboard class is loaded.
//
//*****************************************************************************
static tUSBHostClassDriver const * const g_ppsHostClassDrivers[] =
{
    &g_sUSBHIDClassDriver,
    &g_sUSBHostMSCClassDriver
};

//*****************************************************************************
//
// This global holds the number of class drivers in the g_ppsHostClassDrivers
// list.
//
//*****************************************************************************
static const uint32_t g_ui32NumHostClassDrivers =
    sizeof(g_ppsHostClassDrivers) / sizeof(tUSBHostClassDriver *);

...

//
// Enable the GPIO peripherals used by the USB pins.
//
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG);
MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);

//
// Configure the USB EPEN as a USB pin.
//
MAP_GPIOPinConfigure(GPIO_PG4_USB0EPEN);
MAP_GPIOPinTypeUSBDigital(GPIO_PORTG_BASE, GPIO_PIN_4);

//
// Enable PB0 and PB1 as VBUS and ID pins.
//
MAP_GPIOPinTypeUSBAnalog(GPIO_PORTB_BASE, GPIO_PIN_0 | GPIO_PIN_1);

//
// Enable the D+/D- as USB pins.
//
MAP_GPIOPinTypeUSBAnalog(GPIO_PORTL_BASE, GPIO_PIN_6 | GPIO_PIN_7);

//
// Initialize the USB stack for host mode.
//
USBStackModeSet(0, eUSBModeHost, 0);

//
// Register the host class drivers.
//
USBHCDRegisterDrivers(0, g_ppsUSBHostClassDrivers, g_ui32NumHostClassDrivers);

//
// Initialize the power configuration. This sets the power enable signal
// to be active high and does not enable the power fault.
//
USBHCDPowerConfigInit(0, USBHCD_VBUS_AUTO_HIGH | USBHCD_VBUS_FILTER);

...

//
// Call any open routines on the device class interfaces here so that they
// are ready to receive callbacks if the device is already inserted on
// power on.
//
// Eg: USBHMSCDriveOpen(0, MSCCallback);
//

...

//
// Initialize the host controller.
//
USBHCDInit(0, g_pui8HCDPool, HCD_MEMORY_SIZE);

Host HID Mouse Programming Example

The USB library HID mouse example provides support for HID mouse devices that support the USB HID mouse BIOS protocol. Since most mice support the BIOS protocol nearly any mouse should be able to be connected and be supported. The initial call to USBHMouseOpen() prepares the mouse device application interface to receive notifications from any USB mouse device that is connected. Since the mouse interface needs some basic configuration after being connected the application needs to wait for the mouse to be connected and then call the USBHMouseInit() function to finish off the mouse configuration.

//
// Open an instance of the mouse driver.  The mouse does not need
// to be present at this time, this just saves a place for it and allows
// the applications to be notified when a mouse is present.
//
g_psMouseInstance = USBHMouseOpen(MouseCallback, g_pui8Buffer, 128);

...

//
// Main loop of application.
//
while(1)
{
    switch(iMouseState)
    {
        //
        // This state is entered when they mouse is first detected.
        //
        case MOUSE_INIT:
        {
            //
            // Initialized the newly connected mouse.
            //
            USBHMouseInit(g_psMouseInstance);

            //
            // Proceed to the mouse connected state.
            //
            iMouseState = MOUSE_CONNECTED;

            break;
        }
        case MOUSE_CONNECTED:
        {
            break;
        }
        case MOUSE_NOT_CONNECTED:
        default:
        {
            break;
        }
    }

    //
    // Periodic call the main loop for the Host controller driver.
    //
    USBHCDMain();
}
...

Once the mouse has been configured the application’s mouse callback routine is notified any time there is a state change with the mouse. This includes the switching to the MOUSE_INIT state when a USB_EVENT_CONNECTED event occurs in order to trigger initialization of the mouse device. The USB_EVENT_DISCONNECTED simply switches the state of the application to let it know that the mouse is no longer present. The remaining events are mouse state changes that can be used by the application to move a cursor or make a selection based on a mouse click.

uint32_t
MouseCallback(tUSBHMouse *psMsInstance, uint32_t ui32Event,
              uint32_t ui32MsgParam, void *pvMsgData)
{
    switch(ui32Event)
    {
        //
        // New mouse detected.
        //
        case USB_EVENT_CONNECTED:
        {
            iMouseState = MOUSE_INIT;
            break;
        }

        //
        // Mouse has been unplugged.
        //
        case USB_EVENT_DISCONNECTED:
        {
            iMouseState = MOUSE_NOT_CONNECTED;
            break;
        }

        //
        // New Mouse events detected.
        //
        case USBH_EVENT_HID_MS_PRESS:
        {
            break;
        }
        case USBH_EVENT_HID_MS_REL:
        {
            break;
        }
        case USBH_EVENT_HID_MS_X:
        {
            break;
        }
        case USBH_EVENT_HID_MS_Y:
        {
            break;
        }
    }
    return(0);
}

Host HID Keyboard Programming Example

The USB library HID keyboard example provides support for HID keyboard devices that support the USB HID keyboard BIOS protocol. Since most keyboards support the BIOS protocol most keyboards should be able to be connected and be supported. The initial call to USBHKeyboardOpen() prepares the keyboard device application interface to receive notifications from any USB keyboard device that is connected. The keyboard interface needs some basic configuration and needs to set the current state of LEDs on the keyboard, the application must wait for the keyboard to be connected and then call the USBHKeyboardInit() function.

...

//
// Open an instance of the keyboard driver.  The keyboard does not need
// to be present at this time, this just save a place for it and allows
// the applications to be notified when a keyboard is present.
//
g_psKeyboardInstance = USBHKeyboardOpen(KeyboardCallback, g_pui8Buffer, 128);

//
// The main loop for the application.
//
while(1)
{
    switch(iKeyboardState)
    {
        //
        // This state is entered when they keyboard is first detected.
        //
        case KEYBOARD_INIT:
        {
            //
            // Initialized the newly connected keyboard.
            //
            USBHKeyboardInit(g_psKeyboardInstance);

            //
            // Proceed to the keyboard connected state.
            //
            iKeyboardState = KEYBOARD_CONNECTED;

            break;
        }
        case KEYBOARD_UPDATE:
        {
            //
            // If the application detected a change that required an
            // update to be sent to the keyboard to change the modifier
            // state then call it and return to the connected state.
            //
            iKeyboardState = KEYBOARD_CONNECTED;

            USBHKeyboardModifierSet(g_psKeyboardInstance, g_ui32Modifiers);
        }
        case KEYBOARD_CONNECTED:
        {
            break;
        }
        case KEYBOARD_NOT_CONNECTED:
        default:
        {
            break;
        }
    }

    //
    // Periodic call the main loop for the Host controller driver.
    //
    USBHCDMain();
}

Much like the mouse, the keyboard handles the reception of events entirely in the callback handler. This function should receive and store the keyboard events and handle them in the main program loop when the device is in the connected state. The USB_EVENT_CONNECTED lets the main loop know that it is time to call the USBHKeyboardInit() routine to configure the keyboard. The USB_EVENT_DISCONNECTED event simply informs the application that the keyboard is not longer present and not to expect any more callbacks until another USB_EVENT_CONNECTED occurs. The remaining events all indicate that a key has been pressed or released. Normal key presses/releases generate USBH_EVENT_HID_KB_PRESS or USBH_EVENT_HID_KB_REL events while hitting keys like the shift, ctrl, alt and gui keys generate USBH_EVENT_HID_KB_MOD events.

uint32_t
KeyboardCallback(tUSBHKeyboard *psKbInstance, uint32_t ui32Event,
                 uint32_t ui32MsgParam, void *pvMsgData)
{
    uint8_t ui8Char;

    switch(ui32Event)
    {
        //
        // New keyboard detected.
        //
        case USB_EVENT_CONNECTED:
        {
            iKeyboardState = KEYBOARD_INIT;
            break;
        }

        //
        // Keyboard has been unplugged.
        //
        case USB_EVENT_DISCONNECTED:
        {
            iKeyboardState = KEYBOARD_NOT_CONNECTED;
            break;
        }

        //
        // New Key press detected.
        //
        case USBH_EVENT_HID_KB_PRESS:
        {
            //
            // ui32MsgParam holds the USB Usage ID.
            //
            break;
        }
        case USBH_EVENT_HID_KB_MOD:
        {
            //
            // ui32MsgParam holds the USB Modifier bit mask.
            //
            break;
        }
        case USBH_EVENT_HID_KB_REL:
        {
            //
            // ui32MsgParam holds the USB Usage ID.
            //
            break;
        }
    }
    return(0);
}

Host Mass Storage Programming Example

The following programming example demonstrates some of the basic interfaces that are available from the USB mass storage class application interface. See the “Basic Configuration as Host” example above for the initial configuration. The application should call USBHMSCDriveOpen() in order for the application to be ready for a new mass storage device. The application should also wait for the mass storage device to be ready to receive commands by calling USBHMSCDriveReady() and waiting for the value returned to go to 0 before attempting to read or write the device. Typically the reading and writing of the device is left to a file system layer as is the case in the example application, however the calls to directly read or write a block are shown in the example below.

//
// Open an instance of the mass storage class driver.
//
g_psMSCInstance = USBHMSCDriveOpen(0, MSCCallback);

...

//
// Wait for the drive to become ready.
//
while(USBHMSCDriveReady(g_psMSCInstance))
{
    //
    // System level delay call should be here to give the device time to
    // become ready.
    //
    SysCtlDelay(g_ui32ClockRate / 100);
}

...

//
// Block Read example.
//
USBHMSCBlockRead(g_psMSCInstance, ui32LBA, pui8Data, 1);

...

//
// Block Write example.
//
USBHMSCBlockWrite(g_psMSCInstance, ui32LBA, pui8Data, 1);

...

Host CDC Serial Programming Example

The following programming example demonstrates the transfer of data between CDC host and device. See the “Basic Configuration as Host” example above for the initial configuration.

The call to USBHCDCSerialOpen() prepares the host CDC application interface to receive notifications from any USB serial CDC device that is connected to it. The CDC host interfaces are intialized when the application calls USBHCDInit() and when a CDC device connects a call to USBHCDCSerialInit() is also made.

Once initialization has occured, the application begins to poll the data IN endpoint by calling USBHCDCGetDataFromDevice() API for any data sent from a connected CDC device. The application also can send data to the CDC device by calling USBHCDCSendDataToDevice() API.

...

/    //
    // The main loop for the application.
    //
    while(1)
    {
        //
        // Tell the OTG library code how much time has passed in
        // milliseconds since the last call.
        //
        USBOTGMain(GetTickms());

        switch(g_eUSBState)
        {
            //
            // This state is entered when the CDC device is first detected.
            //
            case STATE_CDC_DEVICE_INIT:
            {
                //
                // Initialize the newly connected CDC device.
                //
                USBHCDCSerialInit(g_psCDCSerialInstance);

                //
                // Proceed to the connected CDC device state.
                //
                g_eUSBState = STATE_CDC_DEVICE_CONNECTED;

                break;
            }

            case STATE_CDC_DEVICE_CONNECTED:
            {

                //
                // Start polling for data on interface 1
                //
                USBHCDCGetDataFromDevice(g_psCDCSerialInstance, INTERFACE_1);

                //
                // 10 sets of string of data has been received from device
                //
                if (ui8DataCounter == 10)
                {
                    //Restart counter
                    ui8DataCounter = 0;
                    //
                    // Press a key to acknowledge reception of data
                    //
                    ui8SendArray[0] = 'j';
                    ui8DataSize = 1;

                    //
                    // Send the key press to the device.
                    //
                    USBHCDCSendDataToDevice(g_psCDCSerialInstance, INTERFACE_1, ui8SendArray, ui8DataSize);
                }

                break;
            }

            case STATE_UNKNOWN_DEVICE:
            {
                //
                // Nothing to do as the device is unknown.
                //
                break;
            }

            case STATE_NO_DEVICE:
            {
                //
                // Nothing is currently done in the main loop when the CDC
                // device is not connected.
                //
                break;
            }

            default:
            {
                break;
            }
        }
    }