This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C1294NCPDT: NAK Transaction before every 64 bytes Transaction

Part Number: TM4C1294NCPDT
Other Parts Discussed in Thread: EK-TM4C1294XL,

Hello,

I use the USB device mode. When the Host (Windows 10) use Get_Feature to get 2962 bytes data, I see there is a NAK Transaction before every 64 bytes Transaction. The USB Protocol is 1.1 (Full Speed).

1. Does it have any way to avoid the NAK Transaction which is before the 64 bytes Transaction?

2. Can I use DMA Controller in endpoint 0 to avoid this NAK Transaction?

  • Hi,

      NAK normally means the device temporary cannot send or received data. I'm not sure what device class you are running. Looking at your capture, they are IN transactions. It means the data is transferred from the device to the host. Is this correct? Is the NAK sent by the host? If this is the case, you will need to investigate on the host side.

      If you look at the C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\usb_dev_bulk example, it has a #define BULK_BUFFER_SIZE 256. I'm not sure by increasing the buffer size will alleviate the situation as the NAK is handled and responded by the hardware USB module when it needs to hold any further incoming data. 

      I can see in a different bulk transfer where the transactions are carried out in endpoint 3 that does not have the NAK after 64 bytes of. But these are OUT transactions (from host to the device).

  • Hi Charles,

    Thanks for your reply.

    I am using the HID class. The NAK is sent by the Devices. It is a control transaction on endpoint 0. When the device get the data from SPI, it will send a interrupt through endpoint 1 to host. host will use hidd_getfeature() to get the data.

    Does it mean that spending too much time in copying 64 bytes data to FIFO?

  • HI,

      I don't know how to answer your question as to under what circumstances will a NAK is inserted after 64 bytes and when it is not. I think during interrupt transactions, NAK is used to inform the host there is no data to send. There are are EP0 control transactions that do not have NAK after 64 bytes. Below is based on the TivaWare CDC device example where a GET_DESCRIPTOR does not have NAK when fetching more than 64 bytes on EP0.

  • Hi, Charles,

    I use the TivaWare CDC device example in C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\usb_dev_cdcserial and find that there still has NAK before the 64 bytes Transaction In GET_DESCRIPTOR.

    I found that there has no NAK before the data transaction if I use the USB 2.0 Hub to connect the laptop and the devices. Do you have any idea about that the NAK was disappeared if I set a USB 2.0 Hub between the laptop and the device?

  • Hi KF,

      How USB 2.0 Hub work is beyond my knowledge. Are you sniffing between the device and the hub or between the hub and the host? Perhaps there is some buffering in the hub that helps in this case. 

  • Hi Charles,

    Thanks for your reply.

    Do you have any idea about that there have NAK Transaction if I use the TM4C1294NCPDT with usb protocol 1.1 to connect the host directly?

    Or do you know someone who maybe knows that what might cause this NAK?

  • Do you have any idea about that there have NAK Transaction if I use the TM4C1294NCPDT with usb protocol 1.1 to connect the host directly?

    Hi KF,

      No, I don't know if will help or not. Please try and let me know your results. All I can think of is that the insertion of NAK is depending on the combination of USB hardware (amount of available buffers) and USB stack (the state of the USB stack at the time of incoming transactions). I don't know how to tweak the stack and certainly not the hardware on removing the NAK at wishes. Is Get_Feature a custom command? Can you use other EP for Get_Feature? Will it make a difference?

  • Hi Charles,

    The Get_Feature command I used is supported in Windows API: HidD_GetFeature function (hidsdi.h) - Windows drivers | Microsoft Learn

    I will try to use other EP for Get_Feature. Do you have any example that create control type endpoint in another endpoint?

  • Hi KF,

      Looks like this is a standard usb request as a control transaction which would normally carries out on EP0. I don't think you can move this request to other EP as I think Windows will send to EP0 only. 

     Isn't Get_Feature() only a control transaction only happening during enumeration between the host and the device? After enumeration is complete, the rest of data transactions will carry out on other EPs which I hope will behave differently in regard to NAK assertion. My point is that for control transactions which happens mostly during initial enumeration, the NAK insertion may not have much impact on the overall performance. Not sure if you agree unless the Get_feature() will happen constantly even after enumeration is complete. 

  • Hi Charles,

    In some cases, I would need to continuously use "Get_Feature" to retrieve a large amount of bytes. I try the usb bulk trasfer with the TivaWare example in C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\usb_dev_bulk and it still have NAK between two 64 bytes transaction when host read 2048 bytes. 

    Does the NAK disappear if I can copy the 64 bytes to the USB FIFO immediately after the previous transaction is completed?

    Is it possible to use the DMA controller to copy 64 bytes from memory into the USB FIFO immediately after the transaction of the previous 64 bytes is completed?

  • Hi KF,

      Looking at the below Bulk Transfers capture, I can see that for IN or OUT transfers, there are no NAK (e.g. transactions 18, 19, 20, 21, 22) inserted and there are places where NAK (e.g. transactions 13, 15, 23, 27) is asserted.  I really don't know when a NAK is inserted. As I mentioned, this will depend on  the combination of USB hardware (amount of available buffers) and USB stack (the state of the USB stack at the time of incoming transactions). 

    The USB controller has an integrated DMA but we don't have examples to showcase the feature. There is some double buffer capability that may help. The USB spec is in NDA. If you have NDA setup with TI then I can share with you privately.

  • Hi Charles,

    I am trying to use DMA. "Sending Multiple Packets" does not work, while "Sending a Single Packet" does work.

    I am using the "TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\usb_dev_bulk" example to send 1024 bytes to the host. I have made the following changes to the code:

    1. Set DMA flag in main function (TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\usb_dev_bulk\usb_dev_bulk.c)

    //*****************************************************************************
    //
    // usb_dev_bulk.c - Main routines for the generic bulk device example.
    //
    // Copyright (c) 2013-2020 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 2.2.0.295 of the EK-TM4C1294XL Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_memmap.h"
    #include "inc/hw_ints.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/usb.h"
    #include "usblib/usblib.h"
    #include "usblib/usb-ids.h"
    #include "usblib/device/usbdevice.h"
    #include "usblib/device/usbdbulk.h"
    #include "utils/uartstdio.h"
    #include "utils/ustdlib.h"
    #include "drivers/pinout.h"
    #include "usb_bulk_structs.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>USB Generic Bulk Device (usb_dev_bulk)</h1>
    //!
    //! This example provides a generic USB device offering simple bulk data
    //! transfer to and from the host.  The device uses a vendor-specific class ID
    //! and supports a single bulk IN endpoint and a single bulk OUT endpoint.
    //! Data received from the host is assumed to be ASCII text and it is
    //! echoed back with the case of all alphabetic characters swapped.
    //!
    //! Assuming you installed TivaWare in the default directory, a driver
    //! information (INF) file for use with Windows XP, Windows Vista, Windows 7,
    //! and Windows 10 can be found in C:/TivaWare_C_Series-x.x/windows_drivers.
    //! For Windows 2000, the required INF file is in
    //! C:/TivaWare_C_Series-x.x/windows_drivers/win2K.
    //!
    //! A sample Windows command-line application, usb_bulk_example, illustrating
    //! how to connect to and communicate with the bulk device is also provided.
    //! The application binary is installed as part of the ``TivaWare for C Series
    //! PC Companion Utilities'' package (SW-TM4C-USB-WIN) on the installation CD
    //! or via download from http://www.ti.com/tivaware .  Project files are
    //! included to allow the examples to be built using
    //! Microsoft Visual Studio 2008.  Source code for this application can be
    //! found in directory ti/TivaWare_C_Series-x.x/tools/usb_bulk_example.
    //
    //*****************************************************************************
    
    
    //*****************************************************************************
    //
    // The system tick rate expressed both as ticks per second and a millisecond
    // period.
    //
    //*****************************************************************************
    #define SYSTICKS_PER_SECOND 100
    #define SYSTICK_PERIOD_MS   (1000 / SYSTICKS_PER_SECOND)
    
    //*****************************************************************************
    //
    // The global system tick counter.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32SysTickCount = 0;
    
    //*****************************************************************************
    //
    // Variables tracking transmit and receive counts.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32TxCount = 0;
    volatile uint32_t g_ui32RxCount = 0;
    
    //*****************************************************************************
    //
    // Flags used to pass commands from interrupt context to the main loop.
    //
    //*****************************************************************************
    #define COMMAND_PACKET_RECEIVED 0x00000001
    #define COMMAND_STATUS_UPDATE   0x00000002
    
    volatile uint32_t g_ui32Flags = 0;
    
    //*****************************************************************************
    //
    // Global flag indicating that a USB configuration has been set.
    //
    //*****************************************************************************
    static volatile bool g_bUSBConfigured = false;
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    
    //*****************************************************************************
    //
    // Interrupt handler for the system tick counter.
    //
    //*****************************************************************************
    void
    SysTickIntHandler(void)
    {
        //
        // Update our system tick counter.
        //
        g_ui32SysTickCount++;
    }
    
    //*****************************************************************************
    //
    // Receive new data and echo it back to the host.
    //
    // \param psDevice points to the instance data for the device whose data is to
    // be processed.
    // \param pi8Data points to the newly received data in the USB receive buffer.
    // \param ui32NumBytes is the number of bytes of data available to be
    // processed.
    //
    // This function is called whenever we receive a notification that data is
    // available from the host. We read the data, byte-by-byte and swap the case
    // of any alphabetical characters found then write it back out to be
    // transmitted back to the host.
    //
    // \return Returns the number of bytes of data processed.
    //
    //*****************************************************************************
    static uint32_t
    EchoNewDataToHost(tUSBDBulkDevice *psDevice, uint8_t *pi8Data,
                      uint_fast32_t ui32NumBytes)
    {
        uint_fast32_t ui32Loop, ui32Space, ui32Count;
        uint_fast32_t ui32ReadIndex;
        uint_fast32_t ui32WriteIndex;
        tUSBRingBufObject sTxRing;
    
        //
        // Get the current buffer information to allow us to write directly to
        // the transmit buffer (we already have enough information from the
        // parameters to access the receive buffer directly).
        //
        USBBufferInfoGet(&g_sTxBuffer, &sTxRing);
    
        //
        // How much space is there in the transmit buffer?
        //
        ui32Space = USBBufferSpaceAvailable(&g_sTxBuffer);
    
        //
        // How many characters can we process this time round?
        //
        ui32Loop = (ui32Space < ui32NumBytes) ? ui32Space : ui32NumBytes;
        ui32Count = ui32Loop;
    
        //
        // Update our receive counter.
        //
        g_ui32RxCount += ui32NumBytes;
    
        //
        // Set up to process the characters by directly accessing the USB buffers.
        //
        ui32ReadIndex = (uint32_t)(pi8Data - g_pui8USBRxBuffer);
        ui32WriteIndex = sTxRing.ui32WriteIndex;
    
        while(ui32Loop)
        {
            //
            // Copy from the receive buffer to the transmit buffer converting
            // character case on the way.
            //
    
            // //
            // // Is this a lower case character?
            // //
            // if((g_pui8USBRxBuffer[ui32ReadIndex] >= 'a') &&
            //    (g_pui8USBRxBuffer[ui32ReadIndex] <= 'z'))
            // {
            //     //
            //     // Convert to upper case and write to the transmit buffer.
            //     //
            //     g_pui8USBTxBuffer[ui32WriteIndex] =
            //         (g_pui8USBRxBuffer[ui32ReadIndex] - 'a') + 'A';
            // }
            // else
            // {
            //     //
            //     // Is this an upper case character?
            //     //
            //     if((g_pui8USBRxBuffer[ui32ReadIndex] >= 'A') &&
            //        (g_pui8USBRxBuffer[ui32ReadIndex] <= 'Z'))
            //     {
            //         //
            //         // Convert to lower case and write to the transmit buffer.
            //         //
            //         g_pui8USBTxBuffer[ui32WriteIndex] =
            //             (g_pui8USBRxBuffer[ui32ReadIndex] - 'Z') + 'z';
            //     }
            //     else
            //     {
            //         //
            //         // Copy the received character to the transmit buffer.
            //         //
                    g_pui8USBTxBuffer[ui32WriteIndex] =
                        g_pui8USBRxBuffer[ui32ReadIndex];
            //     }
            // }
    
            //
            // Move to the next character taking care to adjust the pointer for
            // the buffer wrap if necessary.
            //
            ui32WriteIndex++;
            ui32WriteIndex =
                (ui32WriteIndex == BULK_BUFFER_SIZE) ? 0 : ui32WriteIndex;
    
            ui32ReadIndex++;
    
            ui32ReadIndex = ((ui32ReadIndex == BULK_BUFFER_SIZE) ?
                             0 : ui32ReadIndex);
    
            ui32Loop--;
        }
    
        //
        // We've processed the data in place so now send the processed data
        // back to the host.
        //
        USBBufferDataWritten(&g_sTxBuffer, ui32Count);
    
        //
        // We processed as much data as we can directly from the receive buffer so
        // we need to return the number of bytes to allow the lower layer to
        // update its read pointer appropriately.
        //
        return(ui32Count);
    }
    
    //*****************************************************************************
    //
    // Handles bulk driver notifications related to the transmit channel (data to
    // the USB host).
    //
    // \param pvCBData is the client-supplied callback pointer for this channel.
    // \param ulEvent identifies the event we are being notified about.
    // \param ulMsgValue is an event-specific value.
    // \param pvMsgData is an event-specific pointer.
    //
    // This function is called by the bulk driver to notify us of any events
    // related to operation of the transmit data channel (the IN channel carrying
    // data to the USB host).
    //
    // \return The return value is event-specific.
    //
    //*****************************************************************************
    uint32_t
    TxHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgValue,
              void *pvMsgData)
    {
        //UARTprintf("25\n");
        //
        // We are not required to do anything in response to any transmit event
        // in this example. All we do is update our transmit counter.
        //
        if(ui32Event == USB_EVENT_TX_COMPLETE)
        {
            //UARTprintf("26\n");
            g_ui32TxCount += ui32MsgValue;
        }
        return(0);
    }
    
    //*****************************************************************************
    //
    // Handles bulk driver notifications related to the receive channel (data from
    // the USB host).
    //
    // \param pvCBData is the client-supplied callback pointer for this channel.
    // \param ui32Event identifies the event we are being notified about.
    // \param ui32MsgValue is an event-specific value.
    // \param pvMsgData is an event-specific pointer.
    //
    // This function is called by the bulk driver to notify us of any events
    // related to operation of the receive data channel (the OUT channel carrying
    // data from the USB host).
    //
    // \return The return value is event-specific.
    //
    //*****************************************************************************
    uint32_t
    RxHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgValue,
              void *pvMsgData)
    {
        //UARTprintf("21\n");
        //
        // Which event are we being sent?
        //
        switch(ui32Event)
        {
            //
            // We are connected to a host and communication is now possible.
            //
            case USB_EVENT_CONNECTED:
            {
                //UARTprintf("22\n");
                g_bUSBConfigured = true;
                g_ui32Flags |= COMMAND_STATUS_UPDATE;
    
                //
                // Flush our buffers.
                //
                USBBufferFlush(&g_sTxBuffer);
                USBBufferFlush(&g_sRxBuffer);
    
                break;
            }
    
            //
            // The host has disconnected.
            //
            case USB_EVENT_DISCONNECTED:
            {
                //UARTprintf("23\n");
                g_bUSBConfigured = false;
                g_ui32Flags |= COMMAND_STATUS_UPDATE;
                break;
            }
    
            //
            // A new packet has been received.
            //
            case USB_EVENT_RX_AVAILABLE:
            {
                //UARTprintf("24\n");
                tUSBDBulkDevice *psDevice;
    
                //
                // Get a pointer to our instance data from the callback data
                // parameter.
                //
                psDevice = (tUSBDBulkDevice *)pvCBData;
    
                //
                // Read the new packet and echo it back to the host.
                //
                return(EchoNewDataToHost(psDevice, pvMsgData, ui32MsgValue));
            }
    
            //
            // Ignore SUSPEND and RESUME for now.
            //
            case USB_EVENT_SUSPEND:
            case USB_EVENT_RESUME:
                break;
    
            //
            // Ignore all other events and return 0.
            //
            default:
                break;
        }
    
        return(0);
    }
    
    //*****************************************************************************
    //
    // This is the main application entry function.
    //
    //*****************************************************************************
    int
    main(void)
    {
        uint_fast32_t ui32TxCount;
        uint_fast32_t ui32RxCount;
        uint32_t ui32SysClock;
        uint32_t ui32PLLRate;
    
        //
        // Run from the PLL at 120 MHz.
        // Note: SYSCTL_CFG_VCO_240 is a new setting provided in TivaWare 2.2.x and
        // later to better reflect the actual VCO speed due to SYSCTL#22.
        //
        ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                               SYSCTL_OSC_MAIN |
                                               SYSCTL_USE_PLL |
                                               SYSCTL_CFG_VCO_240), 120000000);
    
        //
        // Configure the device pins.
        //
        PinoutSet(false, true);
    
        //
        // Enable UART0
        //
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, ui32SysClock);
    
        //
        // Not configured initially.
        //
        g_bUSBConfigured = false;
    
        //
        // Enable the system tick.
        //
        MAP_SysTickPeriodSet(ui32SysClock / SYSTICKS_PER_SECOND);
        MAP_SysTickIntEnable();
        MAP_SysTickEnable();
    
        //
        // Show the application name on the display and UART output.
        //
        UARTprintf("\033[2J\nTiva C Series USB bulk device example\n");
        UARTprintf("---------------------------------\n\n");
    
        //
        // Tell the user what we are up to.
        //
        UARTprintf("Configuring USB... \n");
    
        //
        // Initialize the transmit and receive buffers.
        //
        USBBufferInit(&g_sTxBuffer);
        USBBufferInit(&g_sRxBuffer);
    
        //
        // Tell the USB library the CPU clock and the PLL frequency.  This is a
        // new requirement for TM4C129 devices.
        //
        SysCtlVCOGet(SYSCTL_XTAL_25MHZ, &ui32PLLRate);
        USBDCDFeatureSet(0, USBLIB_FEATURE_CPUCLK, &ui32SysClock);
        USBDCDFeatureSet(0, USBLIB_FEATURE_USBPLL, &ui32PLLRate);
    
        //
        // Initialize the USB stack for device mode.
        //
        USBStackModeSet(0, eUSBModeDevice, 0);
    
        //
        // Pass our device information to the USB library and place the device
        // on the bus.
        //
        USBDBulkInit(0, &g_sBulkDevice);
    
        //
        // Wait for initial configuration to complete.
        //
        UARTprintf("Waiting for host...\r");
    
        //
        // Clear our local byte counters.
        //
        ui32RxCount = 0;
        ui32TxCount = 0;
    
        MAP_USBDevEndpointConfigSet(USB0_BASE, USB_EP_1, 64,
                                    (USB_EP_MODE_BULK | USB_EP_DEV_IN |
                                    USB_EP_DMA_MODE_0));
        
        // Endpoint 1 uses Mode 0 and transmit and enables automatic sending
        // when a full packet is sent to the FIFO.
        //
        MAP_USBEndpointDMAConfigSet(USB0_BASE, USB_EP_1, USB_EP_DEV_IN |
        USB_EP_DMA_MODE_0);
        //
        // Assign endpoint 1 to DMA channel 0 using Mode 0, no bursting, transmit,
        // and enable DMA interrupts.
        //
        MAP_USBDMAChannelConfigSet(USB0_BASE, 0, USB_EP_1, USB_DMA_CFG_MODE_0 |
        USB_DMA_CFG_BURST_NONE |
        USB_DMA_CFG_DIR_TX |
        USB_DMA_CFG_INT_EN);
    
        //
        // Main application loop.
        //
        while(1)
        {
            //
            // Have we been asked to update the status display?
            //
            if(g_ui32Flags & COMMAND_STATUS_UPDATE)
            {
                g_ui32Flags &= ~COMMAND_STATUS_UPDATE;
    
                if(g_bUSBConfigured)
                {
                    UARTprintf("Host Connected.            \n\n");
                    UARTprintf("Data transferred:\n");
                    UARTprintf("TX: %d  RX: %d                    \r",
                               g_ui32TxCount,
                               g_ui32RxCount);
                }
                else
                {
                    UARTprintf("\n\nHost Disconnected.\n\n");
                }
            }
    
            //
            // Has there been any transmit traffic since we last checked?
            //
            if(ui32TxCount != g_ui32TxCount)
            {
                //
                // Take a snapshot of the latest transmit count.
                //
                ui32TxCount = g_ui32TxCount;
    
                //
                // Update the displayed buffer count information.
                //
                // UARTprintf("TX: %d  RX: %d                    \r",
                //            g_ui32TxCount,
                //            g_ui32RxCount);
            }
    
            //
            // Has there been any receive traffic since we last checked?
            //
            if(ui32RxCount != g_ui32RxCount)
            {
                //
                // Take a snapshot of the latest receive count.
                //
                ui32RxCount = g_ui32RxCount;
    
                //
                // Update the displayed buffer count information.
                //
                // UARTprintf("TX: %d  RX: %d                    \r",
                //            g_ui32TxCount,
                //            g_ui32RxCount);
            }
        }
    }
    

    2. Trigger DMA in ScheduleNextTransmission function (TivaWare_C_Series-2.2.0.295\usblib\usbbuffer.c)

    //*****************************************************************************
    //
    // usbbuffer.c - USB buffer object.
    //
    // Copyright (c) 2008-2020 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 2.2.0.295 of the Tiva USB Library.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_types.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_ints.h"
    #include "driverlib/debug.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/usb.h"
    #include "usblib/usblib.h"
    #include "usblib/usblibpriv.h"
    #include "utils/uartstdio.h"
    
    //*****************************************************************************
    //
    //! \addtogroup usblib_buffer_api
    //! @{
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // Flags which may be set in the tUSBBufferVars ui32Flags field.
    //
    //*****************************************************************************
    #define USB_BUFFER_FLAG_SEND_ZLP 0x00000001
    
    //*****************************************************************************
    //
    // Schedule the next packet transmission to the host if data remains to be
    // sent.
    //
    // \param psBuffer points to the buffer from which a packet transmission is
    // to be scheduled.
    //
    // This function checks to determine whether the lower layer is capable of
    // accepting a new packet for transmission and, if so, schedules the next
    // packet transmission if data remains in the buffer.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    ScheduleNextTransmission(tUSBBuffer *psBuffer)
    {
        uint32_t ui32Packet, ui32Space, ui32Total, ui32Sent;
    
        //
        // Ask the lower layer if it has space to accept another packet of data.
        //
        ui32Packet = psBuffer->pfnAvailable(psBuffer->pvHandle);
        UARTprintf("ui32Packet = %d\n", ui32Packet);
        //
        // If we were returned something other than zero, we can write that number
        // of bytes to the lower layer.
        //
        if(ui32Packet)
        {
            //
            // How much contiguous data do we have in the buffer?
            //
            ui32Space = USBRingBufContigUsed(&psBuffer->sPrivateData.sRingBuf);
    
            //
            // How much total data do we have in the buffer?
            //
            ui32Total = USBRingBufUsed(&psBuffer->sPrivateData.sRingBuf);
    
            //
            // How much data will we be sending as a result of this call?
            //
            ui32Sent = (ui32Packet < ui32Total) ? ui32Packet : ui32Total;
    
            //
            // Write the contiguous bytes to the lower layer assuming there is
            // something to send.
            //
            if(ui32Space)
            {
                //
                // There is data available to send.  Update our state to indicate
                // the amount we will be sending in this packet.
                //
                psBuffer->sPrivateData.ui32LastSent = ui32Sent;
    
                //
                // Determine the maximum sized block we can send in this transfer.
                //
                ui32Space = (ui32Space < ui32Packet) ? ui32Space : ui32Packet;
                //
                // Call the lower layer to send the new packet.  If the current
                // data spans the buffer wrap, tell the lower layer that it can
                // expect a second call to fill the whole packet before it
                // transmits it.
                //
            //    psBuffer->pfnTransfer(psBuffer->pvHandle,
            //                      (psBuffer->sPrivateData.sRingBuf.pui8Buf +
            //                       psBuffer->sPrivateData.sRingBuf.ui32ReadIndex),
            //                       ui32Space,
            //                      (((ui32Space < ui32Packet) &&
            //                        (ui32Space < ui32Total)) ? false : true));
                //
                // Set the source address for the transfer to pvBuffer.
                //
                MAP_USBDMAChannelAddressSet(USB0_BASE, 0, psBuffer->sPrivateData.sRingBuf.pui8Buf);
                //
                // Set the transfer size to 64 bytes and the packet count to 0.
                //
                MAP_USBDMAChannelCountSet(USB0_BASE, 0, 64);
                MAP_USBEndpointPacketCountSet(USB0_BASE, USB_EP_1, 0);
                //
                // Enable the DMA transfer.
                //
                MAP_USBDMAChannelEnable(USB0_BASE, 0);
    
                //
                // Do we need to send a second part to fill out the packet?  This
                // will occur if the current packet spans the buffer wrap.
                //
                if((ui32Space < ui32Packet) && (ui32Space < ui32Total))
                {
                    //
                    // The packet straddled the wrap.  How much space remains in
                    // the packet?
                    //
                    ui32Packet -= ui32Space;
    
                    //
                    // How much data can we actually send?
                    //
                    ui32Space = ui32Total - ui32Space;
                    ui32Space = (ui32Space > ui32Packet) ? ui32Packet : ui32Space;
    
                    psBuffer->pfnTransfer(psBuffer->pvHandle,
                                          psBuffer->sPrivateData.sRingBuf.pui8Buf,
                                          ui32Space, true);
                }
            }
            else
            {
                //
                // There is no data to send.  Did we last send a full packet?
                //
                if(psBuffer->sPrivateData.ui32LastSent == ui32Packet)
                {
                    //
                    // Yes - if necessary, send a zero-length packet back to the
                    // host to complete the last transaction.
                    //
                    if(psBuffer->sPrivateData.ui32Flags & USB_BUFFER_FLAG_SEND_ZLP)
                    {
                        psBuffer->sPrivateData.ui32LastSent = 0;
                        psBuffer->pfnTransfer(psBuffer->pvHandle,
                                          psBuffer->sPrivateData.sRingBuf.pui8Buf,
                                          0, true);
                    }
                }
            }
    
            //
            // Don't update the ring buffer read index yet.  We do this once we are
            // sure the packet was correctly transmitted.
            //
        }
    }
    
    //*****************************************************************************
    //
    // Handles USB_EVENT_RX_AVAILABLE for a receive buffer.
    //
    // \param psBuffer points to the buffer which is receiving the event.
    // \param ui32Size is the size reported in the event.
    // \param pui8Data is the pointer provided in the event.
    //
    // This function is responsible for reading data from the lower layer into
    // the buffer or, if we had previously passed a section of the buffer to the
    // lower layer for it to write into directly, updating the buffer write pointer
    // to add the new data to the buffer.
    //
    // If the pointer provided is NULL, we call the low level pfnTransfer function
    // to get the new data.  If the pointer is not NULL and not within the existing
    // ring buffer, we copy the data directly from the pointer to the buffer and
    // return the number of bytes read.
    //
    // \return Returns the number of bytes read from the lower layer.
    //
    //*****************************************************************************
    static uint32_t
    HandleRxAvailable(tUSBBuffer *psBuffer, uint32_t ui32Size, uint8_t *pui8Data)
    {
        uint32_t ui32Avail, ui32Read, ui32Packet, ui32RetCount;
    
        //
        // Has the data already been read into memory?
        //
        if(pui8Data)
        {
            //
            // Yes - is it already in our ring buffer?
            //
            if((pui8Data >= psBuffer->pui8Buffer) &&
               (pui8Data < psBuffer->pui8Buffer + psBuffer->ui32BufferSize))
            {
                //
                // The data is already in our ring buffer so merely update the
                // write pointer to add the new data.
                //
                USBRingBufAdvanceWrite(&psBuffer->sPrivateData.sRingBuf, ui32Size);
    
                //
                // In this case, we pass back 0 to indicate that the lower layer
                // doesn't need to make any buffer pointer updates.
                //
                ui32RetCount = 0;
            }
            else
            {
                //
                // The data is not within our buffer so we need to copy it into
                // the buffer.
                //
                // How much space does the buffer have available?
                //
                ui32Avail = USBRingBufFree(&psBuffer->sPrivateData.sRingBuf);
    
                //
                // How much should we copy?
                //
                ui32Read = (ui32Avail < ui32Size) ? ui32Avail : ui32Size;
    
                //
                // Copy the data into the buffer.
                //
                USBRingBufWrite(&psBuffer->sPrivateData.sRingBuf, pui8Data,
                                ui32Read);
    
                //
                // We need to return the number of bytes we read in this case
                // since the buffer supplied to us was owned by the lower layer and
                // it may need to update its read pointer.
                //
                ui32RetCount = ui32Read;
            }
        }
        else
        {
            //
            // We were passed a NULL pointer so the low level driver has not read
            // the data into memory yet.  We need to call the transfer function to
            // get the packet.
            //
            // How big is the packet that we need to receive?
            //
            ui32Packet = psBuffer->pfnAvailable(psBuffer->pvHandle);
    
            //
            // How much contiguous space do we have in the buffer?
            //
            ui32Avail = USBRingBufContigFree(&psBuffer->sPrivateData.sRingBuf);
    
            //
            // Get as much of the packet as we can in the available space.
            //
            ui32Read = psBuffer->pfnTransfer(psBuffer->pvHandle,
                                  (psBuffer->sPrivateData.sRingBuf.pui8Buf +
                                   psBuffer->sPrivateData.sRingBuf.ui32WriteIndex),
                                  ui32Avail, true);
    
            //
            // Advance the ring buffer write pointer to add our new data.
            //
            if(ui32Read)
            {
                USBRingBufAdvanceWrite(&psBuffer->sPrivateData.sRingBuf, ui32Read);
            }
    
            //
            // Did we get the whole packet?
            //
            if(ui32Read < ui32Packet)
            {
                //
                // No - how much space do we have in the buffer?
                //
                ui32Avail = USBRingBufContigFree(&psBuffer->sPrivateData.sRingBuf);
    
                //
                // If there is any space left, read as much of the remainder of
                // the packet as we can.
                //
                if(ui32Avail)
                {
                    ui32Packet =
                        psBuffer->pfnTransfer(psBuffer->pvHandle,
                                  (psBuffer->sPrivateData.sRingBuf.pui8Buf +
                                   psBuffer->sPrivateData.sRingBuf.ui32WriteIndex),
                                   ui32Avail, true);
    
                    //
                    // Update the write pointer after we read more data into the
                    // buffer.
                    //
                    if(ui32Packet)
                    {
                        USBRingBufAdvanceWrite(&psBuffer->sPrivateData.sRingBuf,
                                               ui32Packet);
                    }
                }
            }
    
            //
            // We need to return 0 in this case to indicate that the lower layer
            // need not perform any buffer maintenance as a result of the callback.
            //
            ui32RetCount = 0;
        }
    
        //
        // How much data do we have in the buffer?
        //
        ui32Avail = USBRingBufUsed(&psBuffer->sPrivateData.sRingBuf);
    
        //
        // Pass the event on to the client with the current read pointer and
        // available data size.  The client is expected to understand the ring
        // structure and be able to deal with wrap if it wants to read the data
        // directly from the buffer.
        //
        ui32Read = psBuffer->pfnCallback(psBuffer->pvCBData,
                                 USB_EVENT_RX_AVAILABLE, ui32Avail,
                                 (psBuffer->sPrivateData.sRingBuf.pui8Buf +
                                  psBuffer->sPrivateData.sRingBuf.ui32ReadIndex));
    
        //
        // If the client read anything from the buffer, update the read pointer.
        //
        USBRingBufAdvanceRead(&psBuffer->sPrivateData.sRingBuf, ui32Read);
    
        //
        // Return the correct value to the low level driver.
        //
        return(ui32RetCount);
    }
    
    //*****************************************************************************
    //
    // Handles USB_EVENT_DATA_REMAINING for a receive buffer.
    //
    // \param psBuffer points to the buffer which is receiving the event.
    //
    // This function determines the total number of bytes of data that remain
    // unprocessed in the client and buffer and reports this back to the caller.
    //
    // \return Returns the number of bytes remaining to be processed.
    //
    //*****************************************************************************
    static uint32_t
    HandleDataRemaining(tUSBBuffer *psBuffer)
    {
        uint32_t ui32BufData, ui32ClientData;
    
        //
        // How much data does the client currently have buffered?
        //
        ui32ClientData = psBuffer->pfnCallback(psBuffer->pvCBData,
                                               USB_EVENT_DATA_REMAINING, 0,
                                               (void *)0);
    
        //
        // How much data do we have in the buffer?
        //
        ui32BufData = USBRingBufUsed(&psBuffer->sPrivateData.sRingBuf);
    
        //
        // Return the total number of bytes of unprocessed data to the lower layer.
        //
        return(ui32BufData + ui32ClientData);
    }
    
    //*****************************************************************************
    //
    // Handles USB_EVENT_TX_COMPLETE for a transmit buffer.
    //
    // \param psBuffer points to the buffer which is receiving the event.
    // \param ui32Size is the number of bytes that have been transmitted and
    // acknowledged.
    //
    // This function informs us that data written to the lower layer from a
    // transmit buffer has been successfully transmitted.  We use this to update
    // the buffer read pointer and attempt to schedule the next transmission if
    // data remains in the buffer.
    //
    // \return Returns the number of bytes remaining to be processed.
    //
    //*****************************************************************************
    static uint32_t
    HandleTxComplete(tUSBBuffer *psBuffer, uint32_t ui32Size)
    {
        //
        // Update the transmit buffer read pointer to remove the data that has
        // now been transmitted.
        //
        UARTprintf("HandleTxComplete\n");
        USBRingBufAdvanceRead(&psBuffer->sPrivateData.sRingBuf, ui32Size);
    
        //
        // Try to schedule the next packet transmission if data remains to be
        // sent.
        //
        ScheduleNextTransmission(psBuffer);
    
        //
        // The return code from this event is ignored.
        //
        return(0);
    }
    
    //*****************************************************************************
    //
    // Handles USB_EVENT_REQUEST_BUFFER for a receive buffer.
    //
    // \param psBuffer points to the buffer which is receiving the event.
    // \param ui32Size is the size of the buffer requested.
    // \param ppui8Buffer is a pointer which is to be written with a pointer to
    // the returned buffer.
    //
    // This function is called by a low level driver that wishes to receive data
    // automatically and write it directly to a memory buffer, either using
    // software or DMA prior to issuing USB_EVENT_RX_AVAILABLE.  The event is sent
    // in advance of receiving data to provide storage for whatever is received
    // next.
    //
    // If we have a contiguous block of space in the buffer of at least ui32Size
    // bytes immediately in front of the current write pointer, we pass this back
    // otherwise we send NULL indicating that the next packet should be notified
    // using a standard USB_EVENT_RX_AVAILABLE event without being received
    // automatically.  Note that the USB_EVENT_REQUEST_BUFFER protocol allows us to
    // return less than \e ui32Size bytes if we know how much data is expected next
    // but this is not possible here since the USBBuffer knows nothing about the
    // protocol whose data it is handling.
    //
    // \return Returns the number of bytes remaining to be processed.
    //
    //*****************************************************************************
    static uint32_t
    HandleRequestBuffer(tUSBBuffer *psBuffer, uint32_t ui32Size,
                        uint8_t **ppui8Buffer)
    {
        uint32_t ui32Space;
    
        //
        // How much contiguous space do we have available?
        //
        ui32Space = USBRingBufContigFree(&psBuffer->sPrivateData.sRingBuf);
    
        //
        // Is there enough space available to satisfy the request?
        //
        if(ui32Space >= ui32Size)
        {
            //
            // Yes - return the current write pointer
            //
            *ppui8Buffer = psBuffer->sPrivateData.sRingBuf.pui8Buf +
                           psBuffer->sPrivateData.sRingBuf.ui32WriteIndex;
            return(ui32Size);
        }
        else
        {
            //
            // We do not have enough contiguous space following the current write
            // pointer to satisfy the request so do not provide a buffer.
            //
            *ppui8Buffer = (uint8_t *)0;
            return(0);
        }
    }
    
    //*****************************************************************************
    //
    //! Initializes a USB buffer object to be used with a given USB controller and
    //! device or host class driver.
    //!
    //! \param psBuffer points to a structure containing information on the buffer
    //! memory to be used and the underlying device or host class driver whose data
    //! is to be buffered.  This structure must remain accessible for as long as
    //! the buffer is in use.
    //!
    //! This function is used to initialize a USB buffer object and insert it
    //! into the function and callback interfaces between an underlying driver
    //! and the application.  The caller supplies information on both the RAM
    //! to be used to buffer data, the type of buffer to be created (transmit or
    //! receive) and the functions to be called in the lower layer to transfer
    //! data to or from the USB controller.
    //!
    //! \return Returns the original buffer structure pointer if successful or
    //! NULL if an error is detected.
    //
    //*****************************************************************************
    const tUSBBuffer *
    USBBufferInit(tUSBBuffer *psBuffer)
    {
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer && psBuffer->pui8Buffer &&
               psBuffer->ui32BufferSize && psBuffer->pfnAvailable &&
               psBuffer->pfnTransfer && psBuffer->pfnCallback);
    
        //
        // Get a pointer to the buffer workspace and initialize the variables it
        // contains.
        //
        psBuffer->sPrivateData.ui32Flags = 0;
        USBRingBufInit(&psBuffer->sPrivateData.sRingBuf, psBuffer->pui8Buffer,
                       psBuffer->ui32BufferSize);
    
        //
        // If all is well, return the same pointer we were originally passed.
        //
        return(psBuffer);
    }
    
    //*****************************************************************************
    //
    //! Enables or disables zero-length packet insertion.
    //!
    //! \param psBuffer is the pointer to the buffer instance whose information
    //! is being queried.
    //! \param bSendZLP is \b true to send zero-length packets or \b false to
    //! prevent them from being sent.
    //!
    //! This function allows the use of zero-length packets to be controlled by
    //! an application.  In cases where the USB buffer has sent a full (64 byte)
    //! packet and then discovers that the transmit buffer is empty, the default
    //! behavior is to do nothing.  Some protocols, however, require that a zero-
    //! length packet be inserted to signal the end of the data.  When using such
    //! a protocol, this function should be called with \e bSendZLP set to \b true
    //! to enable the desired behavior.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBufferZeroLengthPacketInsert(const tUSBBuffer *psBuffer, bool bSendZLP)
    {
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // Set the flag telling us whether or not to send a zero-length packet
        // after sending a full packet (64 bytes and 512 bytes for HS) and 
        // finding no more data to send.
        //
        if(bSendZLP)
        {
            //
            // Enable ZLP transmission.
            //
            psPrivate->ui32Flags |= USB_BUFFER_FLAG_SEND_ZLP;
        }
        else
        {
            //
            // Disable ZLP transmission.
            //
            psPrivate->ui32Flags &= ~ USB_BUFFER_FLAG_SEND_ZLP;
        }
    }
    
    //*****************************************************************************
    //
    //! Returns the current ring buffer indices for this USB buffer.
    //!
    //! \param psBuffer is the pointer to the buffer instance whose information
    //! is being queried.
    //! \param psRingBuf is a pointer to storage that will be written with the
    //! current ring buffer control structure for this USB buffer.
    //!
    //! This function is provided to aid a client wishing to write data directly
    //! into the USB buffer rather than using the USBBufferWrite() function.  This
    //! may be necessary to control when the USBBuffer starts transmission of a
    //! large block of data, for example.
    //!
    //! A transmit buffer will immediately send a new packet on any call to
    //! USBBufferWrite() if the underlying layer indicates that a transmission can
    //! be started.  In some cases this is not desirable and a client may wish to
    //! wishes to write more data to the buffer in advance of starting transmission
    //! to the lower layer.  In such cases, this function may be called to retrieve
    //! the current ring buffer indices and the buffer accessed directly.  Once the
    //! client has written all data it wishes to send, it should call function
    //! USBBufferDataWritten() to indicate that transmission may begin.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBufferInfoGet(const tUSBBuffer *psBuffer, tUSBRingBufObject *psRingBuf)
    {
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer && psRingBuf);
    
        //
        // Copy the current ring buffer settings to the clients storage.
        //
        psRingBuf->pui8Buf = psBuffer->sPrivateData.sRingBuf.pui8Buf;
        psRingBuf->ui32ReadIndex = psBuffer->sPrivateData.sRingBuf.ui32ReadIndex;
        psRingBuf->ui32Size = psBuffer->sPrivateData.sRingBuf.ui32ReadIndex;
        psRingBuf->ui32WriteIndex = psBuffer->sPrivateData.sRingBuf.ui32WriteIndex;
    }
    
    //*****************************************************************************
    //
    //! Indicates that a client has written data directly into the buffer and
    //! wishes to start transmission.
    //!
    //! \param psBuffer is the pointer to the buffer instance into which data has
    //! been written.
    //! \param ui32Length is the number of bytes of data that the client has
    //! written.
    //!
    //! This function updates the USB buffer write pointer and starts transmission
    //! of the data in the buffer assuming the lower layer is ready to receive a
    //! new packet.  The function is provided to aid a client wishing to write
    //! data directly into the USB buffer rather than using the USBBufferWrite()
    //! function.  This may be necessary to control when the USB buffer starts
    //! transmission of a large block of data, for example.
    //!
    //! A transmit buffer will immediately send a new packet on any call to
    //! USBBufferWrite() if the underlying layer indicates that a transmission can
    //! be started.  In some cases this is not desirable and a client may wish to
    //! write more data to the buffer in advance of starting transmission
    //! to the lower layer.  In such cases, USBBufferInfoGet() may be called to
    //! retrieve the current ring buffer indices and the buffer accessed directly.
    //! Once the client has written all data it wishes to send (taking care to
    //! handle the ring buffer wrap), it should call this function to indicate that
    //! transmission may begin.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBufferDataWritten(const tUSBBuffer *psBuffer, uint32_t ui32Length)
    {
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // Advance the ring buffer write pointer to include the newly written
        // data.
        //
        if(ui32Length)
        {
            USBRingBufAdvanceWrite(&psPrivate->sRingBuf, ui32Length);
        }
        UARTprintf("ScheduleNextTransmission 1\n");
        //
        // Try to schedule a new packet transmission.
        //
        ScheduleNextTransmission((tUSBBuffer *)psBuffer);
    }
    
    //*****************************************************************************
    //
    //! Indicates that a client has read data directly out of the buffer.
    //!
    //! \param psBuffer is the pointer to the buffer instance from which data has
    //! been read.
    //! \param ui32Length is the number of bytes of data that the client has read.
    //!
    //! This function updates the USB buffer read pointer to remove data that
    //! the client has read directly rather than via a call to USBBufferRead().
    //! The function is provided to aid a client wishing to minimize data copying.
    //! To read directly from the buffer, a client must call USBBufferInfoGet() to
    //! retrieve the current buffer inpsBufVarsdices.  With this information, the
    //! data following the current read index can be read.  Once the client has
    //! processed much data as it needs, USBBufferDataRemoved() must be called to
    //! advance the read pointer past the data that has been read and free up that
    //! section of the buffer.  The client must take care to correctly handle the
    //! wrap point if accessing the buffer directly.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBufferDataRemoved(const tUSBBuffer *psBuffer, uint32_t ui32Length)
    {
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // Advance the ring buffer write pointer to include the newly written
        // data.
        //
        if(ui32Length)
        {
            USBRingBufAdvanceRead(&psPrivate->sRingBuf, ui32Length);
        }
    }
    
    //*****************************************************************************
    //
    //! Sets the callback pointer supplied to clients of this buffer.
    //!
    //! \param psBuffer is the pointer to the buffer instance whose callback data
    //! is to be changed.
    //! \param pvCBData is the pointer the client wishes to receive on all future
    //! callbacks from this buffer.
    //!
    //! This function sets the callback pointer which this buffer will supply
    //! to clients as the \e pvCBData parameter in all future calls to the
    //! event callback.
    //!
    //! \note If this function is to be used, the application must ensure that the
    //! tUSBBuffer structure used to describe this buffer is held in RAM rather
    //! than flash.  The \e pvCBData value passed is written directly into this
    //! structure.
    //!
    //! \return Returns the previous callback pointer set for the buffer.
    //
    //*****************************************************************************
    void *
    USBBufferCallbackDataSet(tUSBBuffer *psBuffer, void *pvCBData)
    {
        void *pvOldData;
    
        //
        // Keep a copy of the old callback data.
        //
        pvOldData = psBuffer->pvCBData;
    
        //
        // Replace the callback data with the new value.
        //
        psBuffer->pvCBData = pvCBData;
    
        //
        // Give the caller the old value back.
        //
        return(pvOldData);
    }
    
    //*****************************************************************************
    //
    //! Writes a block of data to the transmit buffer and queues it for
    //! transmission to the USB controller.
    //!
    //! \param psBuffer points to the pointer instance into which data is to be
    //! written.
    //! \param pui8Data points to the first byte of data which is to be written.
    //! \param ui32Length is the number of bytes of data to write to the buffer.
    //!
    //! This function copies the supplied data into the transmit buffer.  The
    //! transmit buffer data will be packetized according to the constraints
    //! imposed by the lower layer in use and sent to the USB controller as soon as
    //! possible.  Once a packet is transmitted and acknowledged, a
    //! \b USB_EVENT_TX_COMPLETE event will be sent to the application callback
    //! indicating the number of bytes that have been sent from the buffer.
    //!
    //! Attempts to send more data than there is space for in the transmit buffer
    //! will result in fewer bytes than expected being written.  The value returned
    //! by the function indicates the actual number of bytes copied to the buffer.
    //!
    //! \return Returns the number of bytes actually written.
    //
    //*****************************************************************************
    uint32_t
    USBBufferWrite(const tUSBBuffer *psBuffer, const uint8_t *pui8Data,
                   uint32_t ui32Length)
    {
        uint32_t ui32Space;
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer && pui8Data);
        ASSERT(psBuffer->bTransmitBuffer == true);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // How much space is left in the buffer?
        //
        ui32Space = USBRingBufFree(&psPrivate->sRingBuf);
    
        //
        // How many bytes will we write?
        //
        ui32Length = (ui32Length > ui32Space) ? ui32Space : ui32Length;
    
        //
        // Write the data to the buffer.
        //
        if(ui32Length)
        {
            USBRingBufWrite(&psPrivate->sRingBuf, pui8Data, ui32Length);
        }
        UARTprintf("ScheduleNextTransmission 2\n");
        //
        // Try to transmit the next packet to the host.
        //
        ScheduleNextTransmission((tUSBBuffer *)psBuffer);
    
        //
        // Tell the caller how many bytes we wrote to the buffer.
        //
        return(ui32Length);
    }
    
    //*****************************************************************************
    //
    //! Flushes a USB buffer, discarding any data that it contains.
    //!
    //! \param psBuffer is the pointer to the buffer instance which is to be
    //! flushed.
    //!
    //! This function discards all data currently in the supplied buffer without
    //! processing (transmitting it via the USB controller or passing it to the
    //! client depending upon the buffer mode).
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBufferFlush(const tUSBBuffer *psBuffer)
    {
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // Flush the ring buffer.
        //
        USBRingBufFlush(&psPrivate->sRingBuf);
    }
    
    //*****************************************************************************
    //
    //! Reads a block of data from a USB receive buffer into storage supplied by
    //! the caller.
    //!
    //! \param psBuffer is the pointer to the buffer instance from which data is
    //! to be read.
    //! \param pui8Data points to a buffer into which the received data will be
    //! written.
    //! \param ui32Length is the size of the buffer pointed to by pui8Data.
    //!
    //! This function reads up to \e ui32Length bytes of data received from the USB
    //! host into the supplied application buffer.  If the receive buffer
    //! contains fewer than \e ui32Length bytes of data, the data that is present
    //! will be copied and the return code will indicate the actual number of bytes
    //! copied to \e pui8Data.
    //!
    //! \return Returns the number of bytes of data read.
    //
    //*****************************************************************************
    uint32_t
    USBBufferRead(const tUSBBuffer *psBuffer, uint8_t *pui8Data,
                  uint32_t ui32Length)
    {
        uint32_t ui32Avail, ui32Read;
        tUSBBufferVars *psPrivate;
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer && pui8Data && ui32Length);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // How much data is in the buffer?
        //
        ui32Avail = USBRingBufUsed(&psPrivate->sRingBuf);
    
        //
        // Determine how many bytes we can actually read.
        //
        ui32Read = (ui32Avail < ui32Length) ? ui32Avail : ui32Length;
    
        //
        // Read the data from the buffer assuming there is some to read.
        //
        if(ui32Read)
        {
            USBRingBufRead(&psPrivate->sRingBuf, pui8Data, ui32Read);
        }
    
        //
        // Tell the caller how many bytes we wrote to their buffer.
        //
        return(ui32Read);
    }
    
    //*****************************************************************************
    //
    //! Returns the number of bytes of data available in the buffer.
    //!
    //! \param psBuffer is the pointer to the buffer instance which is to be
    //! queried.
    //!
    //! This function may be used to determine the number of bytes of data in a
    //! buffer.  For a receive buffer, this indicates the number of bytes that the
    //! client can read from the buffer using USBBufferRead().  For a transmit
    //! buffer, this indicates the amount of data that remains to be sent to the
    //! USB controller.
    //!
    //! \return Returns the number of bytes of data in the buffer.
    //
    //*****************************************************************************
    uint32_t
    USBBufferDataAvailable(const tUSBBuffer *psBuffer)
    {
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // Return the amount of data in the buffer.
        //
        return(USBRingBufUsed(&psPrivate->sRingBuf));
    }
    
    //*****************************************************************************
    //
    //! Returns the number of free bytes in the buffer.
    //!
    //! \param psBuffer is the pointer to the buffer instance which is to be
    //! queried.
    //!
    //! This function returns the number of free bytes in the buffer.  For a
    //! transmit buffer, this indicates the maximum number of bytes that can be
    //! passed on a call to USBBufferWrite() and accepted for transmission.  For a
    //! receive buffer, it indicates the number of bytes that can be read from the
    //! USB controller before the buffer will be full.
    //!
    //! \return Returns the number of free bytes in the buffer.
    //
    //*****************************************************************************
    uint32_t
    USBBufferSpaceAvailable(const tUSBBuffer *psBuffer)
    {
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // Return the amount of space available in the buffer.
        //
        return(USBRingBufFree(&psPrivate->sRingBuf));
    }
    
    //*****************************************************************************
    //
    //! Called by the USB buffer to notify the client of asynchronous events.
    //!
    //! \param pvCBData is the client-supplied callback pointer associated with
    //! this buffer instance.
    //! \param ui32Event is the identifier of the event being sent.  This will be
    //! a general event identifier of the form \b USBD_EVENT_xxxx or a device
    //! class-dependent event of the form \b USBD_CDC_EVENT_xxx or
    //! \b USBD_HID_EVENT_xxx.
    //! \param ui32MsgValue is an event-specific parameter value.
    //! \param pvMsgData is an event-specific data pointer.
    //!
    //! This function is the USB buffer event handler that applications should
    //! register with the USB device class driver as the callback for the channel
    //! which is to be buffered using this buffer.
    //!
    //! \note This function will never be called by an application.  It is the
    //! handler that allows the USB buffer to be inserted above the device class
    //! driver or host pipe driver and below the application to offer buffering
    //! support.
    //!
    //! \return The return value is dependent upon the event being processed.
    //
    //*****************************************************************************
    uint32_t
    USBBufferEventCallback(void *pvCBData, uint32_t ui32Event,
                           uint32_t ui32MsgValue, void *pvMsgData)
    {
        tUSBBuffer *psBuffer;
    
        //
        // Get our instance data pointers from the callback data.
        //
        psBuffer = (tUSBBuffer *)pvCBData;
        ASSERT(psBuffer);
    
        //
        // Which event have we been sent?
        //
        switch(ui32Event)
        {
            //
            // Data is available from the lower layer.
            //
            case USB_EVENT_RX_AVAILABLE:
            {
                //
                // This event is only relevant to us if we are a receive buffer.
                //
                if(!psBuffer->bTransmitBuffer)
                {
                    return(HandleRxAvailable(psBuffer, ui32MsgValue, pvMsgData));
                }
                break;
            }
    
            //
            // We are being asked how much data remains to be processed.
            //
            case USB_EVENT_DATA_REMAINING:
            {
                return(HandleDataRemaining(psBuffer));
            }
    
            //
            // A previous transmission has completed.
            //
            case USB_EVENT_TX_COMPLETE:
            {
                //
                // This event is only relevant to us if we are a transmit buffer.
                //
                if(psBuffer->bTransmitBuffer)
                {
                    //
                    // Handle the message then drop out of the switch so that the
                    // event is echoed to the layer above.
                    //
                    HandleTxComplete(psBuffer, ui32MsgValue);
                }
                break;
            }
    
            //
            // We are being asked to provide a buffer into which the next packet
            // can be received.
            //
            case USB_EVENT_REQUEST_BUFFER:
            {
                //
                // This event is only relevant to us if we are a receive buffer.
                //
                if(!psBuffer->bTransmitBuffer)
                {
                    return(HandleRequestBuffer(psBuffer, ui32MsgValue, pvMsgData));
                }
                break;
            }
    
            //
            // All other events are merely passed through to the client.
            //
            default:
            {
                break;
            }
        }
    
        //
        // If we drop out of the switch, we need to pass the event on to the client
        // unmodified and return the relevant return code back to the lower layer.
        //
        return(psBuffer->pfnCallback(psBuffer->pvCBData, ui32Event, ui32MsgValue,
                                     pvMsgData));
    }
    
    //*****************************************************************************
    //
    // Close the Doxygen group.
    //! @}
    //
    //*****************************************************************************
    

    3. Handle DMA INT (TivaWare_C_Series-2.2.0.295\usblib\device\usbdenum.c)

    //*****************************************************************************
    //
    // usbenum.c - Enumeration code to handle all endpoint zero traffic.
    //
    // Copyright (c) 2007-2020 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 2.2.0.295 of the Tiva USB Library.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_sysctl.h"
    #include "driverlib/debug.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/usb.h"
    #include "driverlib/rtos_bindings.h"
    #include "usblib/usblib.h"
    #include "usblib/usblibpriv.h"
    #include "usblib/usbulpi.h"
    #include "usblib/device/usbdevice.h"
    #include "usblib/device/usbdevicepriv.h"
    #include "usblib/device/usbdbulk.h"
    #include "usblib/usblibpriv.h"
    #include "utils/uartstdio.h"
    
    //*****************************************************************************
    //
    // External prototypes.
    //
    //*****************************************************************************
    extern tUSBMode g_iUSBMode;
    
    //*****************************************************************************
    //
    // Local functions prototypes.
    //
    //*****************************************************************************
    static void USBDGetStatus(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDClearFeature(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDSetFeature(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDSetAddress(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDGetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDSetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDGetConfiguration(void *pvInstance,
                                     tUSBRequest *psUSBRequest);
    static void USBDSetConfiguration(void *pvInstance,
                                     tUSBRequest *psUSBRequest);
    static void USBDGetInterface(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDSetInterface(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDSyncFrame(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDEP0StateTx(uint32_t ui32Index);
    static void USBDEP0StateTxConfig(uint32_t ui32Index);
    static int32_t USBDStringIndexFromRequest(uint16_t ui16Lang,
                                              uint16_t ui16Index);
    
    //*****************************************************************************
    //
    //! \addtogroup device_api
    //! @{
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // Indices into the ppui8Halt array to select the IN or OUT endpoint group.
    //
    //*****************************************************************************
    #define HALT_EP_IN              0
    #define HALT_EP_OUT             1
    
    //*****************************************************************************
    //
    // Define the max packet size for endpoint zero.
    //
    //*****************************************************************************
    #define EP0_MAX_PACKET_SIZE     64
    
    //*****************************************************************************
    //
    // This is a flag used with g_sUSBDeviceState.ui32DevAddress to indicate that a
    // device address change is pending.
    //
    //*****************************************************************************
    #define DEV_ADDR_PENDING        0x80000000
    
    //*****************************************************************************
    //
    // This label defines the default configuration number to use after a bus
    // reset.  This may be overridden by calling USBDCDSetDefaultConfiguration()
    // during processing of the device reset handler if required.
    //
    //*****************************************************************************
    #define DEFAULT_CONFIG_ID       1
    
    //*****************************************************************************
    //
    // This label defines the number of milliseconds that the remote wake up signal
    // must remain asserted before removing it. Section 7.1.7.7 of the USB 2.0 spec
    // states that "the remote wake up device must hold the resume signaling for at
    // least 1ms but for no more than 15ms" so 10mS seems a reasonable choice.
    //
    //*****************************************************************************
    #define REMOTE_WAKEUP_PULSE_MS 10
    
    //*****************************************************************************
    //
    // This label defines the number of milliseconds between the point where we
    // assert the remote wake up signal and calling the client back to tell it that
    // bus operation has been resumed.  This value is based on the timings provided
    // in section 7.1.7.7 of the USB 2.0 specification which indicates that the
    // host (which takes over resume signaling when the device's initial signal is
    // detected) must hold the resume signaling for at least 20mS.
    //
    //*****************************************************************************
    #define REMOTE_WAKEUP_READY_MS 20
    
    //*****************************************************************************
    //
    // The LPM states.
    //
    //*****************************************************************************
    #define USBLIB_LPM_STATE_DISABLED   0x00000000
    #define USBLIB_LPM_STATE_AWAKE      0x00000001
    #define USBLIB_LPM_STATE_SLEEP      0x00000002
    
    //*****************************************************************************
    //
    // The buffer for reading data coming into EP0
    //
    //*****************************************************************************
    static uint8_t g_pui8DataBufferIn[EP0_MAX_PACKET_SIZE];
    
    //*****************************************************************************
    //
    // This is 480000000/60000000 or a PLL Divide of 8.
    //
    //*****************************************************************************
    static uint32_t g_ui32PLLDiv = 8;
    
    //*****************************************************************************
    //
    // Holds the ULPI configuration.
    //
    //*****************************************************************************
    static uint32_t g_ui32ULPISupport;
    
    //*****************************************************************************
    //
    // This is the instance data for the USB controller itself and not a USB
    // device class.
    //
    //*****************************************************************************
    tDCDInstance g_psDCDInst[1];
    
    //*****************************************************************************
    //
    // This is the currently active class in use by USBLib.  There is only one
    // of these per USB controller and no device has more than one controller.
    //
    //*****************************************************************************
    tDeviceInfo *g_ppsDevInfo[1];
    
    //*****************************************************************************
    //
    // Function table to handle standard requests.
    //
    //*****************************************************************************
    static const tStdRequest g_psUSBDStdRequests[] =
    {
        USBDGetStatus,
        USBDClearFeature,
        0,
        USBDSetFeature,
        0,
        USBDSetAddress,
        USBDGetDescriptor,
        USBDSetDescriptor,
        USBDGetConfiguration,
        USBDSetConfiguration,
        USBDGetInterface,
        USBDSetInterface,
        USBDSyncFrame
    };
    
    //*****************************************************************************
    //
    // Functions accessible by USBLIB clients.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    //! Initialize an instance of the tDeviceInfo structure.
    //!
    //! \param ui32Index is the index of the USB controller which is to be
    //! initialized.
    //! \param psDeviceInfo is a pointer to the tDeviceInfo structure that needs
    //! to be initialized.
    //!
    //! This function must be called by a USB device class
    //! instance to initialize the basic tDeviceInfo required for all USB device
    //! class modules.  This is typically called in the initialization routine for
    //! USB device class.  For example in usbdaudio.c that supports USB device
    //! audio classes, this function is called in the USBDAudioCompositeInit()
    //! function which is used for both composite and non-composites instances of
    //! the USB audio class.
    //!
    //! \note This function should not be called directly by applications.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDDeviceInfoInit(uint32_t ui32Index, tDeviceInfo *psDeviceInfo)
    {
        //
        // Check the arguments.
        //
        ASSERT(ui32Index == 0);
        ASSERT(psDeviceInfo != 0);
    
        //
        // Save the USB interrupt number.
        //
        g_psDCDInst[0].ui32IntNum = INT_USB0_TM4C123;
    
        //
        // These devices have a different USB interrupt number.
        //
        if(CLASS_IS_TM4C129)
        {
            g_psDCDInst[0].ui32IntNum = INT_USB0_TM4C129;
        }
    
        //
        // Disable LPM support by default.
        //
        g_psDCDInst[0].ui32LPMState = 0;
    
        //
        // Initialize a couple of fields in the device state structure.
        //
        g_psDCDInst[0].ui32Configuration = DEFAULT_CONFIG_ID;
        g_psDCDInst[0].ui32DefaultConfiguration = DEFAULT_CONFIG_ID;
    
        g_psDCDInst[0].iEP0State = eUSBStateIdle;
    
        //
        // Default to the state where remote wake up is disabled.
        //
        g_psDCDInst[0].ui8Status = 0;
        g_psDCDInst[0].bRemoteWakeup = false;
    
        //
        // Determine the self- or bus-powered state based on the flags the
        // user provided.
        //
        g_psDCDInst[0].bPwrSrcSet = false;
    }
    
    //*****************************************************************************
    //
    //! Initialize the USB library device control driver for a given hardware
    //! controller.
    //!
    //! \param ui32Index is the index of the USB controller which is to be
    //! initialized.
    //! \param psDevice is a pointer to a structure containing information that
    //! the USB library requires to support operation of this application's
    //! device.  The structure contains event handler callbacks and pointers to the
    //! various standard descriptors that the device wishes to publish to the
    //! host.
    //! \param pvDCDCBData is the callback data for any device callbacks.
    //!
    //! This function must be called by a device class which wishes to operate
    //! as a USB device and is not typically called by an application.  This
    //! function initializes the USB device control driver for the given
    //! controller and saves the device information for future use.  Prior to
    //! returning from this function, the device is connected to the USB bus.
    //! Following return, the caller can expect to receive a callback to the
    //! supplied <tt>pfnResetHandler</tt> function when a host connects to the
    //! device.  The \e pvDCDCBData contains a pointer to data that is returned
    //! with the DCD calls back to the function in the psDevice->psCallbacks()
    //! functions.
    //!
    //! The device information structure passed in \e psDevice must remain
    //! unchanged between this call and any matching call to USBDCDTerm() because
    //! it is not copied by the USB library.
    //!
    //! The USBStackModeSet() function can be called with eUSBModeForceDevice in
    //! order to cause the USB library to force the USB operating mode to a device
    //! controller.  This allows the application to used the USBVBUS and USBID pins
    //! as GPIOs on devices that support forcing OTG to operate as a device only
    //! controller.  By default the USB library will assume that the USBVBUS and
    //! USBID pins are configured as USB pins and not GPIOs.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDInit(uint32_t ui32Index, tDeviceInfo *psDevice, void *pvDCDCBData)
    {
        const tConfigHeader *psHdr;
        const tConfigDescriptor *psDesc;
    
        //
        // Check the arguments.
        //
        ASSERT(ui32Index == 0);
        ASSERT(psDevice != 0);
    
        g_ppsDevInfo[0] = psDevice;
        g_psDCDInst[0].pvCBData = pvDCDCBData;
    
        //
        // Initialize the Device Info structure for a USB device instance.
        //
        USBDCDDeviceInfoInit(ui32Index, psDevice);
    
        //
        // Should not call this if the stack is in host mode.
        //
        ASSERT(g_iUSBMode != eUSBModeHost);
        ASSERT(g_iUSBMode != eUSBModeForceHost);
    
        //
        // Default to device mode if no mode was set.
        //
        if(g_iUSBMode == eUSBModeNone)
        {
            g_iUSBMode = eUSBModeDevice;
        }
    
        //
        // Only do hardware update if the stack is in not in OTG mode.
        //
        if(g_iUSBMode != eUSBModeOTG)
        {
            //
            // Reset the USB controller.
            //
            MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
    
            //
            // Enable Clocking to the USB controller.
            //
            MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
    
            //
            // Turn on USB Phy clock.
            //
            MAP_SysCtlUSBPLLEnable();
    
            //
            // Set the PLL to USB clock divider.
            //
            if(g_ui32PLLDiv == 0)
            {
                USBClockEnable(USB0_BASE, g_ui32PLLDiv, USB_CLOCK_EXTERNAL);
            }
            else
            {
                USBClockEnable(USB0_BASE, g_ui32PLLDiv, USB_CLOCK_INTERNAL);
            }
    
            //
            // Configure ULPI support.
            //
            if(g_ui32ULPISupport != USBLIB_FEATURE_ULPI_NONE)
            {
                USBULPIEnable(USB0_BASE);
    
                if(g_ui32ULPISupport & USBLIB_FEATURE_ULPI_HS)
                {
                    ULPIConfigSet(USB0_BASE, ULPI_CFG_HS);
                }
                else
                {
                    ULPIConfigSet(USB0_BASE, ULPI_CFG_FS);
                }
            }
            else
            {
                USBULPIDisable(USB0_BASE);
            }
    
            //
            // Force device mode if requested.
            //
            if(g_iUSBMode == eUSBModeForceDevice)
            {
                MAP_USBDevMode(USB0_BASE);
            }
            else if(g_iUSBMode == eUSBModeDevice)
            {
                //
                // To run in active device mode the OTG signals must be active.
                // This allows disconnect to be detected by the controller.
                //
                MAP_USBOTGMode(USB0_BASE);
            }
    
            //
            // In all other cases, set the mode to device this function should not
            // be called in OTG mode.
            //
            g_iUSBMode = eUSBModeDevice;
    
            //
            // Enable or disable LPM functionality.
            //
            if(g_psDCDInst[0].ui32Features & USBLIB_FEATURE_LPM_EN)
            {
                //
                // Enable full LPM support and all LPM related interrupts.
                // USB_INTLPM_ERROR is not enabled since there is no response to
                // this interrupt.
                //
                USBDevLPMConfig(USB0_BASE, USB_DEV_LPM_EN);
                USBLPMIntEnable(USB0_BASE, USB_INTLPM_RESUME | USB_INTLPM_ERROR |
                                           USB_INTLPM_ACK | USB_INTLPM_NYET);
                USBDevLPMEnable(USB0_BASE);
    
                //
                // Awake by default.
                //
                g_psDCDInst[0].ui32LPMState = USBLIB_LPM_STATE_AWAKE;
            }
            else
            {
                USBDevLPMDisable(USB0_BASE);
                USBDevLPMConfig(USB0_BASE, USB_DEV_LPM_NONE);
                g_psDCDInst[0].ui32LPMState = USBLIB_LPM_STATE_DISABLED;
            }
        }
    
        //
        // Initialize the USB DMA interface.
        //
        g_psDCDInst[0].psDMAInstance = USBLibDMAInit(0);
    
        //
        // Initialize the USB tick module.
        //
        InternalUSBTickInit();
    
        //
        // Get a pointer to the default configuration descriptor.
        //
        psHdr = psDevice->ppsConfigDescriptors[
                                    g_psDCDInst[0].ui32DefaultConfiguration - 1];
        psDesc = (const tConfigDescriptor *)(psHdr->psSections[0]->pui8Data);
    
        if((psDesc->bmAttributes & USB_CONF_ATTR_PWR_M) == USB_CONF_ATTR_SELF_PWR)
        {
            g_psDCDInst[0].ui8Status |= USB_STATUS_SELF_PWR;
        }
        else
        {
            g_psDCDInst[0].ui8Status &= ~USB_STATUS_SELF_PWR;
        }
    
        //
        // Only do hardware update if the stack is not in OTG mode.
        //
        if(g_iUSBMode != eUSBModeOTG)
        {
            //
            // Get the current interrupt status.to clear all pending USB
            // interrupts.
            //
            MAP_USBIntStatusControl(USB0_BASE);
            MAP_USBIntStatusEndpoint(USB0_BASE);
    
            //
            // Enable USB Interrupts.
            //
            MAP_USBIntEnableControl(USB0_BASE, USB_INTCTRL_RESET |
                                               USB_INTCTRL_DISCONNECT |
                                               USB_INTCTRL_RESUME |
                                               USB_INTCTRL_SUSPEND |
                                               USB_INTCTRL_SOF);
            MAP_USBIntEnableEndpoint(USB0_BASE, USB_INTEP_ALL);
    
            //
            // Attach the device using the soft connect.
            //
            MAP_USBDevConnect(USB0_BASE);
    
            //
            // Enable the USB interrupt.
            //
            OS_INT_ENABLE(g_psDCDInst[0].ui32IntNum);
        }
    }
    
    //*****************************************************************************
    //
    //! Free the USB library device control driver for a given hardware controller.
    //!
    //! \param ui32Index is the index of the USB controller which is to be
    //! freed.
    //!
    //! This function should be called by an application if it no longer requires
    //! the use of a given USB controller to support its operation as a USB device.
    //! It frees the controller for use by another client.
    //!
    //! It is the caller's responsibility to remove its device from the USB bus
    //! prior to calling this function.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDTerm(uint32_t ui32Index)
    {
        //
        // Check the arguments.
        //
        ASSERT(ui32Index == 0);
    
        //
        // Disable the USB interrupts.
        //
        OS_INT_DISABLE(g_psDCDInst[0].ui32IntNum);
    
        //
        // Reset the tick handlers so that they can be reconfigured when and if
        // USBDCDInit() is called.
        //
        InternalUSBTickReset();
    
        //
        // No active device.
        //
        g_ppsDevInfo[0] = 0;
    
        MAP_USBIntDisableControl(USB0_BASE, USB_INTCTRL_ALL);
        MAP_USBIntDisableEndpoint(USB0_BASE, USB_INTEP_ALL);
    
        //
        // Detach the device using the soft connect.
        //
        MAP_USBDevDisconnect(USB0_BASE);
    
        //
        // Clear any pending interrupts.
        //
        MAP_USBIntStatusControl(USB0_BASE);
        MAP_USBIntStatusEndpoint(USB0_BASE);
    
        //
        // Turn off USB Phy clock.
        //
        MAP_SysCtlUSBPLLDisable();
    
        //
        // Disable the USB peripheral
        //
        MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_USB0);
    }
    
    //*****************************************************************************
    //
    //! This function starts the request for data from the host on endpoint zero.
    //!
    //! \param ui32Index is the index of the USB controller from which the data
    //! is being requested.
    //! \param pui8Data is a pointer to the buffer to fill with data from the USB
    //! host.
    //! \param ui32Size is the size of the buffer or data to return from the USB
    //! host.
    //!
    //! This function handles retrieving data from the host when a custom command
    //! has been issued on endpoint zero.  If the application needs notification
    //! when the data has been received,
    //! <tt>psCallbacks->pfnDataReceived()</tt> in the tDeviceInfo structure
    //! must contain valid function pointer.  In nearly all cases this is necessary
    //! because the caller of this function would likely need to know that the data
    //! requested was received.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDRequestDataEP0(uint32_t ui32Index, uint8_t *pui8Data, uint32_t ui32Size)
    {
        ASSERT(ui32Index == 0);
    
        //
        // Enter the RX state on end point 0.
        //
        g_psDCDInst[0].iEP0State = eUSBStateRx;
    
        //
        // Save the pointer to the data.
        //
        g_psDCDInst[0].pui8EP0Data = pui8Data;
    
        //
        // Location to save the current number of bytes received.
        //
        g_psDCDInst[0].ui32OUTDataSize = ui32Size;
    
        //
        // Bytes remaining to be received.
        //
        g_psDCDInst[0].ui32EP0DataRemain = ui32Size;
    }
    
    //*****************************************************************************
    //
    //! This function requests transfer of data to the host on endpoint zero.
    //!
    //! \param ui32Index is the index of the USB controller which is to be used to
    //! send the data.
    //! \param pui8Data is a pointer to the buffer to send via endpoint zero.
    //! \param ui32Size is the amount of data to send in bytes.
    //!
    //! This function handles sending data to the host when a custom command is
    //! issued or non-standard descriptor has been requested on endpoint zero.  If
    //! the application needs notification when this is complete,
    //! <tt>psCallbacks->pfnDataSent</tt> in the tDeviceInfo structure must
    //! contain a valid function pointer.  This callback could be used to free up
    //! the buffer passed into this function in the \e pui8Data parameter.  The
    //! contents of the \e pui8Data buffer must remain unchanged until the
    //! <tt>pfnDataSent</tt> callback is received.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDSendDataEP0(uint32_t ui32Index, uint8_t *pui8Data, uint32_t ui32Size)
    {
        ASSERT(ui32Index == 0);
    
        //
        // Return the externally provided device descriptor.
        //
        g_psDCDInst[0].pui8EP0Data = pui8Data;
    
        //
        // The size of the device descriptor is in the first byte.
        //
        g_psDCDInst[0].ui32EP0DataRemain = ui32Size;
    
        //
        // Save the total size of the data sent.
        //
        g_psDCDInst[0].ui32OUTDataSize = ui32Size;
    
        //
        // Now in the transmit data state.
        //
        USBDEP0StateTx(0);
    }
    
    //*****************************************************************************
    //
    //! This function sets the default configuration for the device.
    //!
    //! \param ui32Index is the index of the USB controller whose default
    //! configuration is to be set.
    //! \param ui32DefaultConfig is the configuration identifier (byte 6 of the
    //! standard configuration descriptor) which is to be presented to the host
    //! as the default configuration in cases where the configuration descriptor is
    //! queried prior to any specific configuration being set.
    //!
    //! This function allows a device to override the default configuration
    //! descriptor that will be returned to a host whenever it is queried prior
    //! to a specific configuration having been set.  The parameter passed must
    //! equal one of the configuration identifiers found in the
    //! <tt>ppsConfigDescriptors</tt> array for the device.
    //!
    //! If this function is not called, the USB library will return the first
    //! configuration in the <tt>ppsConfigDescriptors</tt> array as the default
    //! configuration.
    //!
    //! \note The USB device stack assumes that the configuration IDs (byte 6 of
    //! the configuration descriptor, <tt>bConfigurationValue</tt>) stored within
    //! the configuration descriptor array, <tt>ppsConfigDescriptors</tt>,
    //! are equal to the array index + 1.  In other words, the first entry in the
    //! array must contain a descriptor with <tt>bConfigurationValue</tt> 1, the
    //! second must have <tt>bConfigurationValue</tt> 2 and so on.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDSetDefaultConfiguration(uint32_t ui32Index, uint32_t ui32DefaultConfig)
    {
        ASSERT(ui32Index == 0);
    
        g_psDCDInst[0].ui32DefaultConfiguration = ui32DefaultConfig;
    }
    
    //*****************************************************************************
    //
    //! This function generates a stall condition on endpoint zero.
    //!
    //! \param ui32Index is the index of the USB controller whose endpoint zero is
    //! to be stalled.
    //!
    //! This function is typically called to signal an error condition to the host
    //! when an unsupported request is received by the device.  It should be
    //! called from within the callback itself (in interrupt context) and not
    //! deferred until later since it affects the operation of the endpoint zero
    //! state machine in the USB library.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDStallEP0(uint32_t ui32Index)
    {
        ASSERT(ui32Index == 0);
    
        //
        // Stall the endpoint in question.
        //
        MAP_USBDevEndpointStall(USB0_BASE, USB_EP_0, USB_EP_DEV_OUT);
    
        //
        // Enter the stalled state.
        //
        g_psDCDInst[0].iEP0State = eUSBStateStall;
    }
    #ifndef DEPRECATED
    
    //*****************************************************************************
    //
    //! Reports the device power status (bus- or self-powered) to the library.
    //!
    //! \param ui32Index is the index of the USB controller whose device power
    //! status is being reported.
    //! \param ui8Power indicates the current power status, either
    //! \b USB_STATUS_SELF_PWR or \b USB_STATUS_BUS_PWR.
    //!
    //! Applications which support switching between bus- or self-powered
    //! operation should call this function whenever the power source changes
    //! to indicate the current power status to the USB library.  This information
    //! is required by the library to allow correct responses to be provided when
    //! the host requests status from the device.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDPowerStatusSet(uint32_t ui32Index, uint8_t ui8Power)
    {
        //
        // Check for valid parameters.
        //
        ASSERT((ui8Power == USB_STATUS_BUS_PWR) ||
               (ui8Power == USB_STATUS_SELF_PWR));
        ASSERT(ui32Index == 0);
    
        //
        // Update the device status with the new power status flag.
        //
        g_psDCDInst[0].bPwrSrcSet = true;
        g_psDCDInst[0].ui8Status &= ~USB_STATUS_PWR_M;
        g_psDCDInst[0].ui8Status |= ui8Power;
    }
    #endif
    
    //*****************************************************************************
    //
    //! This function is used to enable/disable features of the USB library.
    //!
    //! \param ui32Index is the index of the USB controller whose device power
    //! status is being reported.
    //! \param ui32Feature indicates which feature is being changed.
    //! \param pvFeature holds the data that controls the feature request.
    //!
    //! Applications can change the support levels of some USB library features by
    //! calling this function to enable/disable certain features.  This function
    //! should normally be called before class initialization functions since the
    //! settings need to be in place before enumeration starts.  This allows the
    //! USB library to properly respond to all enumeration requests. The
    //! \e ui32Feature value is one of the \b USBLIB_FEATURE_* defines which
    //! controls the type of request being made.  The \e pvFeature is a feature
    //! specific data structure that is determined by the value passed in the
    //! \e ui32Feature parameter.
    //!
    //! \return Returns \b true if the feature was successfully changed and returns
    //! \b false if the feature was not able to be changed or is not supported.
    //
    //*****************************************************************************
    bool
    USBDCDFeatureSet(uint32_t ui32Index, uint32_t ui32Feature, void *pvFeature)
    {
        bool bRetCode;
        tLPMFeature *psLPMFeature;
    
        bRetCode = true;
    
        switch(ui32Feature)
        {
            case USBLIB_FEATURE_LPM:
            {
                //
                // Save the LPM setting.
                //
                psLPMFeature = (tLPMFeature *)pvFeature;
    
                if(psLPMFeature->ui32Features & USBLIB_FEATURE_LPM_EN)
                {
                    g_psDCDInst[0].ui32Features |= USBLIB_FEATURE_LPM_EN;
                }
                else
                {
                    g_psDCDInst[0].ui32Features &= ~USBLIB_FEATURE_LPM_EN;
                }
    
                break;
            }
            case USBLIB_FEATURE_USBPLL:
            {
                //
                // If the PLL rate is not evenly divisible by 60MHz then
                // do not set it.
                //
                if((*(uint32_t *)pvFeature % 60000000) != 0)
                {
                    bRetCode = false;
                }
                else
                {
                    //
                    // Save the new PLL rate.
                    //
                    g_ui32PLLDiv = (*(uint32_t *)pvFeature / 60000000);
                }
                break;
            }
            case USBLIB_FEATURE_USBULPI:
            {
                //
                // Save the ULPI support level.
                //
                g_ui32ULPISupport = *(uint32_t *)pvFeature;
    
                break;
            }
            case USBLIB_FEATURE_POWER:
            {
                //
                // Update the device status with the new power status flag.
                //
                g_psDCDInst[0].bPwrSrcSet = true;
                g_psDCDInst[0].ui8Status &= ~USBLIB_FEATURE_POWER_SELF;
                g_psDCDInst[0].ui8Status |= (uint8_t)(*(uint32_t *)pvFeature);
    
                break;
            }
            default:
            {
                bRetCode = false;
                break;
            }
        }
        return(bRetCode);
    }
    
    //*****************************************************************************
    //
    //! This function is used to get the features of the USB library.
    //!
    //! \param ui32Index is the index of the USB controller whose device power
    //! status is being reported.
    //! \param ui32Feature indicates which feature is being requested.
    //! \param pvFeature holds the data that will be reported for the feature
    //! request.
    //!
    //! Applications can query the support levels of some USB library features by
    //! calling this function to get values of the features.  This function
    //! should normally be called before class initialization functions since the
    //! settings need to be in place during enumeration.  This allows the
    //! USB library to properly respond to all enumeration requests. The
    //! \e ui32Feature value is one of the \b USBLIB_FEATURE_* defines which
    //! controls the type of request being made.  The \e pvFeature is a feature
    //! specific data structure that is determined by the value passed in the
    //! \e ui32Feature parameter.
    //!
    //! \return Returns \b true if the feature was requested for ULPI and returns
    //! \b false if the feature was not for ULPI interface.
    //
    //*****************************************************************************
    bool
    USBDCDFeatureGet(uint32_t ui32Index, uint32_t ui32Feature, void *pvFeature)
    {
        bool bRetCode = true;
    
        switch (ui32Feature)
        {
            case USBLIB_FEATURE_USBULPI:
            {
                //
                // Save the ULPI support level.
                //
                *(uint32_t *)pvFeature = g_ui32ULPISupport;
                
                break;
            }
            default:
            {
                 bRetCode = false;
                 break;
            }
        }
        return(bRetCode);
    }
    
    //*****************************************************************************
    //
    //! Requests an LPM remote wake up to resume communication when in an LPM sleep
    //! state.
    //!
    //! \param ui32Index is the index of the USB controller that will request
    //! a bus wake up.
    //!
    //! When the host controller puts the device into an LPM sleep state, the
    //! device can call this function to initiate LPM remote wake up signaling to
    //! the host.  If the remote wake up feature has been enabled by the host, this
    //! will cause the host to respond to the LPM remote wake request and resume
    //! normal operation.  If the host has disabled remote wake up, \b false is
    //! returned to indicate that the wake up request was not successful.
    //!
    //! \return Returns \b true if the remote wake up request has been sent or
    //!\b false if LPM remote wake up is disabled.
    //
    //*****************************************************************************
    bool
    USBDCDRemoteWakeLPM(uint32_t ui32Index)
    {
        if(USBLPMRemoteWakeEnabled(USB0_BASE))
        {
            USBDevLPMRemoteWake(USB0_BASE);
            return(true);
        }
        return(false);
    }
    
    //*****************************************************************************
    //
    //! Requests a remote wake up to resume communication when in suspended state.
    //!
    //! \param ui32Index is the index of the USB controller that will request
    //! a bus wake up.
    //!
    //! When the bus is suspended, an application which supports remote wake up
    //! (advertised to the host via the configuration descriptor) may call this
    //! function to initiate remote wake up signaling to the host.  If the remote
    //! wake up feature has not been disabled by the host, this will cause the bus
    //! to resume operation within 20mS.  If the host has disabled remote wake up,
    //! \b false will be returned to indicate that the wake up request was not
    //! successful.
    //!
    //! \return Returns \b true if the remote wake up is not disabled and the
    //! signaling was started or \b false if remote wake up is disabled or if
    //! signaling is currently ongoing following a previous call to this function.
    //
    //*****************************************************************************
    bool
    USBDCDRemoteWakeupRequest(uint32_t ui32Index)
    {
        //
        // Check for parameter validity.
        //
        ASSERT(ui32Index == 0);
    
        //
        // Is remote wake up signaling currently enabled?
        //
        if(g_psDCDInst[0].ui8Status & USB_STATUS_REMOTE_WAKE)
        {
            //
            // The host has not disabled remote wake up. Are we still in the
            // middle of a previous wake up sequence?
            //
            if(!g_psDCDInst[0].bRemoteWakeup)
            {
                //
                // No - we are not in the middle of a wake up sequence so start
                // one here.
                //
                g_psDCDInst[0].ui8RemoteWakeupCount = 0;
                g_psDCDInst[0].bRemoteWakeup = true;
                MAP_USBHostResume(USB0_BASE, true);
                return(true);
            }
        }
    
        //
        // If we drop through to here, signaling was not initiated so return
        // false.
        return(false);
    }
    
    //*****************************************************************************
    //
    // Internal Functions, not to be called by applications
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // This internal function is called on the SOF interrupt to process any
    // outstanding remote wake up requests.
    //
    // \return None.
    //
    //*****************************************************************************
    void
    USBDeviceResumeTickHandler(tDCDInstance *psDevInst)
    {
        if(g_psDCDInst[0].bRemoteWakeup)
        {
            //
            // Increment the millisecond counter we use to time the resume
            // signaling.
            //
            g_psDCDInst[0].ui8RemoteWakeupCount++;
    
            //
            // Have we reached the 10mS mark? If so, we need to turn the signaling
            // off again.
            //
            if(g_psDCDInst[0].ui8RemoteWakeupCount == REMOTE_WAKEUP_PULSE_MS)
            {
                MAP_USBHostResume(USB0_BASE, false);
            }
    
            //
            // Have we reached the point at which we can tell the client that the
            // bus has resumed? The controller does not give us an interrupt if we
            // initiated the wake up signaling so we just wait until 20mS have
            // passed then tell the client all is well.
            //
            if(g_psDCDInst[0].ui8RemoteWakeupCount == REMOTE_WAKEUP_READY_MS)
            {
                //
                // We are now finished with the remote wake up signaling.
                //
                g_psDCDInst[0].bRemoteWakeup = false;
    
                //
                // If the client has registered a resume callback, call it.  In the
                // case of a remote wake up request, we do not get a resume
                // interrupt from the controller so we need to fake it here.
                //
                if(g_ppsDevInfo[0]->psCallbacks->pfnResumeHandler)
                {
                    g_ppsDevInfo[0]->psCallbacks->pfnResumeHandler(
                                                        g_psDCDInst[0].pvCBData);
                }
            }
        }
    }
    
    //*****************************************************************************
    //
    // This internal function reads a request data packet and dispatches it to
    // either a standard request handler or the registered device request
    // callback depending upon the request type.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDReadAndDispatchRequest(uint32_t ui32Index)
    {
        uint32_t ui32Size;
        tUSBRequest *psRequest;
    
        //
        // Cast the buffer to a request structure.
        //
        psRequest = (tUSBRequest *)g_pui8DataBufferIn;
    
        //
        // Set the buffer size.
        //
        ui32Size = EP0_MAX_PACKET_SIZE;
    
        //
        // Get the data from the USB controller end point 0.
        //
        MAP_USBEndpointDataGet(USB0_BASE, USB_EP_0, g_pui8DataBufferIn,
                               &ui32Size);
    
        //
        // If there was a null setup packet then just return.
        //
        if(!ui32Size)
        {
            return;
        }
    
        //
        // See if this is a standard request or not.
        //
        if((psRequest->bmRequestType & USB_RTYPE_TYPE_M) != USB_RTYPE_STANDARD)
        {
            //
            // Since this is not a standard request, see if there is
            // an external handler present.
            //
            if(g_ppsDevInfo[0]->psCallbacks->pfnRequestHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnRequestHandler(
                                                        g_psDCDInst[0].pvCBData,
                                                        psRequest);
            }
            else
            {
                //
                // If there is no handler then stall this request.
                //
                USBDCDStallEP0(0);
            }
        }
        else
        {
            //
            // Assure that the jump table is not out of bounds.
            //
            if((psRequest->bRequest <
               (sizeof(g_psUSBDStdRequests) / sizeof(tStdRequest))) &&
               (g_psUSBDStdRequests[psRequest->bRequest] != 0))
            {
                //
                // Jump table to the appropriate handler.
                //
                g_psUSBDStdRequests[psRequest->bRequest](&g_psDCDInst[0],
                                                         psRequest);
            }
            else
            {
                //
                // If there is no handler then stall this request.
                //
                USBDCDStallEP0(0);
            }
        }
    }
    
    //*****************************************************************************
    //
    // This is interrupt handler for endpoint zero.
    //
    // This function handles all interrupts on endpoint zero in order to maintain
    // the state needed for the control endpoint on endpoint zero.  In order to
    // successfully enumerate and handle all USB standard requests, all requests
    // on endpoint zero must pass through this function.  The endpoint has the
    // following states: \b eUSBStateIdle, \b eUSBStateTx, \b eUSBStateRx,
    // \b eUSBStateStall, and \b eUSBStateStatus.  In the \b eUSBStateIdle
    // state the USB controller has not received the start of a request, and once
    // it does receive the data for the request it will either enter the
    // \b eUSBStateTx, \b eUSBStateRx, or \b eUSBStateStall depending on the
    // command.  If the controller enters the \b eUSBStateTx or \b eUSBStateRx
    // then once all data has been sent or received, it must pass through the
    // \b eUSBStateStatus state to allow the host to acknowledge completion of
    // the request.  The \b eUSBStateStall is entered from \b eUSBStateIdle in
    // the event that the USB request was not valid.  Both the \b eUSBStateStall
    // and \b eUSBStateStatus are transitional states that return to the
    // \b eUSBStateIdle state.
    //
    // \return None.
    //
    // eUSBStateIdle -*--> eUSBStateTx -*-> eUSBStateStatus -*->eUSBStateIdle
    //                |                 |                    |
    //                |--> eUSBStateRx                       |
    //                |                                      |
    //                |--> eUSBStateStall ---------->--------
    //
    //  ----------------------------------------------------------------
    // | Current State       | State 0           | State 1              |
    // | --------------------|-------------------|----------------------
    // | eUSBStateIdle       | eUSBStateTx/RX    | eUSBStateStall       |
    // | eUSBStateTx         | eUSBStateStatus   |                      |
    // | eUSBStateRx         | eUSBStateStatus   |                      |
    // | eUSBStateStatus     | eUSBStateIdle     |                      |
    // | eUSBStateStall      | eUSBStateIdle     |                      |
    //  ----------------------------------------------------------------
    //
    //*****************************************************************************
    void
    USBDeviceEnumHandler(tDCDInstance *pDevInstance)
    {
        uint32_t ui32EPStatus, ui32DataSize;
    
        //
        // Get the end point 0 status.
        //
        ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, USB_EP_0);
    
        switch(pDevInstance->iEP0State)
        {
            //
            // Handle the status state, this is a transitory state from
            // eUSBStateTx or eUSBStateRx back to eUSBStateIdle.
            //
            case eUSBStateStatus:
            {
                //
                // Just go back to the idle state.
                //
                pDevInstance->iEP0State = eUSBStateIdle;
    
                //
                // If there is a pending address change then set the address.
                //
                if(pDevInstance->ui32DevAddress & DEV_ADDR_PENDING)
                {
                    //
                    // Clear the pending address change and set the address.
                    //
                    pDevInstance->ui32DevAddress &= ~DEV_ADDR_PENDING;
                    MAP_USBDevAddrSet(USB0_BASE, pDevInstance->ui32DevAddress);
                }
    
                //
                // If a new packet is already pending, we need to read it
                // and handle whatever request it contains.
                //
                if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY)
                {
                    //
                    // Process the newly arrived packet.
                    //
                    USBDReadAndDispatchRequest(0);
                }
                break;
            }
    
            //
            // In the IDLE state the code is waiting to receive data from the host.
            //
            case eUSBStateIdle:
            {
                //
                // Is there a packet waiting for us?
                //
                if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY)
                {
                    //
                    // Yes - process it.
                    //
                    USBDReadAndDispatchRequest(0);
                }
                break;
            }
    
            //
            // Data is still being sent to the host so handle this in the
            // EP0StateTx() function.
            //
            case eUSBStateTx:
            {
                USBDEP0StateTx(0);
                break;
            }
    
            //
            // We are still in the middle of sending the configuration descriptor
            // so handle this in the EP0StateTxConfig() function.
            //
            case eUSBStateTxConfig:
            {
                USBDEP0StateTxConfig(0);
                break;
            }
    
            //
            // Handle the receive state for commands that are receiving data on
            // endpoint zero.
            //
            case eUSBStateRx:
            {
                //
                // Set the number of bytes to get out of this next packet.
                //
                if(pDevInstance->ui32EP0DataRemain > EP0_MAX_PACKET_SIZE)
                {
                    //
                    // Don't send more than EP0_MAX_PACKET_SIZE bytes.
                    //
                    ui32DataSize = EP0_MAX_PACKET_SIZE;
                }
                else
                {
                    //
                    // There was space so send the remaining bytes.
                    //
                    ui32DataSize = pDevInstance->ui32EP0DataRemain;
                }
    
                //
                // Get the data from the USB controller end point 0.
                //
                MAP_USBEndpointDataGet(USB0_BASE, USB_EP_0,
                                       pDevInstance->pui8EP0Data, &ui32DataSize);
    
                //
                // If there we not more that EP0_MAX_PACKET_SIZE or more bytes
                // remaining then this transfer is complete.  If there were exactly
                // EP0_MAX_PACKET_SIZE remaining then there still needs to be
                // null packet sent before this is complete.
                //
                if(pDevInstance->ui32EP0DataRemain < EP0_MAX_PACKET_SIZE)
                {
                    //
                    // Return to the idle state.
                    //
                    pDevInstance->iEP0State =  eUSBStateStatus;
    
                    //
                    // If there is a receive callback then call it.
                    //
                    if((g_ppsDevInfo[0]->psCallbacks->pfnDataReceived) &&
                       (pDevInstance->ui32OUTDataSize != 0))
                    {
                        //
                        // Call the custom receive handler to handle the data
                        // that was received.
                        //
                        g_ppsDevInfo[0]->psCallbacks->pfnDataReceived(
                                                    g_psDCDInst[0].pvCBData,
                                                    pDevInstance->ui32OUTDataSize);
    
                        //
                        // Indicate that there is no longer any data being waited
                        // on.
                        //
                        pDevInstance->ui32OUTDataSize = 0;
                    }
    
                    //
                    // Need to ACK the data on end point 0 in this case and set the
                    // data end as this is the last of the data.
                    //
                    MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
                }
                else
                {
                    //
                    // Need to ACK the data on end point 0 in this case
                    // without setting data end because more data is coming.
                    //
                    MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
                }
    
                //
                // Advance the pointer.
                //
                pDevInstance->pui8EP0Data += ui32DataSize;
    
                //
                // Decrement the number of bytes that are being waited on.
                //
                pDevInstance->ui32EP0DataRemain -= ui32DataSize;
    
                break;
            }
            //
            // The device stalled endpoint zero so check if the stall needs to be
            // cleared once it has been successfully sent.
            //
            case eUSBStateStall:
            {
                //
                // If we sent a stall then acknowledge this interrupt.
                //
                if(ui32EPStatus & USB_DEV_EP0_SENT_STALL)
                {
                    //
                    // Clear the Setup End condition.
                    //
                    MAP_USBDevEndpointStatusClear(USB0_BASE, USB_EP_0,
                                                  USB_DEV_EP0_SENT_STALL);
    
                    //
                    // Reset the global end point 0 state to IDLE.
                    //
                    pDevInstance->iEP0State = eUSBStateIdle;
    
                }
                break;
            }
            //
            // Halt on an unknown state, but only in DEBUG mode builds.
            //
            default:
            {
                ASSERT(0);
                break;
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function handles bus reset notifications.
    //
    // This function is called from the low level USB interrupt handler whenever
    // a bus reset is detected.  It performs tidy-up as required and resets the
    // configuration back to defaults in preparation for descriptor queries from
    // the host.
    //
    // \return None.
    //
    //*****************************************************************************
    void
    USBDeviceEnumResetHandler(tDCDInstance *pDevInstance)
    {
        uint32_t ui32Loop;
    
        //
        // Disable remote wake up signaling (as per USB 2.0 spec 9.1.1.6).
        //
        pDevInstance->ui8Status &= ~USB_STATUS_REMOTE_WAKE;
        pDevInstance->bRemoteWakeup = false;
    
        //
        // Call the device dependent code to indicate a bus reset has occurred.
        //
        if(g_ppsDevInfo[0]->psCallbacks->pfnResetHandler)
        {
            g_ppsDevInfo[0]->psCallbacks->pfnResetHandler(g_psDCDInst[0].pvCBData);
        }
    
        //
        // Reset the default configuration identifier and alternate function
        // selections.
        //
        pDevInstance->ui32Configuration = pDevInstance->ui32DefaultConfiguration;
    
        for(ui32Loop = 0; ui32Loop < USB_MAX_INTERFACES_PER_DEVICE; ui32Loop++)
        {
            pDevInstance->pui8AltSetting[ui32Loop] = (uint8_t)0;
        }
    }
    
    //*****************************************************************************
    //
    // This function handles the GET_STATUS standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the request type and endpoint number if endpoint
    // status is requested.
    //
    // This function handles responses to a Get Status request from the host
    // controller.  A status request can be for the device, an interface or an
    // endpoint.  If any other type of request is made this function will cause
    // a stall condition to indicate that the command is not supported.  The
    // \e psUSBRequest structure holds the type of the request in the
    // bmRequestType field.  If the type indicates that this is a request for an
    // endpoint's status, then the wIndex field holds the endpoint number.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDGetStatus(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        uint16_t ui16Data, ui16Index;
        uint32_t ui32Dir;
        tDCDInstance *psUSBControl;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
    
        //
        // Need to ACK the data on end point 0 without setting last data as there
        // will be a data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
    
        //
        // Determine what type of status was requested.
        //
        switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
        {
            //
            // This was a Device Status request.
            //
            case USB_RTYPE_DEVICE:
            {
                //
                // Return the current status for the device.
                //
                ui16Data = (uint16_t)psUSBControl->ui8Status;
    
                break;
            }
    
            //
            // This was a Interface status request.
            //
            case USB_RTYPE_INTERFACE:
            {
                //
                // Interface status always returns 0.
                //
                ui16Data = (uint16_t)0;
    
                break;
            }
    
            //
            // This was an endpoint status request.
            //
            case USB_RTYPE_ENDPOINT:
            {
                //
                // Which endpoint are we dealing with?
                //
                ui16Index = psUSBRequest->wIndex & USB_REQ_EP_NUM_M;
    
                //
                // Check if this was a valid endpoint request.
                //
                if((ui16Index == 0) || (ui16Index >= NUM_USB_EP))
                {
                    USBDCDStallEP0(0);
                    return;
                }
                else
                {
                    //
                    // Are we dealing with an IN or OUT endpoint?
                    //
                    ui32Dir = ((psUSBRequest->wIndex & USB_REQ_EP_DIR_M) ==
                               USB_REQ_EP_DIR_IN) ? HALT_EP_IN : HALT_EP_OUT;
    
                    //
                    // Get the current halt status for this endpoint.
                    //
                    ui16Data =
                        (uint16_t)psUSBControl->ppui8Halt[ui32Dir][ui16Index - 1];
                }
                break;
            }
    
            //
            // This was an unknown request.
            //
            default:
            {
                //
                // Anything else causes a stall condition to indicate that the
                // command was not supported.
                //
                USBDCDStallEP0(0);
                return;
            }
        }
    
        //
        // Send the two byte status response.
        //
        psUSBControl->ui32EP0DataRemain = 2;
        psUSBControl->pui8EP0Data = (uint8_t *)&ui16Data;
    
        //
        // Send the response.
        //
        USBDEP0StateTx(0);
    }
    
    //*****************************************************************************
    //
    // This function handles the CLEAR_FEATURE standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the options for the Clear Feature USB request.
    //
    // This function handles device or endpoint clear feature requests.  The
    // \e psUSBRequest structure holds the type of the request in the bmRequestType
    // field and the feature is held in the wValue field.  The device can only
    // clear the Remote Wake feature.  This device request should only be made if
    // the descriptor indicates that Remote Wake is implemented by the device.
    // Endpoints can only clear a halt on a given endpoint.  If any other
    // requests are made, then the device will stall the request to indicate to
    // the host that the command was not supported.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDClearFeature(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        tDCDInstance *psUSBControl;
        uint32_t ui32Dir;
        uint16_t ui16Index;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
    
        //
        // Need to ACK the data on end point 0 with last data set as this has no
        // data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
    
        //
        // Determine what type of status was requested.
        //
        switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
        {
            //
            // This is a clear feature request at the device level.
            //
            case USB_RTYPE_DEVICE:
            {
                //
                // Only remote wake is can be cleared by this function.
                //
                if(USB_FEATURE_REMOTE_WAKE & psUSBRequest->wValue)
                {
                    //
                    // Clear the remote wake up state.
                    //
                    psUSBControl->ui8Status &= ~USB_STATUS_REMOTE_WAKE;
                }
                else
                {
                    USBDCDStallEP0(0);
                }
                break;
            }
    
            //
            // This is a clear feature request at the endpoint level.
            //
            case USB_RTYPE_ENDPOINT:
            {
                //
                // Which endpoint are we dealing with?
                //
                ui16Index = psUSBRequest->wIndex & USB_REQ_EP_NUM_M;
    
                //
                // Not a valid endpoint.
                //
                if((ui16Index == 0) || (ui16Index > NUM_USB_EP))
                {
                    USBDCDStallEP0(0);
                }
                else
                {
                    //
                    // Only the halt feature is supported.
                    //
                    if(USB_FEATURE_EP_HALT == psUSBRequest->wValue)
                    {
                        //
                        // Are we dealing with an IN or OUT endpoint?
                        //
                        ui32Dir = ((psUSBRequest->wIndex & USB_REQ_EP_DIR_M) ==
                                   USB_REQ_EP_DIR_IN) ? HALT_EP_IN : HALT_EP_OUT;
    
                        //
                        // Clear the halt condition on this endpoint.
                        //
                        psUSBControl->ppui8Halt[ui32Dir][ui16Index - 1] = 0;
    
                        if(ui32Dir == HALT_EP_IN)
                        {
                            MAP_USBDevEndpointStallClear(USB0_BASE,
                                                         IndexToUSBEP(ui16Index),
                                                         USB_EP_DEV_IN);
                        }
                        else
                        {
                            MAP_USBDevEndpointStallClear(USB0_BASE,
                                                         IndexToUSBEP(ui16Index),
                                                         USB_EP_DEV_OUT);
                        }
                    }
                    else
                    {
                        //
                        // If any other feature is requested, this is an error.
                        //
                        USBDCDStallEP0(0);
                        return;
                    }
                }
                break;
            }
    
            //
            // This is an unknown request.
            //
            default:
            {
                USBDCDStallEP0(0);
                return;
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_FEATURE standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the feature in the wValue field of the USB
    // request.
    //
    // This function handles device or endpoint set feature requests.  The
    // \e psUSBRequest structure holds the type of the request in the bmRequestType
    // field and the feature is held in the wValue field.  The device can only
    // set the Remote Wake feature.  This device request should only be made if the
    // descriptor indicates that Remote Wake is implemented by the device.
    // Endpoint requests can only issue a halt on a given endpoint.  If any other
    // requests are made, then the device will stall the request to indicate to the
    // host that the command was not supported.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetFeature(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        tDCDInstance *psUSBControl;
        uint16_t ui16Index;
        uint32_t ui32Dir;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
    
        //
        // Need to ACK the data on end point 0 with last data set as this has no
        // data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
    
        //
        // Determine what type of status was requested.
        //
        switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
        {
            //
            // This is a set feature request at the device level.
            //
            case USB_RTYPE_DEVICE:
            {
                //
                // Only remote wake is the only feature that can be set by this
                // function.
                //
                if(USB_FEATURE_REMOTE_WAKE & psUSBRequest->wValue)
                {
                    //
                    // Set the remote wake up state.
                    //
                    psUSBControl->ui8Status |= USB_STATUS_REMOTE_WAKE;
                }
                else
                {
                    USBDCDStallEP0(0);
                }
                break;
            }
    
            //
            // This is a set feature request at the endpoint level.
            //
            case USB_RTYPE_ENDPOINT:
            {
                //
                // Which endpoint are we dealing with?
                //
                ui16Index = psUSBRequest->wIndex & USB_REQ_EP_NUM_M;
    
                //
                // Not a valid endpoint?
                //
                if((ui16Index == 0) || (ui16Index >= NUM_USB_EP))
                {
                    USBDCDStallEP0(0);
                }
                else
                {
                    //
                    // Only the Halt feature can be set.
                    //
                    if(USB_FEATURE_EP_HALT == psUSBRequest->wValue)
                    {
                        //
                        // Are we dealing with an IN or OUT endpoint?
                        //
                        ui32Dir = ((psUSBRequest->wIndex & USB_REQ_EP_DIR_M) ==
                                   USB_REQ_EP_DIR_IN) ? HALT_EP_IN : HALT_EP_OUT;
    
                        //
                        // Clear the halt condition on this endpoint.
                        //
                        psUSBControl->ppui8Halt[ui32Dir][ui16Index - 1] = 1;
                    }
                    else
                    {
                        //
                        // No other requests are supported.
                        //
                        USBDCDStallEP0(0);
                        return;
                    }
                }
                break;
            }
    
            //
            // This is an unknown request.
            //
            default:
            {
                USBDCDStallEP0(0);
                return;
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_ADDRESS standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the new address to use in the wValue field of the
    // USB request.
    //
    // This function is called to handle the change of address request from the
    // host controller.  This can only start the sequence as the host must
    // acknowledge that the device has changed address.  Thus this function sets
    // the address change as pending until the status phase of the request has
    // been completed successfully.  This prevents the devices address from
    // changing and not properly responding to the status phase.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetAddress(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        tDCDInstance *psUSBControl;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
    
        //
        // Need to ACK the data on end point 0 with last data set as this has no
        // data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
    
        //
        // Save the device address as we cannot change address until the status
        // phase is complete.
        //
        psUSBControl->ui32DevAddress = psUSBRequest->wValue | DEV_ADDR_PENDING;
    
        //
        // Transition directly to the status state since there is no data phase
        // for this request.
        //
        psUSBControl->iEP0State = eUSBStateStatus;
    }
    
    //*****************************************************************************
    //
    // This function handles the GET_DESCRIPTOR standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This function will return most of the descriptors requested by the host
    // controller.  The descriptor specified by \e
    // pvInstance->psInfo->pui8DeviceDescriptor will be returned when the device
    // descriptor is requested.  If a request for a specific configuration
    // descriptor is made, then the appropriate descriptor from the \e
    // g_pConfigDescriptors will be returned.  When a request for a string
    // descriptor is made, the appropriate string from the
    // \e pvInstance->psInfo->pStringDescriptors will be returned.  If the
    // \e pvInstance->psInfo->psCallbacks->GetDescriptor is specified it will be
    // called to handle the request.  In this case it must call the
    // USBDCDSendDataEP0() function to send the data to the host controller.  If
    // the callback is not specified, and the descriptor request is not for a
    // device, configuration, or string descriptor then this function will stall
    // the request to indicate that the request was not supported by the device.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDGetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        bool bConfig;
        tDCDInstance *psUSBControl;
        tDeviceInfo *psDevice;
        const tConfigHeader *psConfig;
        const tDeviceDescriptor *psDeviceDesc;
        uint8_t ui8Index;
        int32_t i32Index;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
        psDevice = g_ppsDevInfo[0];
    
        //
        // Need to ACK the data on end point 0 without setting last data as there
        // will be a data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
    
        //
        // Assume we are not sending the configuration descriptor until we
        // determine otherwise.
        //
        bConfig = false;
    
        //
        // Which descriptor are we being asked for?
        //
        switch(psUSBRequest->wValue >> 8)
        {
            //
            // This request was for a device descriptor.
            //
            case USB_DTYPE_DEVICE:
            {
                //
                // Return the externally provided device descriptor.
                //
                psUSBControl->pui8EP0Data =
                                        (uint8_t *)psDevice->pui8DeviceDescriptor;
    
                //
                // The size of the device descriptor is in the first byte.
                //
                psUSBControl->ui32EP0DataRemain =
                    psDevice->pui8DeviceDescriptor[0];
    
                break;
            }
    
            //
            // This request was for a configuration descriptor.
            //
            case USB_DTYPE_CONFIGURATION:
            {
                //
                // Which configuration are we being asked for?
                //
                ui8Index = (uint8_t)(psUSBRequest->wValue & 0xFF);
    
                //
                // Is this valid?
                //
                psDeviceDesc =
                    (const tDeviceDescriptor *)psDevice->pui8DeviceDescriptor;
    
                if(ui8Index >= psDeviceDesc->bNumConfigurations)
                {
                    //
                    // This is an invalid configuration index.  Stall EP0 to
                    // indicate a request error.
                    //
                    USBDCDStallEP0(0);
                    psUSBControl->pui8EP0Data = 0;
                    psUSBControl->ui32EP0DataRemain = 0;
                }
                else
                {
                    //
                    // Return the externally specified configuration descriptor.
                    //
                    psConfig = psDevice->ppsConfigDescriptors[ui8Index];
    
                    //
                    // Start by sending data from the beginning of the first
                    // descriptor.
                    //
                    psUSBControl->ui8ConfigSection = 0;
                    psUSBControl->ui16SectionOffset = 0;
                    psUSBControl->pui8EP0Data =
                                    (uint8_t *)psConfig->psSections[0]->pui8Data;
    
                    //
                    // Determine the total size of the configuration descriptor
                    // by counting the sizes of the sections comprising it.
                    //
                    psUSBControl->ui32EP0DataRemain =
                                                USBDCDConfigDescGetSize(psConfig);
    
                    //
                    // Remember that we need to send the configuration descriptor
                    // and which descriptor we need to send.
                    //
                    psUSBControl->ui8ConfigIndex = ui8Index;
    
                    bConfig = true;
                }
                break;
            }
    
            //
            // This request was for a string descriptor.
            //
            case USB_DTYPE_STRING:
            {
                //
                // Determine the correct descriptor index based on the requested
                // language ID and index.
                //
                i32Index = USBDStringIndexFromRequest(psUSBRequest->wIndex,
                                                      psUSBRequest->wValue & 0xFF);
    
                //
                // If the mapping function returned -1 then stall the request to
                // indicate that the request was not valid.
                //
                if(i32Index == -1)
                {
                    USBDCDStallEP0(0);
                    break;
                }
    
                //
                // Return the externally specified configuration descriptor.
                //
                psUSBControl->pui8EP0Data =
                    (uint8_t *)psDevice->ppui8StringDescriptors[i32Index];
    
                //
                // The total size of a string descriptor is in byte 0.
                //
                psUSBControl->ui32EP0DataRemain =
                    psDevice->ppui8StringDescriptors[i32Index][0];
    
                break;
            }
    
            //
            // Any other request is not handled by the default enumeration handler
            // so see if it needs to be passed on to another handler.
            //
            default:
            {
                //
                // If there is a handler for requests that are not handled then
                // call it.
                //
                if(psDevice->psCallbacks->pfnGetDescriptor)
                {
                    psDevice->psCallbacks->pfnGetDescriptor(g_psDCDInst[0].pvCBData,
                                                          psUSBRequest);
                }
                else
                {
                    //
                    // Whatever this was this handler does not understand it so
                    // just stall the request.
                    //
                    USBDCDStallEP0(0);
                }
    
                return;
            }
        }
    
        //
        // If this request has data to send, then send it.
        //
        if(psUSBControl->pui8EP0Data)
        {
            //
            // If there is more data to send than is requested then just
            // send the requested amount of data.
            //
            if(psUSBControl->ui32EP0DataRemain > psUSBRequest->wLength)
            {
                psUSBControl->ui32EP0DataRemain = psUSBRequest->wLength;
            }
    
            //
            // Now in the transmit data state.  Be careful to call the correct
            // function since we need to handle the configuration descriptor
            // differently from the others.
            //
            if(!bConfig)
            {
                USBDEP0StateTx(0);
            }
            else
            {
                USBDEP0StateTxConfig(0);
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function determines which string descriptor to send to satisfy a
    // request for a given index and language.
    //
    // \param ui16Lang is the requested string language ID.
    // \param ui16Index is the requested string descriptor index.
    //
    // When a string descriptor is requested, the host provides a language ID and
    // index to identify the string ("give me string number 5 in French").  This
    // function maps these two parameters to an index within our device's string
    // descriptor array which is arranged as multiple groups of strings with
    // one group for each language advertised via string descriptor 0.
    //
    // We assume that there are an equal number of strings per language and
    // that the first descriptor is the language descriptor and use this fact to
    // perform the mapping.
    //
    // \return The index of the string descriptor to return or -1 if the string
    // could not be found.
    //
    //*****************************************************************************
    static int32_t
    USBDStringIndexFromRequest(uint16_t ui16Lang, uint16_t ui16Index)
    {
        tString0Descriptor *pLang;
        uint32_t ui32NumLangs, ui32NumStringi16PerLang, ui32Loop;
    
        //
        // Make sure we have a string table at all.
        //
        if((g_ppsDevInfo[0] == 0) ||
           (g_ppsDevInfo[0]->ppui8StringDescriptors == 0))
        {
            return(-1);
        }
    
        //
        // First look for the trivial case where descriptor 0 is being
        // requested.  This is the special case since descriptor 0 contains the
        // language codes supported by the device.
        //
        if(ui16Index == 0)
        {
            return(0);
        }
    
        //
        // How many languages does this device support?  This is determined by
        // looking at the length of the first descriptor in the string table,
        // subtracting 2 for the header and dividing by two (the size of each
        // language code).
        //
        ui32NumLangs =
                (g_ppsDevInfo[0]->ppui8StringDescriptors[0][0] - 2) / 2;
    
        //
        // We assume that the table includes the same number of strings for each
        // supported language.  We know the number of entries in the string table,
        // so how many are there for each language?  This may seem an odd way to
        // do this (why not just have the application tell us in the device info
        // structure?) but it's needed since we didn't want to change the API
        // after the first release which did not support multiple languages.
        //
        ui32NumStringi16PerLang =
            ((g_ppsDevInfo[0]->ui32NumStringDescriptors - 1) /ui32NumLangs);
    
        //
        // Just to be sure, make sure that the calculation indicates an equal
        // number of strings per language.  We expect the string table to contain
        // (1 + (strings_per_language * languages)) entries.
        //
        if((1 + (ui32NumStringi16PerLang * ui32NumLangs)) !=
                g_ppsDevInfo[0]->ui32NumStringDescriptors)
        {
            return(-1);
        }
    
        //
        // Now determine which language we are looking for.  It is assumed that
        // the order of the groups of strings per language in the table is the
        // same as the order of the language IDs listed in the first descriptor.
        //
        pLang = (tString0Descriptor *)
                            (g_ppsDevInfo[0]->ppui8StringDescriptors[0]);
    
        //
        // Look through the supported languages looking for the one we were asked
        // for.
        //
        for(ui32Loop = 0; ui32Loop < ui32NumLangs; ui32Loop++)
        {
            //
            // Have we found the requested language?
            //
            if(pLang->wLANGID[ui32Loop] == ui16Lang)
            {
                //
                // Yes - calculate the index of the descriptor to send.
                //
                return((ui32NumStringi16PerLang * ui32Loop) + ui16Index);
            }
        }
    
        //
        // If we drop out of the loop, the requested language was not found so
        // return -1 to indicate the error.
        //
        return(-1);
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_DESCRIPTOR standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This function currently is not supported and will respond with a Stall
    // to indicate that this command is not supported by the device.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        //
        // Need to ACK the data on end point 0 without setting last data as there
        // will be a data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
    
        //
        // This function is not handled by default.
        //
        USBDCDStallEP0(0);
    }
    
    //*****************************************************************************
    //
    // This function handles the GET_CONFIGURATION standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This function responds to a host request to return the current
    // configuration of the USB device.  The function will send the configuration
    // response to the host and return.  This value will either be 0 or the last
    // value received from a call to SetConfiguration().
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDGetConfiguration(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        uint8_t ui8Value;
        tDCDInstance *psUSBControl;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
    
        //
        // Need to ACK the data on end point 0 without setting last data as there
        // will be a data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
    
        //
        // If we still have an address pending then the device is still not
        // configured.
        //
        if(psUSBControl->ui32DevAddress & DEV_ADDR_PENDING)
        {
            ui8Value = 0;
        }
        else
        {
            ui8Value = (uint8_t)psUSBControl->ui32Configuration;
        }
    
        psUSBControl->ui32EP0DataRemain = 1;
        psUSBControl->pui8EP0Data = &ui8Value;
    
        //
        // Send the single byte response.
        //
        USBDEP0StateTx(0);
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_CONFIGURATION standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This function responds to a host request to change the current
    // configuration of the USB device.  The actual configuration number is taken
    // from the structure passed in via \e psUSBRequest.  This number should be one
    // of the configurations that was specified in the descriptors.  If the
    // \e ConfigChange callback is specified in \e pvInstance->psInfo->psCallbacks->
    // it will be called so that the application can respond to a change in
    // configuration.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetConfiguration(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        tDCDInstance *psUSBControl;
        tDeviceInfo *psDevice;
        const tConfigHeader *psHdr;
        const tConfigDescriptor *psDesc;
    
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
        psDevice = g_ppsDevInfo[0];
    
        //
        // Need to ACK the data on end point 0 with last data set as this has no
        // data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
    
        //
        // Cannot set the configuration to one that does not exist so check the
        // enumeration structure to see how many valid configurations are present.
        //
        if(psUSBRequest->wValue > psDevice->pui8DeviceDescriptor[17])
        {
            //
            // The passed configuration number is not valid.  Stall the endpoint to
            // signal the error to the host.
            //
            USBDCDStallEP0(0);
        }
        else
        {
            //
            // Save the configuration.
            //
            psUSBControl->ui32Configuration = psUSBRequest->wValue;
    
            //
            // If passed a configuration other than 0 (which tells us that we are
            // not currently configured), configure the endpoints (other than EP0)
            // appropriately.
            //
            if(psUSBControl->ui32Configuration)
            {
                //
                // Get a pointer to the configuration descriptor.  This will always
                // be the first section in the current configuration.
                //
                psHdr = psDevice->ppsConfigDescriptors[psUSBRequest->wValue - 1];
                psDesc =
                    (const tConfigDescriptor *)(psHdr->psSections[0]->pui8Data);
    
                //
                // Remember the new self- or bus-powered state if the user has not
                // already called us to tell us the state to report.
                //
                if(!psUSBControl->bPwrSrcSet)
                {
                    if((psDesc->bmAttributes & USB_CONF_ATTR_PWR_M) ==
                        USB_CONF_ATTR_SELF_PWR)
                    {
                        psUSBControl->ui8Status |= USB_STATUS_SELF_PWR;
                    }
                    else
                    {
                        psUSBControl->ui8Status &= ~USB_STATUS_SELF_PWR;
                    }
                }
    
                //
                // Configure endpoints for the new configuration.
                //
                USBDeviceConfig(psUSBControl,
                        psDevice->ppsConfigDescriptors[psUSBRequest->wValue - 1]);
            }
    
            //
            // If there is a configuration change callback then call it.
            //
            if(psDevice->psCallbacks->pfnConfigChange)
            {
                psDevice->psCallbacks->pfnConfigChange(g_psDCDInst[0].pvCBData,
                                                psUSBControl->ui32Configuration);
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function handles the GET_INTERFACE standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This function is called when the host controller request the current
    // interface that is in use by the device.  This simply returns the value set
    // by the last call to SetInterface().
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDGetInterface(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        uint8_t ui8Value;
        tDCDInstance *psUSBControl;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
    
        //
        // Need to ACK the data on end point 0 without setting last data as there
        // will be a data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
    
        //
        // If we still have an address pending then the device is still not
        // configured.
        //
        if(psUSBControl->ui32DevAddress & DEV_ADDR_PENDING)
        {
            ui8Value = (uint8_t)0;
        }
        else
        {
            //
            // Is the interface number valid?
            //
            if(psUSBRequest->wIndex < USB_MAX_INTERFACES_PER_DEVICE)
            {
                //
                // Read the current alternate setting for the required interface.
                //
                ui8Value = psUSBControl->pui8AltSetting[psUSBRequest->wIndex];
            }
            else
            {
                //
                // An invalid interface number was specified.
                //
                USBDCDStallEP0(0);
                return;
            }
        }
    
        //
        // Send the single byte response.
        //
        psUSBControl->ui32EP0DataRemain = 1;
        psUSBControl->pui8EP0Data = &ui8Value;
    
        //
        // Send the single byte response.
        //
        USBDEP0StateTx(0);
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_INTERFACE standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This function is called when a standard request for changing the interface
    // is received from the host controller.  If this is a valid request the
    // function will call the function specified by the InterfaceChange in the
    // \e pvInstance->psInfo->psCallbacks->variable to notify the application that
    // the interface has changed and will pass it the new alternate interface
    // number.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetInterface(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        const tConfigHeader *psConfig;
        tInterfaceDescriptor *psInterface;
        uint32_t ui32Loop, ui32Section, ui32NumInterfaces;
        uint8_t ui8Interface;
        bool bRetcode;
        tDCDInstance *psUSBControl;
        tDeviceInfo *psDevice;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
        psDevice = g_ppsDevInfo[0];
    
        //
        // Need to ACK the data on end point 0 with last data set as this has no
        // data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
    
        //
        // Use the current configuration.
        //
        psConfig =
            psDevice->ppsConfigDescriptors[psUSBControl->ui32Configuration - 1];
    
        //
        // How many interfaces are included in the descriptor?
        //
        ui32NumInterfaces = USBDCDConfigDescGetNum(psConfig, USB_DTYPE_INTERFACE);
    
        //
        // Find the interface descriptor for the supplied interface and alternate
        // setting numbers.
        //
        for(ui32Loop = 0; ui32Loop < ui32NumInterfaces; ui32Loop++)
        {
            //
            // Get the next interface descriptor in the configuration descriptor.
            //
            psInterface = USBDCDConfigGetInterface(psConfig, ui32Loop,
                                                   USB_DESC_ANY, &ui32Section);
    
            //
            // Is this the required interface with the correct alternate setting?
            //
            if(psInterface &&
               (psInterface->bInterfaceNumber == psUSBRequest->wIndex) &&
               (psInterface->bAlternateSetting == psUSBRequest->wValue))
            {
                ui8Interface = psInterface->bInterfaceNumber;
    
                //
                // Make sure we don't write outside the bounds of the
                // pui8AltSetting array (in a debug build, anyway, since this
                // indicates an error in the device descriptor).
                //
                ASSERT(ui8Interface < USB_MAX_INTERFACES_PER_DEVICE);
    
                //
                // This is the correct interface descriptor so save the
                // setting.
                //
                psUSBControl->pui8AltSetting[ui8Interface] =
                                                psInterface->bAlternateSetting;
    
                //
                // Reconfigure the endpoints to match the requirements of the
                // new alternate setting for the interface.
                //
                bRetcode = USBDeviceConfigAlternate(psUSBControl, psConfig,
                                                ui8Interface,
                                                psInterface->bAlternateSetting);
    
                //
                // If there is a callback then notify the application of the
                // change to the alternate interface.
                //
                if(bRetcode && psDevice->psCallbacks->pfnInterfaceChange)
                {
                    psDevice->psCallbacks->pfnInterfaceChange(
                                                    g_psDCDInst[0].pvCBData,
                                                    psUSBRequest->wIndex,
                                                    psUSBRequest->wValue);
                }
    
                //
                // All done.
                //
                return;
            }
        }
    
        //
        // If we drop out of the loop, we didn't find an interface descriptor
        // matching the requested number and alternate setting or there was an
        // error while trying to set up for the new alternate setting.
        //
        USBDCDStallEP0(0);
    }
    
    //*****************************************************************************
    //
    // This function handles the SYNC_FRAME standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This is currently a stub function that will stall indicating that the
    // command is not supported.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSyncFrame(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        //
        // Need to ACK the data on end point 0 with last data set as this has no
        // data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
    
        //
        // Not handled yet so stall this request.
        //
        USBDCDStallEP0(0);
    }
    
    //*****************************************************************************
    //
    // This internal function handles sending data on endpoint zero.
    //
    // \param ui32Index is the index of the USB controller which is to be
    // initialized.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDEP0StateTx(uint32_t ui32Index)
    {
        uint32_t ui32NumBytes;
        uint8_t *pui8Data;
    
        ASSERT(ui32Index == 0);
    
        //
        // In the TX state on endpoint zero.
        //
        g_psDCDInst[0].iEP0State = eUSBStateTx;
    
        //
        // Set the number of bytes to send this iteration.
        //
        ui32NumBytes = g_psDCDInst[0].ui32EP0DataRemain;
    
        //
        // Limit individual transfers to 64 bytes.
        //
        if(ui32NumBytes > EP0_MAX_PACKET_SIZE)
        {
            ui32NumBytes = EP0_MAX_PACKET_SIZE;
        }
    
        //
        // Save the pointer so that it can be passed to the USBEndpointDataPut()
        // function.
        //
        pui8Data = (uint8_t *)g_psDCDInst[0].pui8EP0Data;
    
        //
        // Advance the data pointer and counter to the next data to be sent.
        //
        g_psDCDInst[0].ui32EP0DataRemain -= ui32NumBytes;
        g_psDCDInst[0].pui8EP0Data += ui32NumBytes;
    
        //
        // Put the data in the correct FIFO.
        //
        MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, pui8Data, ui32NumBytes);
    
        //
        // If this is exactly 64 then don't set the last packet yet.
        //
        if(ui32NumBytes == EP0_MAX_PACKET_SIZE)
        {
            //
            // There is more data to send or exactly 64 bytes were sent, this
            // means that there is either more data coming or a null packet needs
            // to be sent to complete the transaction.
            //
            MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_IN);
        }
        else
        {
            //
            // Now go to the status state and wait for the transmit to complete.
            //
            g_psDCDInst[0].iEP0State = eUSBStateStatus;
    
            //
            // Send the last bit of data.
            //
            MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_IN_LAST);
    
            //
            // If there is a sent callback then call it.
            //
            if((g_ppsDevInfo[0]->psCallbacks->pfnDataSent) &&
               (g_psDCDInst[0].ui32OUTDataSize != 0))
            {
                //
                // Call the custom handler.
                //
                g_ppsDevInfo[0]->psCallbacks->pfnDataSent(
                                                g_psDCDInst[0].pvCBData,
                                                g_psDCDInst[0].ui32OUTDataSize);
    
                //
                // There is no longer any data pending to be sent.
                //
                g_psDCDInst[0].ui32OUTDataSize = 0;
            }
        }
    }
    
    //*****************************************************************************
    //
    // This internal function handles sending the configuration descriptor on
    // endpoint zero.
    //
    // \param ui32Index is the index of the USB controller.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDEP0StateTxConfig(uint32_t ui32Index)
    {
        uint32_t ui32NumBytes, ui32SecBytes, ui32ToSend;
        uint8_t *pui8Data;
        tConfigDescriptor sConfDesc;
        const tConfigHeader *psConfig;
        const tConfigSection *psSection;
    
        ASSERT(ui32Index == 0);
    
        //
        // In the TX state on endpoint zero.
        //
        g_psDCDInst[0].iEP0State = eUSBStateTxConfig;
    
        //
        // Find the current configuration descriptor definition.
        //
        psConfig = g_ppsDevInfo[0]->ppsConfigDescriptors[
                                                g_psDCDInst[0].ui8ConfigIndex];
    
        //
        // Set the number of bytes to send this iteration.
        //
        ui32NumBytes = g_psDCDInst[0].ui32EP0DataRemain;
    
        //
        // Limit individual transfers to 64 bytes.
        //
        if(ui32NumBytes > EP0_MAX_PACKET_SIZE)
        {
            ui32NumBytes = EP0_MAX_PACKET_SIZE;
        }
    
        //
        // If this is the first call, we need to fix up the total length of the
        // configuration descriptor.  This has already been determined and set in
        // g_sUSBDeviceState.ui32EP0DataRemain.
        //
        if((g_psDCDInst[0].ui16SectionOffset == 0) &&
           (g_psDCDInst[0].ui8ConfigSection == 0))
        {
            //
            // Copy the USB configuration descriptor from the beginning of the
            // first section of the current configuration.
            //
            sConfDesc = *(tConfigDescriptor *)g_psDCDInst[0].pui8EP0Data;
    
            //
            // Update the total size.
            //
            sConfDesc.wTotalLength = (uint16_t)USBDCDConfigDescGetSize(psConfig);
    
            //
            // Write the descriptor to the USB FIFO.
            //
            ui32ToSend = (ui32NumBytes < sizeof(tConfigDescriptor)) ? ui32NumBytes:
                            sizeof(tConfigDescriptor);
            MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, (uint8_t *)&sConfDesc,
                                   ui32ToSend);
    
            //
            // Did we reach the end of the first section?
            //
            if(psConfig->psSections[0]->ui16Size == ui32ToSend)
            {
                //
                // Update our tracking indices to point to the start of the next
                // section.
                //
                g_psDCDInst[0].ui16SectionOffset = 0;
                g_psDCDInst[0].ui8ConfigSection = 1;
            }
            else
            {
                //
                // Note that we have sent the first few bytes of the descriptor.
                //
                g_psDCDInst[0].ui16SectionOffset = (uint8_t)ui32ToSend;
            }
    
            //
            // How many bytes do we have remaining to send on this iteration?
            //
            ui32ToSend = ui32NumBytes - ui32ToSend;
        }
        else
        {
            //
            // Set the number of bytes we still have to send on this call.
            //
            ui32ToSend = ui32NumBytes;
        }
    
        //
        // Add the relevant number of bytes to the USB FIFO
        //
        while(ui32ToSend)
        {
            //
            // Get a pointer to the current configuration section.
            //
            psSection = psConfig->psSections[g_psDCDInst[0].ui8ConfigSection];
    
            //
            // Calculate bytes are available in the current configuration section.
            //
            ui32SecBytes = (uint32_t)(psSection->ui16Size -
                                      g_psDCDInst[0].ui16SectionOffset);
    
            //
            // Save the pointer so that it can be passed to the
            // USBEndpointDataPut() function.
            //
            pui8Data = (uint8_t *)psSection->pui8Data +
                                  g_psDCDInst[0].ui16SectionOffset;
    
            //
            // Are there more bytes in this section that we still have to send?
            //
            if(ui32SecBytes > ui32ToSend)
            {
                //
                // Yes - send only the remaining bytes in the transfer.
                //
                ui32SecBytes = ui32ToSend;
            }
    
            //
            // Put the data in the correct FIFO.
            //
            MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, pui8Data, ui32SecBytes);
    
            //
            // Fix up our pointers for the next iteration.
            //
            ui32ToSend -= ui32SecBytes;
            g_psDCDInst[0].ui16SectionOffset += (uint8_t)ui32SecBytes;
    
            //
            // Have we reached the end of a section?
            //
            if(g_psDCDInst[0].ui16SectionOffset == psSection->ui16Size)
            {
                //
                // Yes - move to the next one.
                //
                g_psDCDInst[0].ui8ConfigSection++;
                g_psDCDInst[0].ui16SectionOffset = 0;
            }
        }
    
        //
        // Fix up the number of bytes remaining to be sent and the start pointer.
        //
        g_psDCDInst[0].ui32EP0DataRemain -= ui32NumBytes;
    
        //
        // If we ran out of bytes in the configuration section, bail and just
        // send out what we have.
        //
        if(psConfig->ui8NumSections <= g_psDCDInst[0].ui8ConfigSection)
        {
            g_psDCDInst[0].ui32EP0DataRemain = 0;
        }
    
        //
        // If there is no more data don't keep looking or ui8ConfigSection might
        // overrun the available space.
        //
        if(g_psDCDInst[0].ui32EP0DataRemain != 0)
        {
            pui8Data =(uint8_t *)
                psConfig->psSections[g_psDCDInst[0].ui8ConfigSection]->pui8Data;
            ui32ToSend = g_psDCDInst[0].ui16SectionOffset;
            g_psDCDInst[0].pui8EP0Data = (pui8Data + ui32ToSend);
        }
    
        //
        // If this is exactly 64 then don't set the last packet yet.
        //
        if(ui32NumBytes == EP0_MAX_PACKET_SIZE)
        {
            //
            // There is more data to send or exactly 64 bytes were sent, this
            // means that there is either more data coming or a null packet needs
            // to be sent to complete the transaction.
            //
            MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_IN);
        }
        else
        {
            //
            // Send the last bit of data.
            //
            MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_IN_LAST);
    
            //
            // If there is a sent callback then call it.
            //
            if((g_ppsDevInfo[0]->psCallbacks->pfnDataSent) &&
               (g_psDCDInst[0].ui32OUTDataSize != 0))
            {
                //
                // Call the custom handler.
                //
                g_ppsDevInfo[0]->psCallbacks->pfnDataSent(g_psDCDInst[0].pvCBData,
                                                g_psDCDInst[0].ui32OUTDataSize);
    
                //
                // There is no longer any data pending to be sent.
                //
                g_psDCDInst[0].ui32OUTDataSize = 0;
            }
    
            //
            // Now go to the status state and wait for the transmit to complete.
            //
            g_psDCDInst[0].iEP0State = eUSBStateStatus;
        }
    }
    
    //*****************************************************************************
    //
    // The internal USB device interrupt handler.
    //
    // \param ui32Index is the USB controller associated with this interrupt.
    // \param ui32Status is the current interrupt status as read via a call to
    // USBIntStatusControl().
    //
    // This function is called from either \e USB0DualModeIntHandler() or
    // \e USB0DeviceIntHandler() to process USB interrupts when in device mode.
    // This handler will branch the interrupt off to the appropriate application or
    // stack handlers depending on the current status of the USB controller.
    //
    // The two-tiered structure for the interrupt handler ensures that it is
    // possible to use the same handler code in both device and OTG modes and
    // means that host code can be excluded from applications that only require
    // support for USB device mode operation.
    //
    // \return None.
    //
    //*****************************************************************************
    void
    USBDeviceIntHandlerInternal(uint32_t ui32Index, uint32_t ui32Status)
    {
        static uint32_t ui32SOFDivide = 0;
        void *pvInstance;
        uint32_t ui32DMAIntStatus;
        uint32_t ui32LPMStatus;
        tUSBDBulkDevice *psBulkDevice;
        tBulkInstance *psInst;
    
        //
        // If device initialization has not been performed then just disconnect
        // from the USB bus and return from the handler.
        //
        if(g_ppsDevInfo[0] == 0)
        {
            MAP_USBDevDisconnect(USB0_BASE);
            return;
        }
    
        pvInstance = g_psDCDInst[0].pvCBData;
    
        //
        // Received a reset from the host.
        //
        if(ui32Status & USB_INTCTRL_RESET)
        {
            USBDeviceEnumResetHandler(&g_psDCDInst[0]);
        }
    
        //
        // Suspend was signaled on the bus.
        //
        if(ui32Status & USB_INTCTRL_SUSPEND)
        {
            //
            // Call the SuspendHandler() if it was specified.
            //
            if(g_ppsDevInfo[0]->psCallbacks->pfnSuspendHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnSuspendHandler(pvInstance);
            }
        }
    
        //
        // Resume was signaled on the bus.
        //
        if(ui32Status & USB_INTCTRL_RESUME)
        {
            //
            // Call the ResumeHandler() if it was specified.
            //
            if(g_ppsDevInfo[0]->psCallbacks->pfnResumeHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnResumeHandler(pvInstance);
            }
        }
    
        //
        // USB device was disconnected.
        //
        if(ui32Status & USB_INTCTRL_DISCONNECT)
        {
            //
            // Call the DisconnectHandler() if it was specified.
            //
            if(g_ppsDevInfo[0]->psCallbacks->pfnDisconnectHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnDisconnectHandler(pvInstance);
            }
        }
    
        //
        // Start of Frame was received.
        //
        if(ui32Status & USB_INTCTRL_SOF)
        {
            //
            // Increment the global Start of Frame counter.
            //
            g_ui32USBSOFCount++;
    
            //
            // Increment our SOF divider.
            //
            ui32SOFDivide++;
    
            //
            // Handle resume signaling if required.
            //
            USBDeviceResumeTickHandler(&g_psDCDInst[0]);
    
            //
            // Have we counted enough SOFs to allow us to call the tick function?
            //
            if(ui32SOFDivide == USB_SOF_TICK_DIVIDE)
            {
                //
                // Yes - reset the divider and call the SOF tick handler.
                //
                ui32SOFDivide = 0;
                InternalUSBStartOfFrameTick(USB_SOF_TICK_DIVIDE);
            }
        }
    
        //
        // Handle LPM interrupts.
        //
        ui32LPMStatus = USBLPMIntStatus(USB0_BASE);
    
        //
        // The host LPM resume request has been acknowledged, allow the device
        // class to handle the sleep state.
        //
        if((g_psDCDInst[0].ui32LPMState == USBLIB_LPM_STATE_SLEEP) &&
           ((ui32LPMStatus & (USB_INTLPM_ACK | USB_INTLPM_RESUME)) ==
            USB_INTLPM_RESUME))
        {
            //
            // Notify the class of the wake from LPM L1.
            //
            if(g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler(pvInstance,
                                                    USB_EVENT_LPM_RESUME,
                                                    (void *)0);
            }
    
            //
            // Now back in the awake state.
            //
            g_psDCDInst[0].ui32LPMState = USBLIB_LPM_STATE_AWAKE;
    
            //
            // Enable receiving of LPM packet.
            //
            USBDevLPMEnable(USB0_BASE);
        }
        //
        // The host LPM sleep request has been acknowledged, allow the device
        // class to handle the sleep state.
        //
        else if((g_psDCDInst[0].ui32LPMState == USBLIB_LPM_STATE_AWAKE) &&
                ((ui32LPMStatus & (USB_INTLPM_ACK | USB_INTLPM_RESUME)) ==
                 USB_INTLPM_ACK))
        {
            if(g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler(pvInstance,
                                                    USB_EVENT_LPM_SLEEP,
                                                    (void *)0);
            }
    
            //
            // Now back in the sleep state.
            //
            g_psDCDInst[0].ui32LPMState = USBLIB_LPM_STATE_SLEEP;
        }
        else if(ui32LPMStatus & USB_INTLPM_NYET)
        {
            //
            // The device has held off the sleep state because LPM
            // responses are disabled.
            //
            if(g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler(pvInstance,
                                                    USB_EVENT_LPM_ERROR,
                                                    (void *)0);
            }
        }
    
        //
        // Get the controller interrupt status.
        //
        ui32Status = MAP_USBIntStatusEndpoint(USB0_BASE);
    
        //
        // Handle end point 0 interrupts.
        //
        if(ui32Status & USB_INTEP_0)
        {
            USBDeviceEnumHandler(&g_psDCDInst[0]);
            ui32Status &= ~USB_INTEP_0;
        }
    
        //
        // Check to see if any DMA transfers are pending
        //
        ui32DMAIntStatus = USBLibDMAIntStatus(g_psDCDInst[0].psDMAInstance);
    
        if(ui32DMAIntStatus)
        {
            //
            // Handle any DMA interrupt processing.
            //
            USBLibDMAIntHandler(g_psDCDInst[0].psDMAInstance, ui32DMAIntStatus);
            UARTprintf("DMA Done1\n");
            if (ui32DMAIntStatus & 1)
            {
                //
                // Send the packet to the host if we have received all the data we
                // can expect for this packet.
                //
                psBulkDevice = (tUSBDBulkDevice *)pvInstance;
                psInst = &psBulkDevice->sPrivateData;
                psInst->ui16LastTxSize = 64;
                psInst->iBulkTxState = eBulkStateWaitData;
                MAP_USBEndpointDataSend(USB0_BASE,
                                        USB_EP_1,
                                        USB_TRANS_IN);
            }
        }
    
        //
        // Because there is no way to detect if a uDMA interrupt has occurred,
        // check for an endpoint callback and call it if it is available.
        //
        if((g_ppsDevInfo[0]->psCallbacks->pfnEndpointHandler) &&
           ((ui32Status != 0) || (ui32DMAIntStatus != 0)))
        {
            g_ppsDevInfo[0]->psCallbacks->pfnEndpointHandler(pvInstance, ui32Status);
        }
    }
    
    //*****************************************************************************
    //
    // Close the Doxygen group.
    //! @}
    //
    //*****************************************************************************
    

    If I switch to using USB_EP_DMA_MODE_1, the host always receives the NAK packet. The code is changed as follows:

    1. Set DMA flag in main function (TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\usb_dev_bulk\usb_dev_bulk.c)

    //*****************************************************************************
    //
    // usb_dev_bulk.c - Main routines for the generic bulk device example.
    //
    // Copyright (c) 2013-2020 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 2.2.0.295 of the EK-TM4C1294XL Firmware Package.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_memmap.h"
    #include "inc/hw_ints.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/usb.h"
    #include "usblib/usblib.h"
    #include "usblib/usb-ids.h"
    #include "usblib/device/usbdevice.h"
    #include "usblib/device/usbdbulk.h"
    #include "utils/uartstdio.h"
    #include "utils/ustdlib.h"
    #include "drivers/pinout.h"
    #include "usb_bulk_structs.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>USB Generic Bulk Device (usb_dev_bulk)</h1>
    //!
    //! This example provides a generic USB device offering simple bulk data
    //! transfer to and from the host.  The device uses a vendor-specific class ID
    //! and supports a single bulk IN endpoint and a single bulk OUT endpoint.
    //! Data received from the host is assumed to be ASCII text and it is
    //! echoed back with the case of all alphabetic characters swapped.
    //!
    //! Assuming you installed TivaWare in the default directory, a driver
    //! information (INF) file for use with Windows XP, Windows Vista, Windows 7,
    //! and Windows 10 can be found in C:/TivaWare_C_Series-x.x/windows_drivers.
    //! For Windows 2000, the required INF file is in
    //! C:/TivaWare_C_Series-x.x/windows_drivers/win2K.
    //!
    //! A sample Windows command-line application, usb_bulk_example, illustrating
    //! how to connect to and communicate with the bulk device is also provided.
    //! The application binary is installed as part of the ``TivaWare for C Series
    //! PC Companion Utilities'' package (SW-TM4C-USB-WIN) on the installation CD
    //! or via download from http://www.ti.com/tivaware .  Project files are
    //! included to allow the examples to be built using
    //! Microsoft Visual Studio 2008.  Source code for this application can be
    //! found in directory ti/TivaWare_C_Series-x.x/tools/usb_bulk_example.
    //
    //*****************************************************************************
    
    
    //*****************************************************************************
    //
    // The system tick rate expressed both as ticks per second and a millisecond
    // period.
    //
    //*****************************************************************************
    #define SYSTICKS_PER_SECOND 100
    #define SYSTICK_PERIOD_MS   (1000 / SYSTICKS_PER_SECOND)
    
    //*****************************************************************************
    //
    // The global system tick counter.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32SysTickCount = 0;
    
    //*****************************************************************************
    //
    // Variables tracking transmit and receive counts.
    //
    //*****************************************************************************
    volatile uint32_t g_ui32TxCount = 0;
    volatile uint32_t g_ui32RxCount = 0;
    
    //*****************************************************************************
    //
    // Flags used to pass commands from interrupt context to the main loop.
    //
    //*****************************************************************************
    #define COMMAND_PACKET_RECEIVED 0x00000001
    #define COMMAND_STATUS_UPDATE   0x00000002
    
    volatile uint32_t g_ui32Flags = 0;
    
    //*****************************************************************************
    //
    // Global flag indicating that a USB configuration has been set.
    //
    //*****************************************************************************
    static volatile bool g_bUSBConfigured = false;
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
    }
    #endif
    
    //*****************************************************************************
    //
    // Interrupt handler for the system tick counter.
    //
    //*****************************************************************************
    void
    SysTickIntHandler(void)
    {
        //
        // Update our system tick counter.
        //
        g_ui32SysTickCount++;
    }
    
    //*****************************************************************************
    //
    // Receive new data and echo it back to the host.
    //
    // \param psDevice points to the instance data for the device whose data is to
    // be processed.
    // \param pi8Data points to the newly received data in the USB receive buffer.
    // \param ui32NumBytes is the number of bytes of data available to be
    // processed.
    //
    // This function is called whenever we receive a notification that data is
    // available from the host. We read the data, byte-by-byte and swap the case
    // of any alphabetical characters found then write it back out to be
    // transmitted back to the host.
    //
    // \return Returns the number of bytes of data processed.
    //
    //*****************************************************************************
    static uint32_t
    EchoNewDataToHost(tUSBDBulkDevice *psDevice, uint8_t *pi8Data,
                      uint_fast32_t ui32NumBytes)
    {
        uint_fast32_t ui32Loop, ui32Space, ui32Count;
        uint_fast32_t ui32ReadIndex;
        uint_fast32_t ui32WriteIndex;
        tUSBRingBufObject sTxRing;
    
        //
        // Get the current buffer information to allow us to write directly to
        // the transmit buffer (we already have enough information from the
        // parameters to access the receive buffer directly).
        //
        USBBufferInfoGet(&g_sTxBuffer, &sTxRing);
    
        //
        // How much space is there in the transmit buffer?
        //
        ui32Space = USBBufferSpaceAvailable(&g_sTxBuffer);
    
        //
        // How many characters can we process this time round?
        //
        ui32Loop = (ui32Space < ui32NumBytes) ? ui32Space : ui32NumBytes;
        ui32Count = ui32Loop;
    
        //
        // Update our receive counter.
        //
        g_ui32RxCount += ui32NumBytes;
    
        //
        // Set up to process the characters by directly accessing the USB buffers.
        //
        ui32ReadIndex = (uint32_t)(pi8Data - g_pui8USBRxBuffer);
        ui32WriteIndex = sTxRing.ui32WriteIndex;
    
        while(ui32Loop)
        {
            //
            // Copy from the receive buffer to the transmit buffer converting
            // character case on the way.
            //
    
            // //
            // // Is this a lower case character?
            // //
            // if((g_pui8USBRxBuffer[ui32ReadIndex] >= 'a') &&
            //    (g_pui8USBRxBuffer[ui32ReadIndex] <= 'z'))
            // {
            //     //
            //     // Convert to upper case and write to the transmit buffer.
            //     //
            //     g_pui8USBTxBuffer[ui32WriteIndex] =
            //         (g_pui8USBRxBuffer[ui32ReadIndex] - 'a') + 'A';
            // }
            // else
            // {
            //     //
            //     // Is this an upper case character?
            //     //
            //     if((g_pui8USBRxBuffer[ui32ReadIndex] >= 'A') &&
            //        (g_pui8USBRxBuffer[ui32ReadIndex] <= 'Z'))
            //     {
            //         //
            //         // Convert to lower case and write to the transmit buffer.
            //         //
            //         g_pui8USBTxBuffer[ui32WriteIndex] =
            //             (g_pui8USBRxBuffer[ui32ReadIndex] - 'Z') + 'z';
            //     }
            //     else
            //     {
            //         //
            //         // Copy the received character to the transmit buffer.
            //         //
                    g_pui8USBTxBuffer[ui32WriteIndex] =
                        g_pui8USBRxBuffer[ui32ReadIndex];
            //     }
            // }
    
            //
            // Move to the next character taking care to adjust the pointer for
            // the buffer wrap if necessary.
            //
            ui32WriteIndex++;
            ui32WriteIndex =
                (ui32WriteIndex == BULK_BUFFER_SIZE) ? 0 : ui32WriteIndex;
    
            ui32ReadIndex++;
    
            ui32ReadIndex = ((ui32ReadIndex == BULK_BUFFER_SIZE) ?
                             0 : ui32ReadIndex);
    
            ui32Loop--;
        }
    
        //
        // We've processed the data in place so now send the processed data
        // back to the host.
        //
        USBBufferDataWritten(&g_sTxBuffer, ui32Count);
    
        //
        // We processed as much data as we can directly from the receive buffer so
        // we need to return the number of bytes to allow the lower layer to
        // update its read pointer appropriately.
        //
        return(ui32Count);
    }
    
    //*****************************************************************************
    //
    // Handles bulk driver notifications related to the transmit channel (data to
    // the USB host).
    //
    // \param pvCBData is the client-supplied callback pointer for this channel.
    // \param ulEvent identifies the event we are being notified about.
    // \param ulMsgValue is an event-specific value.
    // \param pvMsgData is an event-specific pointer.
    //
    // This function is called by the bulk driver to notify us of any events
    // related to operation of the transmit data channel (the IN channel carrying
    // data to the USB host).
    //
    // \return The return value is event-specific.
    //
    //*****************************************************************************
    uint32_t
    TxHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgValue,
              void *pvMsgData)
    {
        //UARTprintf("25\n");
        //
        // We are not required to do anything in response to any transmit event
        // in this example. All we do is update our transmit counter.
        //
        if(ui32Event == USB_EVENT_TX_COMPLETE)
        {
            //UARTprintf("26\n");
            g_ui32TxCount += ui32MsgValue;
        }
        return(0);
    }
    
    //*****************************************************************************
    //
    // Handles bulk driver notifications related to the receive channel (data from
    // the USB host).
    //
    // \param pvCBData is the client-supplied callback pointer for this channel.
    // \param ui32Event identifies the event we are being notified about.
    // \param ui32MsgValue is an event-specific value.
    // \param pvMsgData is an event-specific pointer.
    //
    // This function is called by the bulk driver to notify us of any events
    // related to operation of the receive data channel (the OUT channel carrying
    // data from the USB host).
    //
    // \return The return value is event-specific.
    //
    //*****************************************************************************
    uint32_t
    RxHandler(void *pvCBData, uint32_t ui32Event, uint32_t ui32MsgValue,
              void *pvMsgData)
    {
        //UARTprintf("21\n");
        //
        // Which event are we being sent?
        //
        switch(ui32Event)
        {
            //
            // We are connected to a host and communication is now possible.
            //
            case USB_EVENT_CONNECTED:
            {
                //UARTprintf("22\n");
                g_bUSBConfigured = true;
                g_ui32Flags |= COMMAND_STATUS_UPDATE;
    
                //
                // Flush our buffers.
                //
                USBBufferFlush(&g_sTxBuffer);
                USBBufferFlush(&g_sRxBuffer);
    
                break;
            }
    
            //
            // The host has disconnected.
            //
            case USB_EVENT_DISCONNECTED:
            {
                //UARTprintf("23\n");
                g_bUSBConfigured = false;
                g_ui32Flags |= COMMAND_STATUS_UPDATE;
                break;
            }
    
            //
            // A new packet has been received.
            //
            case USB_EVENT_RX_AVAILABLE:
            {
                //UARTprintf("24\n");
                tUSBDBulkDevice *psDevice;
    
                //
                // Get a pointer to our instance data from the callback data
                // parameter.
                //
                psDevice = (tUSBDBulkDevice *)pvCBData;
    
                //
                // Read the new packet and echo it back to the host.
                //
                return(EchoNewDataToHost(psDevice, pvMsgData, ui32MsgValue));
            }
    
            //
            // Ignore SUSPEND and RESUME for now.
            //
            case USB_EVENT_SUSPEND:
            case USB_EVENT_RESUME:
                break;
    
            //
            // Ignore all other events and return 0.
            //
            default:
                break;
        }
    
        return(0);
    }
    
    //*****************************************************************************
    //
    // This is the main application entry function.
    //
    //*****************************************************************************
    int
    main(void)
    {
        uint_fast32_t ui32TxCount;
        uint_fast32_t ui32RxCount;
        uint32_t ui32SysClock;
        uint32_t ui32PLLRate;
    
        //
        // Run from the PLL at 120 MHz.
        // Note: SYSCTL_CFG_VCO_240 is a new setting provided in TivaWare 2.2.x and
        // later to better reflect the actual VCO speed due to SYSCTL#22.
        //
        ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                               SYSCTL_OSC_MAIN |
                                               SYSCTL_USE_PLL |
                                               SYSCTL_CFG_VCO_240), 120000000);
    
        //
        // Configure the device pins.
        //
        PinoutSet(false, true);
    
        //
        // Enable UART0
        //
        MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
        //
        // Initialize the UART for console I/O.
        //
        UARTStdioConfig(0, 115200, ui32SysClock);
    
        //
        // Not configured initially.
        //
        g_bUSBConfigured = false;
    
        //
        // Enable the system tick.
        //
        MAP_SysTickPeriodSet(ui32SysClock / SYSTICKS_PER_SECOND);
        MAP_SysTickIntEnable();
        MAP_SysTickEnable();
    
        //
        // Show the application name on the display and UART output.
        //
        UARTprintf("\033[2J\nTiva C Series USB bulk device example\n");
        UARTprintf("---------------------------------\n\n");
    
        //
        // Tell the user what we are up to.
        //
        UARTprintf("Configuring USB... \n");
    
        //
        // Initialize the transmit and receive buffers.
        //
        USBBufferInit(&g_sTxBuffer);
        USBBufferInit(&g_sRxBuffer);
    
        //
        // Tell the USB library the CPU clock and the PLL frequency.  This is a
        // new requirement for TM4C129 devices.
        //
        SysCtlVCOGet(SYSCTL_XTAL_25MHZ, &ui32PLLRate);
        USBDCDFeatureSet(0, USBLIB_FEATURE_CPUCLK, &ui32SysClock);
        USBDCDFeatureSet(0, USBLIB_FEATURE_USBPLL, &ui32PLLRate);
    
        //
        // Initialize the USB stack for device mode.
        //
        USBStackModeSet(0, eUSBModeDevice, 0);
    
        //
        // Pass our device information to the USB library and place the device
        // on the bus.
        //
        USBDBulkInit(0, &g_sBulkDevice);
    
        //
        // Wait for initial configuration to complete.
        //
        UARTprintf("Waiting for host...\r");
    
        //
        // Clear our local byte counters.
        //
        ui32RxCount = 0;
        ui32TxCount = 0;
        MAP_USBDevEndpointConfigSet(USB0_BASE, USB_EP_1, 64,
                                    (USB_EP_MODE_BULK | USB_EP_DEV_IN |
                                    USB_EP_DMA_MODE_1 | USB_EP_AUTO_SET));
        // Endpoint 1 uses Mode 1 and transmit and enables automatic sending
        // when a full packet is sent to the FIFO.
        //
        MAP_USBEndpointDMAConfigSet(USB0_BASE, USB_EP_1, USB_EP_DEV_IN |
        USB_EP_DMA_MODE_1 |
        USB_EP_AUTO_SET);
        //
        // Assign endpoint 1 to DMA channel 0 using Mode 1, no bursting, transmit,
        // and enable DMA interrupts.
        //
        MAP_USBDMAChannelConfigSet(USB0_BASE, 0, USB_EP_1, USB_DMA_CFG_MODE_1 |
        USB_DMA_CFG_BURST_NONE |
        USB_DMA_CFG_DIR_TX |
        USB_DMA_CFG_INT_EN);
    
        //
        // Main application loop.
        //
        while(1)
        {
            //
            // Have we been asked to update the status display?
            //
            if(g_ui32Flags & COMMAND_STATUS_UPDATE)
            {
                g_ui32Flags &= ~COMMAND_STATUS_UPDATE;
    
                if(g_bUSBConfigured)
                {
                    UARTprintf("Host Connected.            \n\n");
                    UARTprintf("Data transferred:\n");
                    UARTprintf("TX: %d  RX: %d                    \r",
                               g_ui32TxCount,
                               g_ui32RxCount);
                }
                else
                {
                    UARTprintf("\n\nHost Disconnected.\n\n");
                }
            }
    
            //
            // Has there been any transmit traffic since we last checked?
            //
            if(ui32TxCount != g_ui32TxCount)
            {
                //
                // Take a snapshot of the latest transmit count.
                //
                ui32TxCount = g_ui32TxCount;
    
                //
                // Update the displayed buffer count information.
                //
                // UARTprintf("TX: %d  RX: %d                    \r",
                //            g_ui32TxCount,
                //            g_ui32RxCount);
            }
    
            //
            // Has there been any receive traffic since we last checked?
            //
            if(ui32RxCount != g_ui32RxCount)
            {
                //
                // Take a snapshot of the latest receive count.
                //
                ui32RxCount = g_ui32RxCount;
    
                //
                // Update the displayed buffer count information.
                //
                // UARTprintf("TX: %d  RX: %d                    \r",
                //            g_ui32TxCount,
                //            g_ui32RxCount);
            }
        }
    }
    

    2. Trigger DMA in ScheduleNextTransmission function (TivaWare_C_Series-2.2.0.295\usblib\usbbuffer.c)

    //*****************************************************************************
    //
    // usbbuffer.c - USB buffer object.
    //
    // Copyright (c) 2008-2020 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 2.2.0.295 of the Tiva USB Library.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_types.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_ints.h"
    #include "driverlib/debug.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/usb.h"
    #include "usblib/usblib.h"
    #include "usblib/usblibpriv.h"
    #include "utils/uartstdio.h"
    
    //*****************************************************************************
    //
    //! \addtogroup usblib_buffer_api
    //! @{
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // Flags which may be set in the tUSBBufferVars ui32Flags field.
    //
    //*****************************************************************************
    #define USB_BUFFER_FLAG_SEND_ZLP 0x00000001
    
    //*****************************************************************************
    //
    // Schedule the next packet transmission to the host if data remains to be
    // sent.
    //
    // \param psBuffer points to the buffer from which a packet transmission is
    // to be scheduled.
    //
    // This function checks to determine whether the lower layer is capable of
    // accepting a new packet for transmission and, if so, schedules the next
    // packet transmission if data remains in the buffer.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    ScheduleNextTransmission(tUSBBuffer *psBuffer)
    {
        uint32_t ui32Packet, ui32Space, ui32Total, ui32Sent;
    
        //
        // Ask the lower layer if it has space to accept another packet of data.
        //
        ui32Packet = psBuffer->pfnAvailable(psBuffer->pvHandle);
        UARTprintf("ui32Packet = %d\n", ui32Packet);
        //
        // If we were returned something other than zero, we can write that number
        // of bytes to the lower layer.
        //
        if(ui32Packet)
        {
            //
            // How much contiguous data do we have in the buffer?
            //
            ui32Space = USBRingBufContigUsed(&psBuffer->sPrivateData.sRingBuf);
    
            //
            // How much total data do we have in the buffer?
            //
            ui32Total = USBRingBufUsed(&psBuffer->sPrivateData.sRingBuf);
    
            //
            // How much data will we be sending as a result of this call?
            //
            ui32Sent = (ui32Packet < ui32Total) ? ui32Packet : ui32Total;
    
            //
            // Write the contiguous bytes to the lower layer assuming there is
            // something to send.
            //
            if(ui32Space)
            {
                //
                // There is data available to send.  Update our state to indicate
                // the amount we will be sending in this packet.
                //
                psBuffer->sPrivateData.ui32LastSent = ui32Sent;
    
                //
                // Determine the maximum sized block we can send in this transfer.
                //
                ui32Space = (ui32Space < ui32Packet) ? ui32Space : ui32Packet;
                //
                // Call the lower layer to send the new packet.  If the current
                // data spans the buffer wrap, tell the lower layer that it can
                // expect a second call to fill the whole packet before it
                // transmits it.
                //
            //    psBuffer->pfnTransfer(psBuffer->pvHandle,
            //                      (psBuffer->sPrivateData.sRingBuf.pui8Buf +
            //                       psBuffer->sPrivateData.sRingBuf.ui32ReadIndex),
            //                       ui32Space,
            //                      (((ui32Space < ui32Packet) &&
            //                        (ui32Space < ui32Total)) ? false : true));
                //
                // Set the source address for the transfer to pvBuffer.
                //
                MAP_USBDMAChannelAddressSet(USB0_BASE, 0, psBuffer->sPrivateData.sRingBuf.pui8Buf);
                //
                // Set the transfer size to 1024 bytes and the packet count to 1024 / 64.
                //
                MAP_USBDMAChannelCountSet(USB0_BASE, 0, 1024);
                MAP_USBEndpointPacketCountSet(USB0_BASE, USB_EP_1, 1024 / 64);
                //
                // Enable the DMA transfer.
                //
                MAP_USBDMAChannelEnable(USB0_BASE, 0);
    
                //
                // Do we need to send a second part to fill out the packet?  This
                // will occur if the current packet spans the buffer wrap.
                //
                if((ui32Space < ui32Packet) && (ui32Space < ui32Total))
                {
                    //
                    // The packet straddled the wrap.  How much space remains in
                    // the packet?
                    //
                    ui32Packet -= ui32Space;
    
                    //
                    // How much data can we actually send?
                    //
                    ui32Space = ui32Total - ui32Space;
                    ui32Space = (ui32Space > ui32Packet) ? ui32Packet : ui32Space;
    
                    psBuffer->pfnTransfer(psBuffer->pvHandle,
                                          psBuffer->sPrivateData.sRingBuf.pui8Buf,
                                          ui32Space, true);
                }
            }
            else
            {
                //
                // There is no data to send.  Did we last send a full packet?
                //
                if(psBuffer->sPrivateData.ui32LastSent == ui32Packet)
                {
                    //
                    // Yes - if necessary, send a zero-length packet back to the
                    // host to complete the last transaction.
                    //
                    if(psBuffer->sPrivateData.ui32Flags & USB_BUFFER_FLAG_SEND_ZLP)
                    {
                        psBuffer->sPrivateData.ui32LastSent = 0;
                        psBuffer->pfnTransfer(psBuffer->pvHandle,
                                          psBuffer->sPrivateData.sRingBuf.pui8Buf,
                                          0, true);
                    }
                }
            }
    
            //
            // Don't update the ring buffer read index yet.  We do this once we are
            // sure the packet was correctly transmitted.
            //
        }
    }
    
    //*****************************************************************************
    //
    // Handles USB_EVENT_RX_AVAILABLE for a receive buffer.
    //
    // \param psBuffer points to the buffer which is receiving the event.
    // \param ui32Size is the size reported in the event.
    // \param pui8Data is the pointer provided in the event.
    //
    // This function is responsible for reading data from the lower layer into
    // the buffer or, if we had previously passed a section of the buffer to the
    // lower layer for it to write into directly, updating the buffer write pointer
    // to add the new data to the buffer.
    //
    // If the pointer provided is NULL, we call the low level pfnTransfer function
    // to get the new data.  If the pointer is not NULL and not within the existing
    // ring buffer, we copy the data directly from the pointer to the buffer and
    // return the number of bytes read.
    //
    // \return Returns the number of bytes read from the lower layer.
    //
    //*****************************************************************************
    static uint32_t
    HandleRxAvailable(tUSBBuffer *psBuffer, uint32_t ui32Size, uint8_t *pui8Data)
    {
        uint32_t ui32Avail, ui32Read, ui32Packet, ui32RetCount;
    
        //
        // Has the data already been read into memory?
        //
        if(pui8Data)
        {
            //
            // Yes - is it already in our ring buffer?
            //
            if((pui8Data >= psBuffer->pui8Buffer) &&
               (pui8Data < psBuffer->pui8Buffer + psBuffer->ui32BufferSize))
            {
                //
                // The data is already in our ring buffer so merely update the
                // write pointer to add the new data.
                //
                USBRingBufAdvanceWrite(&psBuffer->sPrivateData.sRingBuf, ui32Size);
    
                //
                // In this case, we pass back 0 to indicate that the lower layer
                // doesn't need to make any buffer pointer updates.
                //
                ui32RetCount = 0;
            }
            else
            {
                //
                // The data is not within our buffer so we need to copy it into
                // the buffer.
                //
                // How much space does the buffer have available?
                //
                ui32Avail = USBRingBufFree(&psBuffer->sPrivateData.sRingBuf);
    
                //
                // How much should we copy?
                //
                ui32Read = (ui32Avail < ui32Size) ? ui32Avail : ui32Size;
    
                //
                // Copy the data into the buffer.
                //
                USBRingBufWrite(&psBuffer->sPrivateData.sRingBuf, pui8Data,
                                ui32Read);
    
                //
                // We need to return the number of bytes we read in this case
                // since the buffer supplied to us was owned by the lower layer and
                // it may need to update its read pointer.
                //
                ui32RetCount = ui32Read;
            }
        }
        else
        {
            //
            // We were passed a NULL pointer so the low level driver has not read
            // the data into memory yet.  We need to call the transfer function to
            // get the packet.
            //
            // How big is the packet that we need to receive?
            //
            ui32Packet = psBuffer->pfnAvailable(psBuffer->pvHandle);
    
            //
            // How much contiguous space do we have in the buffer?
            //
            ui32Avail = USBRingBufContigFree(&psBuffer->sPrivateData.sRingBuf);
    
            //
            // Get as much of the packet as we can in the available space.
            //
            ui32Read = psBuffer->pfnTransfer(psBuffer->pvHandle,
                                  (psBuffer->sPrivateData.sRingBuf.pui8Buf +
                                   psBuffer->sPrivateData.sRingBuf.ui32WriteIndex),
                                  ui32Avail, true);
    
            //
            // Advance the ring buffer write pointer to add our new data.
            //
            if(ui32Read)
            {
                USBRingBufAdvanceWrite(&psBuffer->sPrivateData.sRingBuf, ui32Read);
            }
    
            //
            // Did we get the whole packet?
            //
            if(ui32Read < ui32Packet)
            {
                //
                // No - how much space do we have in the buffer?
                //
                ui32Avail = USBRingBufContigFree(&psBuffer->sPrivateData.sRingBuf);
    
                //
                // If there is any space left, read as much of the remainder of
                // the packet as we can.
                //
                if(ui32Avail)
                {
                    ui32Packet =
                        psBuffer->pfnTransfer(psBuffer->pvHandle,
                                  (psBuffer->sPrivateData.sRingBuf.pui8Buf +
                                   psBuffer->sPrivateData.sRingBuf.ui32WriteIndex),
                                   ui32Avail, true);
    
                    //
                    // Update the write pointer after we read more data into the
                    // buffer.
                    //
                    if(ui32Packet)
                    {
                        USBRingBufAdvanceWrite(&psBuffer->sPrivateData.sRingBuf,
                                               ui32Packet);
                    }
                }
            }
    
            //
            // We need to return 0 in this case to indicate that the lower layer
            // need not perform any buffer maintenance as a result of the callback.
            //
            ui32RetCount = 0;
        }
    
        //
        // How much data do we have in the buffer?
        //
        ui32Avail = USBRingBufUsed(&psBuffer->sPrivateData.sRingBuf);
    
        //
        // Pass the event on to the client with the current read pointer and
        // available data size.  The client is expected to understand the ring
        // structure and be able to deal with wrap if it wants to read the data
        // directly from the buffer.
        //
        ui32Read = psBuffer->pfnCallback(psBuffer->pvCBData,
                                 USB_EVENT_RX_AVAILABLE, ui32Avail,
                                 (psBuffer->sPrivateData.sRingBuf.pui8Buf +
                                  psBuffer->sPrivateData.sRingBuf.ui32ReadIndex));
    
        //
        // If the client read anything from the buffer, update the read pointer.
        //
        USBRingBufAdvanceRead(&psBuffer->sPrivateData.sRingBuf, ui32Read);
    
        //
        // Return the correct value to the low level driver.
        //
        return(ui32RetCount);
    }
    
    //*****************************************************************************
    //
    // Handles USB_EVENT_DATA_REMAINING for a receive buffer.
    //
    // \param psBuffer points to the buffer which is receiving the event.
    //
    // This function determines the total number of bytes of data that remain
    // unprocessed in the client and buffer and reports this back to the caller.
    //
    // \return Returns the number of bytes remaining to be processed.
    //
    //*****************************************************************************
    static uint32_t
    HandleDataRemaining(tUSBBuffer *psBuffer)
    {
        uint32_t ui32BufData, ui32ClientData;
    
        //
        // How much data does the client currently have buffered?
        //
        ui32ClientData = psBuffer->pfnCallback(psBuffer->pvCBData,
                                               USB_EVENT_DATA_REMAINING, 0,
                                               (void *)0);
    
        //
        // How much data do we have in the buffer?
        //
        ui32BufData = USBRingBufUsed(&psBuffer->sPrivateData.sRingBuf);
    
        //
        // Return the total number of bytes of unprocessed data to the lower layer.
        //
        return(ui32BufData + ui32ClientData);
    }
    
    //*****************************************************************************
    //
    // Handles USB_EVENT_TX_COMPLETE for a transmit buffer.
    //
    // \param psBuffer points to the buffer which is receiving the event.
    // \param ui32Size is the number of bytes that have been transmitted and
    // acknowledged.
    //
    // This function informs us that data written to the lower layer from a
    // transmit buffer has been successfully transmitted.  We use this to update
    // the buffer read pointer and attempt to schedule the next transmission if
    // data remains in the buffer.
    //
    // \return Returns the number of bytes remaining to be processed.
    //
    //*****************************************************************************
    static uint32_t
    HandleTxComplete(tUSBBuffer *psBuffer, uint32_t ui32Size)
    {
        //
        // Update the transmit buffer read pointer to remove the data that has
        // now been transmitted.
        //
        UARTprintf("HandleTxComplete\n");
        USBRingBufAdvanceRead(&psBuffer->sPrivateData.sRingBuf, ui32Size);
    
        //
        // Try to schedule the next packet transmission if data remains to be
        // sent.
        //
        ScheduleNextTransmission(psBuffer);
    
        //
        // The return code from this event is ignored.
        //
        return(0);
    }
    
    //*****************************************************************************
    //
    // Handles USB_EVENT_REQUEST_BUFFER for a receive buffer.
    //
    // \param psBuffer points to the buffer which is receiving the event.
    // \param ui32Size is the size of the buffer requested.
    // \param ppui8Buffer is a pointer which is to be written with a pointer to
    // the returned buffer.
    //
    // This function is called by a low level driver that wishes to receive data
    // automatically and write it directly to a memory buffer, either using
    // software or DMA prior to issuing USB_EVENT_RX_AVAILABLE.  The event is sent
    // in advance of receiving data to provide storage for whatever is received
    // next.
    //
    // If we have a contiguous block of space in the buffer of at least ui32Size
    // bytes immediately in front of the current write pointer, we pass this back
    // otherwise we send NULL indicating that the next packet should be notified
    // using a standard USB_EVENT_RX_AVAILABLE event without being received
    // automatically.  Note that the USB_EVENT_REQUEST_BUFFER protocol allows us to
    // return less than \e ui32Size bytes if we know how much data is expected next
    // but this is not possible here since the USBBuffer knows nothing about the
    // protocol whose data it is handling.
    //
    // \return Returns the number of bytes remaining to be processed.
    //
    //*****************************************************************************
    static uint32_t
    HandleRequestBuffer(tUSBBuffer *psBuffer, uint32_t ui32Size,
                        uint8_t **ppui8Buffer)
    {
        uint32_t ui32Space;
    
        //
        // How much contiguous space do we have available?
        //
        ui32Space = USBRingBufContigFree(&psBuffer->sPrivateData.sRingBuf);
    
        //
        // Is there enough space available to satisfy the request?
        //
        if(ui32Space >= ui32Size)
        {
            //
            // Yes - return the current write pointer
            //
            *ppui8Buffer = psBuffer->sPrivateData.sRingBuf.pui8Buf +
                           psBuffer->sPrivateData.sRingBuf.ui32WriteIndex;
            return(ui32Size);
        }
        else
        {
            //
            // We do not have enough contiguous space following the current write
            // pointer to satisfy the request so do not provide a buffer.
            //
            *ppui8Buffer = (uint8_t *)0;
            return(0);
        }
    }
    
    //*****************************************************************************
    //
    //! Initializes a USB buffer object to be used with a given USB controller and
    //! device or host class driver.
    //!
    //! \param psBuffer points to a structure containing information on the buffer
    //! memory to be used and the underlying device or host class driver whose data
    //! is to be buffered.  This structure must remain accessible for as long as
    //! the buffer is in use.
    //!
    //! This function is used to initialize a USB buffer object and insert it
    //! into the function and callback interfaces between an underlying driver
    //! and the application.  The caller supplies information on both the RAM
    //! to be used to buffer data, the type of buffer to be created (transmit or
    //! receive) and the functions to be called in the lower layer to transfer
    //! data to or from the USB controller.
    //!
    //! \return Returns the original buffer structure pointer if successful or
    //! NULL if an error is detected.
    //
    //*****************************************************************************
    const tUSBBuffer *
    USBBufferInit(tUSBBuffer *psBuffer)
    {
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer && psBuffer->pui8Buffer &&
               psBuffer->ui32BufferSize && psBuffer->pfnAvailable &&
               psBuffer->pfnTransfer && psBuffer->pfnCallback);
    
        //
        // Get a pointer to the buffer workspace and initialize the variables it
        // contains.
        //
        psBuffer->sPrivateData.ui32Flags = 0;
        USBRingBufInit(&psBuffer->sPrivateData.sRingBuf, psBuffer->pui8Buffer,
                       psBuffer->ui32BufferSize);
    
        //
        // If all is well, return the same pointer we were originally passed.
        //
        return(psBuffer);
    }
    
    //*****************************************************************************
    //
    //! Enables or disables zero-length packet insertion.
    //!
    //! \param psBuffer is the pointer to the buffer instance whose information
    //! is being queried.
    //! \param bSendZLP is \b true to send zero-length packets or \b false to
    //! prevent them from being sent.
    //!
    //! This function allows the use of zero-length packets to be controlled by
    //! an application.  In cases where the USB buffer has sent a full (64 byte)
    //! packet and then discovers that the transmit buffer is empty, the default
    //! behavior is to do nothing.  Some protocols, however, require that a zero-
    //! length packet be inserted to signal the end of the data.  When using such
    //! a protocol, this function should be called with \e bSendZLP set to \b true
    //! to enable the desired behavior.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBufferZeroLengthPacketInsert(const tUSBBuffer *psBuffer, bool bSendZLP)
    {
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // Set the flag telling us whether or not to send a zero-length packet
        // after sending a full packet (64 bytes and 512 bytes for HS) and 
        // finding no more data to send.
        //
        if(bSendZLP)
        {
            //
            // Enable ZLP transmission.
            //
            psPrivate->ui32Flags |= USB_BUFFER_FLAG_SEND_ZLP;
        }
        else
        {
            //
            // Disable ZLP transmission.
            //
            psPrivate->ui32Flags &= ~ USB_BUFFER_FLAG_SEND_ZLP;
        }
    }
    
    //*****************************************************************************
    //
    //! Returns the current ring buffer indices for this USB buffer.
    //!
    //! \param psBuffer is the pointer to the buffer instance whose information
    //! is being queried.
    //! \param psRingBuf is a pointer to storage that will be written with the
    //! current ring buffer control structure for this USB buffer.
    //!
    //! This function is provided to aid a client wishing to write data directly
    //! into the USB buffer rather than using the USBBufferWrite() function.  This
    //! may be necessary to control when the USBBuffer starts transmission of a
    //! large block of data, for example.
    //!
    //! A transmit buffer will immediately send a new packet on any call to
    //! USBBufferWrite() if the underlying layer indicates that a transmission can
    //! be started.  In some cases this is not desirable and a client may wish to
    //! wishes to write more data to the buffer in advance of starting transmission
    //! to the lower layer.  In such cases, this function may be called to retrieve
    //! the current ring buffer indices and the buffer accessed directly.  Once the
    //! client has written all data it wishes to send, it should call function
    //! USBBufferDataWritten() to indicate that transmission may begin.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBufferInfoGet(const tUSBBuffer *psBuffer, tUSBRingBufObject *psRingBuf)
    {
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer && psRingBuf);
    
        //
        // Copy the current ring buffer settings to the clients storage.
        //
        psRingBuf->pui8Buf = psBuffer->sPrivateData.sRingBuf.pui8Buf;
        psRingBuf->ui32ReadIndex = psBuffer->sPrivateData.sRingBuf.ui32ReadIndex;
        psRingBuf->ui32Size = psBuffer->sPrivateData.sRingBuf.ui32ReadIndex;
        psRingBuf->ui32WriteIndex = psBuffer->sPrivateData.sRingBuf.ui32WriteIndex;
    }
    
    //*****************************************************************************
    //
    //! Indicates that a client has written data directly into the buffer and
    //! wishes to start transmission.
    //!
    //! \param psBuffer is the pointer to the buffer instance into which data has
    //! been written.
    //! \param ui32Length is the number of bytes of data that the client has
    //! written.
    //!
    //! This function updates the USB buffer write pointer and starts transmission
    //! of the data in the buffer assuming the lower layer is ready to receive a
    //! new packet.  The function is provided to aid a client wishing to write
    //! data directly into the USB buffer rather than using the USBBufferWrite()
    //! function.  This may be necessary to control when the USB buffer starts
    //! transmission of a large block of data, for example.
    //!
    //! A transmit buffer will immediately send a new packet on any call to
    //! USBBufferWrite() if the underlying layer indicates that a transmission can
    //! be started.  In some cases this is not desirable and a client may wish to
    //! write more data to the buffer in advance of starting transmission
    //! to the lower layer.  In such cases, USBBufferInfoGet() may be called to
    //! retrieve the current ring buffer indices and the buffer accessed directly.
    //! Once the client has written all data it wishes to send (taking care to
    //! handle the ring buffer wrap), it should call this function to indicate that
    //! transmission may begin.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBufferDataWritten(const tUSBBuffer *psBuffer, uint32_t ui32Length)
    {
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // Advance the ring buffer write pointer to include the newly written
        // data.
        //
        if(ui32Length)
        {
            USBRingBufAdvanceWrite(&psPrivate->sRingBuf, ui32Length);
        }
        UARTprintf("ScheduleNextTransmission 1\n");
        //
        // Try to schedule a new packet transmission.
        //
        ScheduleNextTransmission((tUSBBuffer *)psBuffer);
    }
    
    //*****************************************************************************
    //
    //! Indicates that a client has read data directly out of the buffer.
    //!
    //! \param psBuffer is the pointer to the buffer instance from which data has
    //! been read.
    //! \param ui32Length is the number of bytes of data that the client has read.
    //!
    //! This function updates the USB buffer read pointer to remove data that
    //! the client has read directly rather than via a call to USBBufferRead().
    //! The function is provided to aid a client wishing to minimize data copying.
    //! To read directly from the buffer, a client must call USBBufferInfoGet() to
    //! retrieve the current buffer inpsBufVarsdices.  With this information, the
    //! data following the current read index can be read.  Once the client has
    //! processed much data as it needs, USBBufferDataRemoved() must be called to
    //! advance the read pointer past the data that has been read and free up that
    //! section of the buffer.  The client must take care to correctly handle the
    //! wrap point if accessing the buffer directly.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBufferDataRemoved(const tUSBBuffer *psBuffer, uint32_t ui32Length)
    {
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // Advance the ring buffer write pointer to include the newly written
        // data.
        //
        if(ui32Length)
        {
            USBRingBufAdvanceRead(&psPrivate->sRingBuf, ui32Length);
        }
    }
    
    //*****************************************************************************
    //
    //! Sets the callback pointer supplied to clients of this buffer.
    //!
    //! \param psBuffer is the pointer to the buffer instance whose callback data
    //! is to be changed.
    //! \param pvCBData is the pointer the client wishes to receive on all future
    //! callbacks from this buffer.
    //!
    //! This function sets the callback pointer which this buffer will supply
    //! to clients as the \e pvCBData parameter in all future calls to the
    //! event callback.
    //!
    //! \note If this function is to be used, the application must ensure that the
    //! tUSBBuffer structure used to describe this buffer is held in RAM rather
    //! than flash.  The \e pvCBData value passed is written directly into this
    //! structure.
    //!
    //! \return Returns the previous callback pointer set for the buffer.
    //
    //*****************************************************************************
    void *
    USBBufferCallbackDataSet(tUSBBuffer *psBuffer, void *pvCBData)
    {
        void *pvOldData;
    
        //
        // Keep a copy of the old callback data.
        //
        pvOldData = psBuffer->pvCBData;
    
        //
        // Replace the callback data with the new value.
        //
        psBuffer->pvCBData = pvCBData;
    
        //
        // Give the caller the old value back.
        //
        return(pvOldData);
    }
    
    //*****************************************************************************
    //
    //! Writes a block of data to the transmit buffer and queues it for
    //! transmission to the USB controller.
    //!
    //! \param psBuffer points to the pointer instance into which data is to be
    //! written.
    //! \param pui8Data points to the first byte of data which is to be written.
    //! \param ui32Length is the number of bytes of data to write to the buffer.
    //!
    //! This function copies the supplied data into the transmit buffer.  The
    //! transmit buffer data will be packetized according to the constraints
    //! imposed by the lower layer in use and sent to the USB controller as soon as
    //! possible.  Once a packet is transmitted and acknowledged, a
    //! \b USB_EVENT_TX_COMPLETE event will be sent to the application callback
    //! indicating the number of bytes that have been sent from the buffer.
    //!
    //! Attempts to send more data than there is space for in the transmit buffer
    //! will result in fewer bytes than expected being written.  The value returned
    //! by the function indicates the actual number of bytes copied to the buffer.
    //!
    //! \return Returns the number of bytes actually written.
    //
    //*****************************************************************************
    uint32_t
    USBBufferWrite(const tUSBBuffer *psBuffer, const uint8_t *pui8Data,
                   uint32_t ui32Length)
    {
        uint32_t ui32Space;
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer && pui8Data);
        ASSERT(psBuffer->bTransmitBuffer == true);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // How much space is left in the buffer?
        //
        ui32Space = USBRingBufFree(&psPrivate->sRingBuf);
    
        //
        // How many bytes will we write?
        //
        ui32Length = (ui32Length > ui32Space) ? ui32Space : ui32Length;
    
        //
        // Write the data to the buffer.
        //
        if(ui32Length)
        {
            USBRingBufWrite(&psPrivate->sRingBuf, pui8Data, ui32Length);
        }
        UARTprintf("ScheduleNextTransmission 2\n");
        //
        // Try to transmit the next packet to the host.
        //
        ScheduleNextTransmission((tUSBBuffer *)psBuffer);
    
        //
        // Tell the caller how many bytes we wrote to the buffer.
        //
        return(ui32Length);
    }
    
    //*****************************************************************************
    //
    //! Flushes a USB buffer, discarding any data that it contains.
    //!
    //! \param psBuffer is the pointer to the buffer instance which is to be
    //! flushed.
    //!
    //! This function discards all data currently in the supplied buffer without
    //! processing (transmitting it via the USB controller or passing it to the
    //! client depending upon the buffer mode).
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBBufferFlush(const tUSBBuffer *psBuffer)
    {
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // Flush the ring buffer.
        //
        USBRingBufFlush(&psPrivate->sRingBuf);
    }
    
    //*****************************************************************************
    //
    //! Reads a block of data from a USB receive buffer into storage supplied by
    //! the caller.
    //!
    //! \param psBuffer is the pointer to the buffer instance from which data is
    //! to be read.
    //! \param pui8Data points to a buffer into which the received data will be
    //! written.
    //! \param ui32Length is the size of the buffer pointed to by pui8Data.
    //!
    //! This function reads up to \e ui32Length bytes of data received from the USB
    //! host into the supplied application buffer.  If the receive buffer
    //! contains fewer than \e ui32Length bytes of data, the data that is present
    //! will be copied and the return code will indicate the actual number of bytes
    //! copied to \e pui8Data.
    //!
    //! \return Returns the number of bytes of data read.
    //
    //*****************************************************************************
    uint32_t
    USBBufferRead(const tUSBBuffer *psBuffer, uint8_t *pui8Data,
                  uint32_t ui32Length)
    {
        uint32_t ui32Avail, ui32Read;
        tUSBBufferVars *psPrivate;
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer && pui8Data && ui32Length);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // How much data is in the buffer?
        //
        ui32Avail = USBRingBufUsed(&psPrivate->sRingBuf);
    
        //
        // Determine how many bytes we can actually read.
        //
        ui32Read = (ui32Avail < ui32Length) ? ui32Avail : ui32Length;
    
        //
        // Read the data from the buffer assuming there is some to read.
        //
        if(ui32Read)
        {
            USBRingBufRead(&psPrivate->sRingBuf, pui8Data, ui32Read);
        }
    
        //
        // Tell the caller how many bytes we wrote to their buffer.
        //
        return(ui32Read);
    }
    
    //*****************************************************************************
    //
    //! Returns the number of bytes of data available in the buffer.
    //!
    //! \param psBuffer is the pointer to the buffer instance which is to be
    //! queried.
    //!
    //! This function may be used to determine the number of bytes of data in a
    //! buffer.  For a receive buffer, this indicates the number of bytes that the
    //! client can read from the buffer using USBBufferRead().  For a transmit
    //! buffer, this indicates the amount of data that remains to be sent to the
    //! USB controller.
    //!
    //! \return Returns the number of bytes of data in the buffer.
    //
    //*****************************************************************************
    uint32_t
    USBBufferDataAvailable(const tUSBBuffer *psBuffer)
    {
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // Return the amount of data in the buffer.
        //
        return(USBRingBufUsed(&psPrivate->sRingBuf));
    }
    
    //*****************************************************************************
    //
    //! Returns the number of free bytes in the buffer.
    //!
    //! \param psBuffer is the pointer to the buffer instance which is to be
    //! queried.
    //!
    //! This function returns the number of free bytes in the buffer.  For a
    //! transmit buffer, this indicates the maximum number of bytes that can be
    //! passed on a call to USBBufferWrite() and accepted for transmission.  For a
    //! receive buffer, it indicates the number of bytes that can be read from the
    //! USB controller before the buffer will be full.
    //!
    //! \return Returns the number of free bytes in the buffer.
    //
    //*****************************************************************************
    uint32_t
    USBBufferSpaceAvailable(const tUSBBuffer *psBuffer)
    {
        tUSBBufferVars *psPrivate;
    
        //
        // Check parameter validity.
        //
        ASSERT(psBuffer);
    
        //
        // Create a writable pointer to the private data.
        //
        psPrivate = &((tUSBBuffer *)psBuffer)->sPrivateData;
    
        //
        // Return the amount of space available in the buffer.
        //
        return(USBRingBufFree(&psPrivate->sRingBuf));
    }
    
    //*****************************************************************************
    //
    //! Called by the USB buffer to notify the client of asynchronous events.
    //!
    //! \param pvCBData is the client-supplied callback pointer associated with
    //! this buffer instance.
    //! \param ui32Event is the identifier of the event being sent.  This will be
    //! a general event identifier of the form \b USBD_EVENT_xxxx or a device
    //! class-dependent event of the form \b USBD_CDC_EVENT_xxx or
    //! \b USBD_HID_EVENT_xxx.
    //! \param ui32MsgValue is an event-specific parameter value.
    //! \param pvMsgData is an event-specific data pointer.
    //!
    //! This function is the USB buffer event handler that applications should
    //! register with the USB device class driver as the callback for the channel
    //! which is to be buffered using this buffer.
    //!
    //! \note This function will never be called by an application.  It is the
    //! handler that allows the USB buffer to be inserted above the device class
    //! driver or host pipe driver and below the application to offer buffering
    //! support.
    //!
    //! \return The return value is dependent upon the event being processed.
    //
    //*****************************************************************************
    uint32_t
    USBBufferEventCallback(void *pvCBData, uint32_t ui32Event,
                           uint32_t ui32MsgValue, void *pvMsgData)
    {
        tUSBBuffer *psBuffer;
    
        //
        // Get our instance data pointers from the callback data.
        //
        psBuffer = (tUSBBuffer *)pvCBData;
        ASSERT(psBuffer);
    
        //
        // Which event have we been sent?
        //
        switch(ui32Event)
        {
            //
            // Data is available from the lower layer.
            //
            case USB_EVENT_RX_AVAILABLE:
            {
                //
                // This event is only relevant to us if we are a receive buffer.
                //
                if(!psBuffer->bTransmitBuffer)
                {
                    return(HandleRxAvailable(psBuffer, ui32MsgValue, pvMsgData));
                }
                break;
            }
    
            //
            // We are being asked how much data remains to be processed.
            //
            case USB_EVENT_DATA_REMAINING:
            {
                return(HandleDataRemaining(psBuffer));
            }
    
            //
            // A previous transmission has completed.
            //
            case USB_EVENT_TX_COMPLETE:
            {
                //
                // This event is only relevant to us if we are a transmit buffer.
                //
                if(psBuffer->bTransmitBuffer)
                {
                    //
                    // Handle the message then drop out of the switch so that the
                    // event is echoed to the layer above.
                    //
                    HandleTxComplete(psBuffer, ui32MsgValue);
                }
                break;
            }
    
            //
            // We are being asked to provide a buffer into which the next packet
            // can be received.
            //
            case USB_EVENT_REQUEST_BUFFER:
            {
                //
                // This event is only relevant to us if we are a receive buffer.
                //
                if(!psBuffer->bTransmitBuffer)
                {
                    return(HandleRequestBuffer(psBuffer, ui32MsgValue, pvMsgData));
                }
                break;
            }
    
            //
            // All other events are merely passed through to the client.
            //
            default:
            {
                break;
            }
        }
    
        //
        // If we drop out of the switch, we need to pass the event on to the client
        // unmodified and return the relevant return code back to the lower layer.
        //
        return(psBuffer->pfnCallback(psBuffer->pvCBData, ui32Event, ui32MsgValue,
                                     pvMsgData));
    }
    
    //*****************************************************************************
    //
    // Close the Doxygen group.
    //! @}
    //
    //*****************************************************************************
    

    3. Handle DMA INT (TivaWare_C_Series-2.2.0.295\usblib\device\usbdenum.c)

    //*****************************************************************************
    //
    // usbenum.c - Enumeration code to handle all endpoint zero traffic.
    //
    // Copyright (c) 2007-2020 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    // 
    // Texas Instruments (TI) is supplying this software for use solely and
    // exclusively on TI's microcontroller products. The software is owned by
    // TI and/or its suppliers, and is protected under applicable copyright
    // laws. You may not combine this software with "viral" open-source
    // software in order to form a larger program.
    // 
    // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
    // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
    // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
    // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
    // DAMAGES, FOR ANY REASON WHATSOEVER.
    // 
    // This is part of revision 2.2.0.295 of the Tiva USB Library.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_sysctl.h"
    #include "driverlib/debug.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/rom.h"
    #include "driverlib/rom_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/usb.h"
    #include "driverlib/rtos_bindings.h"
    #include "usblib/usblib.h"
    #include "usblib/usblibpriv.h"
    #include "usblib/usbulpi.h"
    #include "usblib/device/usbdevice.h"
    #include "usblib/device/usbdevicepriv.h"
    #include "usblib/device/usbdbulk.h"
    #include "usblib/usblibpriv.h"
    #include "utils/uartstdio.h"
    
    //*****************************************************************************
    //
    // External prototypes.
    //
    //*****************************************************************************
    extern tUSBMode g_iUSBMode;
    
    //*****************************************************************************
    //
    // Local functions prototypes.
    //
    //*****************************************************************************
    static void USBDGetStatus(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDClearFeature(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDSetFeature(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDSetAddress(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDGetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDSetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDGetConfiguration(void *pvInstance,
                                     tUSBRequest *psUSBRequest);
    static void USBDSetConfiguration(void *pvInstance,
                                     tUSBRequest *psUSBRequest);
    static void USBDGetInterface(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDSetInterface(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDSyncFrame(void *pvInstance, tUSBRequest *psUSBRequest);
    static void USBDEP0StateTx(uint32_t ui32Index);
    static void USBDEP0StateTxConfig(uint32_t ui32Index);
    static int32_t USBDStringIndexFromRequest(uint16_t ui16Lang,
                                              uint16_t ui16Index);
    
    //*****************************************************************************
    //
    //! \addtogroup device_api
    //! @{
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // Indices into the ppui8Halt array to select the IN or OUT endpoint group.
    //
    //*****************************************************************************
    #define HALT_EP_IN              0
    #define HALT_EP_OUT             1
    
    //*****************************************************************************
    //
    // Define the max packet size for endpoint zero.
    //
    //*****************************************************************************
    #define EP0_MAX_PACKET_SIZE     64
    
    //*****************************************************************************
    //
    // This is a flag used with g_sUSBDeviceState.ui32DevAddress to indicate that a
    // device address change is pending.
    //
    //*****************************************************************************
    #define DEV_ADDR_PENDING        0x80000000
    
    //*****************************************************************************
    //
    // This label defines the default configuration number to use after a bus
    // reset.  This may be overridden by calling USBDCDSetDefaultConfiguration()
    // during processing of the device reset handler if required.
    //
    //*****************************************************************************
    #define DEFAULT_CONFIG_ID       1
    
    //*****************************************************************************
    //
    // This label defines the number of milliseconds that the remote wake up signal
    // must remain asserted before removing it. Section 7.1.7.7 of the USB 2.0 spec
    // states that "the remote wake up device must hold the resume signaling for at
    // least 1ms but for no more than 15ms" so 10mS seems a reasonable choice.
    //
    //*****************************************************************************
    #define REMOTE_WAKEUP_PULSE_MS 10
    
    //*****************************************************************************
    //
    // This label defines the number of milliseconds between the point where we
    // assert the remote wake up signal and calling the client back to tell it that
    // bus operation has been resumed.  This value is based on the timings provided
    // in section 7.1.7.7 of the USB 2.0 specification which indicates that the
    // host (which takes over resume signaling when the device's initial signal is
    // detected) must hold the resume signaling for at least 20mS.
    //
    //*****************************************************************************
    #define REMOTE_WAKEUP_READY_MS 20
    
    //*****************************************************************************
    //
    // The LPM states.
    //
    //*****************************************************************************
    #define USBLIB_LPM_STATE_DISABLED   0x00000000
    #define USBLIB_LPM_STATE_AWAKE      0x00000001
    #define USBLIB_LPM_STATE_SLEEP      0x00000002
    
    //*****************************************************************************
    //
    // The buffer for reading data coming into EP0
    //
    //*****************************************************************************
    static uint8_t g_pui8DataBufferIn[EP0_MAX_PACKET_SIZE];
    
    //*****************************************************************************
    //
    // This is 480000000/60000000 or a PLL Divide of 8.
    //
    //*****************************************************************************
    static uint32_t g_ui32PLLDiv = 8;
    
    //*****************************************************************************
    //
    // Holds the ULPI configuration.
    //
    //*****************************************************************************
    static uint32_t g_ui32ULPISupport;
    
    //*****************************************************************************
    //
    // This is the instance data for the USB controller itself and not a USB
    // device class.
    //
    //*****************************************************************************
    tDCDInstance g_psDCDInst[1];
    
    //*****************************************************************************
    //
    // This is the currently active class in use by USBLib.  There is only one
    // of these per USB controller and no device has more than one controller.
    //
    //*****************************************************************************
    tDeviceInfo *g_ppsDevInfo[1];
    
    //*****************************************************************************
    //
    // Function table to handle standard requests.
    //
    //*****************************************************************************
    static const tStdRequest g_psUSBDStdRequests[] =
    {
        USBDGetStatus,
        USBDClearFeature,
        0,
        USBDSetFeature,
        0,
        USBDSetAddress,
        USBDGetDescriptor,
        USBDSetDescriptor,
        USBDGetConfiguration,
        USBDSetConfiguration,
        USBDGetInterface,
        USBDSetInterface,
        USBDSyncFrame
    };
    
    //*****************************************************************************
    //
    // Functions accessible by USBLIB clients.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    //! Initialize an instance of the tDeviceInfo structure.
    //!
    //! \param ui32Index is the index of the USB controller which is to be
    //! initialized.
    //! \param psDeviceInfo is a pointer to the tDeviceInfo structure that needs
    //! to be initialized.
    //!
    //! This function must be called by a USB device class
    //! instance to initialize the basic tDeviceInfo required for all USB device
    //! class modules.  This is typically called in the initialization routine for
    //! USB device class.  For example in usbdaudio.c that supports USB device
    //! audio classes, this function is called in the USBDAudioCompositeInit()
    //! function which is used for both composite and non-composites instances of
    //! the USB audio class.
    //!
    //! \note This function should not be called directly by applications.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDDeviceInfoInit(uint32_t ui32Index, tDeviceInfo *psDeviceInfo)
    {
        //
        // Check the arguments.
        //
        ASSERT(ui32Index == 0);
        ASSERT(psDeviceInfo != 0);
    
        //
        // Save the USB interrupt number.
        //
        g_psDCDInst[0].ui32IntNum = INT_USB0_TM4C123;
    
        //
        // These devices have a different USB interrupt number.
        //
        if(CLASS_IS_TM4C129)
        {
            g_psDCDInst[0].ui32IntNum = INT_USB0_TM4C129;
        }
    
        //
        // Disable LPM support by default.
        //
        g_psDCDInst[0].ui32LPMState = 0;
    
        //
        // Initialize a couple of fields in the device state structure.
        //
        g_psDCDInst[0].ui32Configuration = DEFAULT_CONFIG_ID;
        g_psDCDInst[0].ui32DefaultConfiguration = DEFAULT_CONFIG_ID;
    
        g_psDCDInst[0].iEP0State = eUSBStateIdle;
    
        //
        // Default to the state where remote wake up is disabled.
        //
        g_psDCDInst[0].ui8Status = 0;
        g_psDCDInst[0].bRemoteWakeup = false;
    
        //
        // Determine the self- or bus-powered state based on the flags the
        // user provided.
        //
        g_psDCDInst[0].bPwrSrcSet = false;
    }
    
    //*****************************************************************************
    //
    //! Initialize the USB library device control driver for a given hardware
    //! controller.
    //!
    //! \param ui32Index is the index of the USB controller which is to be
    //! initialized.
    //! \param psDevice is a pointer to a structure containing information that
    //! the USB library requires to support operation of this application's
    //! device.  The structure contains event handler callbacks and pointers to the
    //! various standard descriptors that the device wishes to publish to the
    //! host.
    //! \param pvDCDCBData is the callback data for any device callbacks.
    //!
    //! This function must be called by a device class which wishes to operate
    //! as a USB device and is not typically called by an application.  This
    //! function initializes the USB device control driver for the given
    //! controller and saves the device information for future use.  Prior to
    //! returning from this function, the device is connected to the USB bus.
    //! Following return, the caller can expect to receive a callback to the
    //! supplied <tt>pfnResetHandler</tt> function when a host connects to the
    //! device.  The \e pvDCDCBData contains a pointer to data that is returned
    //! with the DCD calls back to the function in the psDevice->psCallbacks()
    //! functions.
    //!
    //! The device information structure passed in \e psDevice must remain
    //! unchanged between this call and any matching call to USBDCDTerm() because
    //! it is not copied by the USB library.
    //!
    //! The USBStackModeSet() function can be called with eUSBModeForceDevice in
    //! order to cause the USB library to force the USB operating mode to a device
    //! controller.  This allows the application to used the USBVBUS and USBID pins
    //! as GPIOs on devices that support forcing OTG to operate as a device only
    //! controller.  By default the USB library will assume that the USBVBUS and
    //! USBID pins are configured as USB pins and not GPIOs.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDInit(uint32_t ui32Index, tDeviceInfo *psDevice, void *pvDCDCBData)
    {
        const tConfigHeader *psHdr;
        const tConfigDescriptor *psDesc;
    
        //
        // Check the arguments.
        //
        ASSERT(ui32Index == 0);
        ASSERT(psDevice != 0);
    
        g_ppsDevInfo[0] = psDevice;
        g_psDCDInst[0].pvCBData = pvDCDCBData;
    
        //
        // Initialize the Device Info structure for a USB device instance.
        //
        USBDCDDeviceInfoInit(ui32Index, psDevice);
    
        //
        // Should not call this if the stack is in host mode.
        //
        ASSERT(g_iUSBMode != eUSBModeHost);
        ASSERT(g_iUSBMode != eUSBModeForceHost);
    
        //
        // Default to device mode if no mode was set.
        //
        if(g_iUSBMode == eUSBModeNone)
        {
            g_iUSBMode = eUSBModeDevice;
        }
    
        //
        // Only do hardware update if the stack is in not in OTG mode.
        //
        if(g_iUSBMode != eUSBModeOTG)
        {
            //
            // Reset the USB controller.
            //
            MAP_SysCtlPeripheralReset(SYSCTL_PERIPH_USB0);
    
            //
            // Enable Clocking to the USB controller.
            //
            MAP_SysCtlPeripheralEnable(SYSCTL_PERIPH_USB0);
    
            //
            // Turn on USB Phy clock.
            //
            MAP_SysCtlUSBPLLEnable();
    
            //
            // Set the PLL to USB clock divider.
            //
            if(g_ui32PLLDiv == 0)
            {
                USBClockEnable(USB0_BASE, g_ui32PLLDiv, USB_CLOCK_EXTERNAL);
            }
            else
            {
                USBClockEnable(USB0_BASE, g_ui32PLLDiv, USB_CLOCK_INTERNAL);
            }
    
            //
            // Configure ULPI support.
            //
            if(g_ui32ULPISupport != USBLIB_FEATURE_ULPI_NONE)
            {
                USBULPIEnable(USB0_BASE);
    
                if(g_ui32ULPISupport & USBLIB_FEATURE_ULPI_HS)
                {
                    ULPIConfigSet(USB0_BASE, ULPI_CFG_HS);
                }
                else
                {
                    ULPIConfigSet(USB0_BASE, ULPI_CFG_FS);
                }
            }
            else
            {
                USBULPIDisable(USB0_BASE);
            }
    
            //
            // Force device mode if requested.
            //
            if(g_iUSBMode == eUSBModeForceDevice)
            {
                MAP_USBDevMode(USB0_BASE);
            }
            else if(g_iUSBMode == eUSBModeDevice)
            {
                //
                // To run in active device mode the OTG signals must be active.
                // This allows disconnect to be detected by the controller.
                //
                MAP_USBOTGMode(USB0_BASE);
            }
    
            //
            // In all other cases, set the mode to device this function should not
            // be called in OTG mode.
            //
            g_iUSBMode = eUSBModeDevice;
    
            //
            // Enable or disable LPM functionality.
            //
            if(g_psDCDInst[0].ui32Features & USBLIB_FEATURE_LPM_EN)
            {
                //
                // Enable full LPM support and all LPM related interrupts.
                // USB_INTLPM_ERROR is not enabled since there is no response to
                // this interrupt.
                //
                USBDevLPMConfig(USB0_BASE, USB_DEV_LPM_EN);
                USBLPMIntEnable(USB0_BASE, USB_INTLPM_RESUME | USB_INTLPM_ERROR |
                                           USB_INTLPM_ACK | USB_INTLPM_NYET);
                USBDevLPMEnable(USB0_BASE);
    
                //
                // Awake by default.
                //
                g_psDCDInst[0].ui32LPMState = USBLIB_LPM_STATE_AWAKE;
            }
            else
            {
                USBDevLPMDisable(USB0_BASE);
                USBDevLPMConfig(USB0_BASE, USB_DEV_LPM_NONE);
                g_psDCDInst[0].ui32LPMState = USBLIB_LPM_STATE_DISABLED;
            }
        }
    
        //
        // Initialize the USB DMA interface.
        //
        g_psDCDInst[0].psDMAInstance = USBLibDMAInit(0);
    
        //
        // Initialize the USB tick module.
        //
        InternalUSBTickInit();
    
        //
        // Get a pointer to the default configuration descriptor.
        //
        psHdr = psDevice->ppsConfigDescriptors[
                                    g_psDCDInst[0].ui32DefaultConfiguration - 1];
        psDesc = (const tConfigDescriptor *)(psHdr->psSections[0]->pui8Data);
    
        if((psDesc->bmAttributes & USB_CONF_ATTR_PWR_M) == USB_CONF_ATTR_SELF_PWR)
        {
            g_psDCDInst[0].ui8Status |= USB_STATUS_SELF_PWR;
        }
        else
        {
            g_psDCDInst[0].ui8Status &= ~USB_STATUS_SELF_PWR;
        }
    
        //
        // Only do hardware update if the stack is not in OTG mode.
        //
        if(g_iUSBMode != eUSBModeOTG)
        {
            //
            // Get the current interrupt status.to clear all pending USB
            // interrupts.
            //
            MAP_USBIntStatusControl(USB0_BASE);
            MAP_USBIntStatusEndpoint(USB0_BASE);
    
            //
            // Enable USB Interrupts.
            //
            MAP_USBIntEnableControl(USB0_BASE, USB_INTCTRL_RESET |
                                               USB_INTCTRL_DISCONNECT |
                                               USB_INTCTRL_RESUME |
                                               USB_INTCTRL_SUSPEND |
                                               USB_INTCTRL_SOF);
            MAP_USBIntEnableEndpoint(USB0_BASE, USB_INTEP_ALL);
    
            //
            // Attach the device using the soft connect.
            //
            MAP_USBDevConnect(USB0_BASE);
    
            //
            // Enable the USB interrupt.
            //
            OS_INT_ENABLE(g_psDCDInst[0].ui32IntNum);
        }
    }
    
    //*****************************************************************************
    //
    //! Free the USB library device control driver for a given hardware controller.
    //!
    //! \param ui32Index is the index of the USB controller which is to be
    //! freed.
    //!
    //! This function should be called by an application if it no longer requires
    //! the use of a given USB controller to support its operation as a USB device.
    //! It frees the controller for use by another client.
    //!
    //! It is the caller's responsibility to remove its device from the USB bus
    //! prior to calling this function.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDTerm(uint32_t ui32Index)
    {
        //
        // Check the arguments.
        //
        ASSERT(ui32Index == 0);
    
        //
        // Disable the USB interrupts.
        //
        OS_INT_DISABLE(g_psDCDInst[0].ui32IntNum);
    
        //
        // Reset the tick handlers so that they can be reconfigured when and if
        // USBDCDInit() is called.
        //
        InternalUSBTickReset();
    
        //
        // No active device.
        //
        g_ppsDevInfo[0] = 0;
    
        MAP_USBIntDisableControl(USB0_BASE, USB_INTCTRL_ALL);
        MAP_USBIntDisableEndpoint(USB0_BASE, USB_INTEP_ALL);
    
        //
        // Detach the device using the soft connect.
        //
        MAP_USBDevDisconnect(USB0_BASE);
    
        //
        // Clear any pending interrupts.
        //
        MAP_USBIntStatusControl(USB0_BASE);
        MAP_USBIntStatusEndpoint(USB0_BASE);
    
        //
        // Turn off USB Phy clock.
        //
        MAP_SysCtlUSBPLLDisable();
    
        //
        // Disable the USB peripheral
        //
        MAP_SysCtlPeripheralDisable(SYSCTL_PERIPH_USB0);
    }
    
    //*****************************************************************************
    //
    //! This function starts the request for data from the host on endpoint zero.
    //!
    //! \param ui32Index is the index of the USB controller from which the data
    //! is being requested.
    //! \param pui8Data is a pointer to the buffer to fill with data from the USB
    //! host.
    //! \param ui32Size is the size of the buffer or data to return from the USB
    //! host.
    //!
    //! This function handles retrieving data from the host when a custom command
    //! has been issued on endpoint zero.  If the application needs notification
    //! when the data has been received,
    //! <tt>psCallbacks->pfnDataReceived()</tt> in the tDeviceInfo structure
    //! must contain valid function pointer.  In nearly all cases this is necessary
    //! because the caller of this function would likely need to know that the data
    //! requested was received.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDRequestDataEP0(uint32_t ui32Index, uint8_t *pui8Data, uint32_t ui32Size)
    {
        ASSERT(ui32Index == 0);
    
        //
        // Enter the RX state on end point 0.
        //
        g_psDCDInst[0].iEP0State = eUSBStateRx;
    
        //
        // Save the pointer to the data.
        //
        g_psDCDInst[0].pui8EP0Data = pui8Data;
    
        //
        // Location to save the current number of bytes received.
        //
        g_psDCDInst[0].ui32OUTDataSize = ui32Size;
    
        //
        // Bytes remaining to be received.
        //
        g_psDCDInst[0].ui32EP0DataRemain = ui32Size;
    }
    
    //*****************************************************************************
    //
    //! This function requests transfer of data to the host on endpoint zero.
    //!
    //! \param ui32Index is the index of the USB controller which is to be used to
    //! send the data.
    //! \param pui8Data is a pointer to the buffer to send via endpoint zero.
    //! \param ui32Size is the amount of data to send in bytes.
    //!
    //! This function handles sending data to the host when a custom command is
    //! issued or non-standard descriptor has been requested on endpoint zero.  If
    //! the application needs notification when this is complete,
    //! <tt>psCallbacks->pfnDataSent</tt> in the tDeviceInfo structure must
    //! contain a valid function pointer.  This callback could be used to free up
    //! the buffer passed into this function in the \e pui8Data parameter.  The
    //! contents of the \e pui8Data buffer must remain unchanged until the
    //! <tt>pfnDataSent</tt> callback is received.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDSendDataEP0(uint32_t ui32Index, uint8_t *pui8Data, uint32_t ui32Size)
    {
        ASSERT(ui32Index == 0);
    
        //
        // Return the externally provided device descriptor.
        //
        g_psDCDInst[0].pui8EP0Data = pui8Data;
    
        //
        // The size of the device descriptor is in the first byte.
        //
        g_psDCDInst[0].ui32EP0DataRemain = ui32Size;
    
        //
        // Save the total size of the data sent.
        //
        g_psDCDInst[0].ui32OUTDataSize = ui32Size;
    
        //
        // Now in the transmit data state.
        //
        USBDEP0StateTx(0);
    }
    
    //*****************************************************************************
    //
    //! This function sets the default configuration for the device.
    //!
    //! \param ui32Index is the index of the USB controller whose default
    //! configuration is to be set.
    //! \param ui32DefaultConfig is the configuration identifier (byte 6 of the
    //! standard configuration descriptor) which is to be presented to the host
    //! as the default configuration in cases where the configuration descriptor is
    //! queried prior to any specific configuration being set.
    //!
    //! This function allows a device to override the default configuration
    //! descriptor that will be returned to a host whenever it is queried prior
    //! to a specific configuration having been set.  The parameter passed must
    //! equal one of the configuration identifiers found in the
    //! <tt>ppsConfigDescriptors</tt> array for the device.
    //!
    //! If this function is not called, the USB library will return the first
    //! configuration in the <tt>ppsConfigDescriptors</tt> array as the default
    //! configuration.
    //!
    //! \note The USB device stack assumes that the configuration IDs (byte 6 of
    //! the configuration descriptor, <tt>bConfigurationValue</tt>) stored within
    //! the configuration descriptor array, <tt>ppsConfigDescriptors</tt>,
    //! are equal to the array index + 1.  In other words, the first entry in the
    //! array must contain a descriptor with <tt>bConfigurationValue</tt> 1, the
    //! second must have <tt>bConfigurationValue</tt> 2 and so on.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDSetDefaultConfiguration(uint32_t ui32Index, uint32_t ui32DefaultConfig)
    {
        ASSERT(ui32Index == 0);
    
        g_psDCDInst[0].ui32DefaultConfiguration = ui32DefaultConfig;
    }
    
    //*****************************************************************************
    //
    //! This function generates a stall condition on endpoint zero.
    //!
    //! \param ui32Index is the index of the USB controller whose endpoint zero is
    //! to be stalled.
    //!
    //! This function is typically called to signal an error condition to the host
    //! when an unsupported request is received by the device.  It should be
    //! called from within the callback itself (in interrupt context) and not
    //! deferred until later since it affects the operation of the endpoint zero
    //! state machine in the USB library.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDStallEP0(uint32_t ui32Index)
    {
        ASSERT(ui32Index == 0);
    
        //
        // Stall the endpoint in question.
        //
        MAP_USBDevEndpointStall(USB0_BASE, USB_EP_0, USB_EP_DEV_OUT);
    
        //
        // Enter the stalled state.
        //
        g_psDCDInst[0].iEP0State = eUSBStateStall;
    }
    #ifndef DEPRECATED
    
    //*****************************************************************************
    //
    //! Reports the device power status (bus- or self-powered) to the library.
    //!
    //! \param ui32Index is the index of the USB controller whose device power
    //! status is being reported.
    //! \param ui8Power indicates the current power status, either
    //! \b USB_STATUS_SELF_PWR or \b USB_STATUS_BUS_PWR.
    //!
    //! Applications which support switching between bus- or self-powered
    //! operation should call this function whenever the power source changes
    //! to indicate the current power status to the USB library.  This information
    //! is required by the library to allow correct responses to be provided when
    //! the host requests status from the device.
    //!
    //! \return None.
    //
    //*****************************************************************************
    void
    USBDCDPowerStatusSet(uint32_t ui32Index, uint8_t ui8Power)
    {
        //
        // Check for valid parameters.
        //
        ASSERT((ui8Power == USB_STATUS_BUS_PWR) ||
               (ui8Power == USB_STATUS_SELF_PWR));
        ASSERT(ui32Index == 0);
    
        //
        // Update the device status with the new power status flag.
        //
        g_psDCDInst[0].bPwrSrcSet = true;
        g_psDCDInst[0].ui8Status &= ~USB_STATUS_PWR_M;
        g_psDCDInst[0].ui8Status |= ui8Power;
    }
    #endif
    
    //*****************************************************************************
    //
    //! This function is used to enable/disable features of the USB library.
    //!
    //! \param ui32Index is the index of the USB controller whose device power
    //! status is being reported.
    //! \param ui32Feature indicates which feature is being changed.
    //! \param pvFeature holds the data that controls the feature request.
    //!
    //! Applications can change the support levels of some USB library features by
    //! calling this function to enable/disable certain features.  This function
    //! should normally be called before class initialization functions since the
    //! settings need to be in place before enumeration starts.  This allows the
    //! USB library to properly respond to all enumeration requests. The
    //! \e ui32Feature value is one of the \b USBLIB_FEATURE_* defines which
    //! controls the type of request being made.  The \e pvFeature is a feature
    //! specific data structure that is determined by the value passed in the
    //! \e ui32Feature parameter.
    //!
    //! \return Returns \b true if the feature was successfully changed and returns
    //! \b false if the feature was not able to be changed or is not supported.
    //
    //*****************************************************************************
    bool
    USBDCDFeatureSet(uint32_t ui32Index, uint32_t ui32Feature, void *pvFeature)
    {
        bool bRetCode;
        tLPMFeature *psLPMFeature;
    
        bRetCode = true;
    
        switch(ui32Feature)
        {
            case USBLIB_FEATURE_LPM:
            {
                //
                // Save the LPM setting.
                //
                psLPMFeature = (tLPMFeature *)pvFeature;
    
                if(psLPMFeature->ui32Features & USBLIB_FEATURE_LPM_EN)
                {
                    g_psDCDInst[0].ui32Features |= USBLIB_FEATURE_LPM_EN;
                }
                else
                {
                    g_psDCDInst[0].ui32Features &= ~USBLIB_FEATURE_LPM_EN;
                }
    
                break;
            }
            case USBLIB_FEATURE_USBPLL:
            {
                //
                // If the PLL rate is not evenly divisible by 60MHz then
                // do not set it.
                //
                if((*(uint32_t *)pvFeature % 60000000) != 0)
                {
                    bRetCode = false;
                }
                else
                {
                    //
                    // Save the new PLL rate.
                    //
                    g_ui32PLLDiv = (*(uint32_t *)pvFeature / 60000000);
                }
                break;
            }
            case USBLIB_FEATURE_USBULPI:
            {
                //
                // Save the ULPI support level.
                //
                g_ui32ULPISupport = *(uint32_t *)pvFeature;
    
                break;
            }
            case USBLIB_FEATURE_POWER:
            {
                //
                // Update the device status with the new power status flag.
                //
                g_psDCDInst[0].bPwrSrcSet = true;
                g_psDCDInst[0].ui8Status &= ~USBLIB_FEATURE_POWER_SELF;
                g_psDCDInst[0].ui8Status |= (uint8_t)(*(uint32_t *)pvFeature);
    
                break;
            }
            default:
            {
                bRetCode = false;
                break;
            }
        }
        return(bRetCode);
    }
    
    //*****************************************************************************
    //
    //! This function is used to get the features of the USB library.
    //!
    //! \param ui32Index is the index of the USB controller whose device power
    //! status is being reported.
    //! \param ui32Feature indicates which feature is being requested.
    //! \param pvFeature holds the data that will be reported for the feature
    //! request.
    //!
    //! Applications can query the support levels of some USB library features by
    //! calling this function to get values of the features.  This function
    //! should normally be called before class initialization functions since the
    //! settings need to be in place during enumeration.  This allows the
    //! USB library to properly respond to all enumeration requests. The
    //! \e ui32Feature value is one of the \b USBLIB_FEATURE_* defines which
    //! controls the type of request being made.  The \e pvFeature is a feature
    //! specific data structure that is determined by the value passed in the
    //! \e ui32Feature parameter.
    //!
    //! \return Returns \b true if the feature was requested for ULPI and returns
    //! \b false if the feature was not for ULPI interface.
    //
    //*****************************************************************************
    bool
    USBDCDFeatureGet(uint32_t ui32Index, uint32_t ui32Feature, void *pvFeature)
    {
        bool bRetCode = true;
    
        switch (ui32Feature)
        {
            case USBLIB_FEATURE_USBULPI:
            {
                //
                // Save the ULPI support level.
                //
                *(uint32_t *)pvFeature = g_ui32ULPISupport;
                
                break;
            }
            default:
            {
                 bRetCode = false;
                 break;
            }
        }
        return(bRetCode);
    }
    
    //*****************************************************************************
    //
    //! Requests an LPM remote wake up to resume communication when in an LPM sleep
    //! state.
    //!
    //! \param ui32Index is the index of the USB controller that will request
    //! a bus wake up.
    //!
    //! When the host controller puts the device into an LPM sleep state, the
    //! device can call this function to initiate LPM remote wake up signaling to
    //! the host.  If the remote wake up feature has been enabled by the host, this
    //! will cause the host to respond to the LPM remote wake request and resume
    //! normal operation.  If the host has disabled remote wake up, \b false is
    //! returned to indicate that the wake up request was not successful.
    //!
    //! \return Returns \b true if the remote wake up request has been sent or
    //!\b false if LPM remote wake up is disabled.
    //
    //*****************************************************************************
    bool
    USBDCDRemoteWakeLPM(uint32_t ui32Index)
    {
        if(USBLPMRemoteWakeEnabled(USB0_BASE))
        {
            USBDevLPMRemoteWake(USB0_BASE);
            return(true);
        }
        return(false);
    }
    
    //*****************************************************************************
    //
    //! Requests a remote wake up to resume communication when in suspended state.
    //!
    //! \param ui32Index is the index of the USB controller that will request
    //! a bus wake up.
    //!
    //! When the bus is suspended, an application which supports remote wake up
    //! (advertised to the host via the configuration descriptor) may call this
    //! function to initiate remote wake up signaling to the host.  If the remote
    //! wake up feature has not been disabled by the host, this will cause the bus
    //! to resume operation within 20mS.  If the host has disabled remote wake up,
    //! \b false will be returned to indicate that the wake up request was not
    //! successful.
    //!
    //! \return Returns \b true if the remote wake up is not disabled and the
    //! signaling was started or \b false if remote wake up is disabled or if
    //! signaling is currently ongoing following a previous call to this function.
    //
    //*****************************************************************************
    bool
    USBDCDRemoteWakeupRequest(uint32_t ui32Index)
    {
        //
        // Check for parameter validity.
        //
        ASSERT(ui32Index == 0);
    
        //
        // Is remote wake up signaling currently enabled?
        //
        if(g_psDCDInst[0].ui8Status & USB_STATUS_REMOTE_WAKE)
        {
            //
            // The host has not disabled remote wake up. Are we still in the
            // middle of a previous wake up sequence?
            //
            if(!g_psDCDInst[0].bRemoteWakeup)
            {
                //
                // No - we are not in the middle of a wake up sequence so start
                // one here.
                //
                g_psDCDInst[0].ui8RemoteWakeupCount = 0;
                g_psDCDInst[0].bRemoteWakeup = true;
                MAP_USBHostResume(USB0_BASE, true);
                return(true);
            }
        }
    
        //
        // If we drop through to here, signaling was not initiated so return
        // false.
        return(false);
    }
    
    //*****************************************************************************
    //
    // Internal Functions, not to be called by applications
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // This internal function is called on the SOF interrupt to process any
    // outstanding remote wake up requests.
    //
    // \return None.
    //
    //*****************************************************************************
    void
    USBDeviceResumeTickHandler(tDCDInstance *psDevInst)
    {
        if(g_psDCDInst[0].bRemoteWakeup)
        {
            //
            // Increment the millisecond counter we use to time the resume
            // signaling.
            //
            g_psDCDInst[0].ui8RemoteWakeupCount++;
    
            //
            // Have we reached the 10mS mark? If so, we need to turn the signaling
            // off again.
            //
            if(g_psDCDInst[0].ui8RemoteWakeupCount == REMOTE_WAKEUP_PULSE_MS)
            {
                MAP_USBHostResume(USB0_BASE, false);
            }
    
            //
            // Have we reached the point at which we can tell the client that the
            // bus has resumed? The controller does not give us an interrupt if we
            // initiated the wake up signaling so we just wait until 20mS have
            // passed then tell the client all is well.
            //
            if(g_psDCDInst[0].ui8RemoteWakeupCount == REMOTE_WAKEUP_READY_MS)
            {
                //
                // We are now finished with the remote wake up signaling.
                //
                g_psDCDInst[0].bRemoteWakeup = false;
    
                //
                // If the client has registered a resume callback, call it.  In the
                // case of a remote wake up request, we do not get a resume
                // interrupt from the controller so we need to fake it here.
                //
                if(g_ppsDevInfo[0]->psCallbacks->pfnResumeHandler)
                {
                    g_ppsDevInfo[0]->psCallbacks->pfnResumeHandler(
                                                        g_psDCDInst[0].pvCBData);
                }
            }
        }
    }
    
    //*****************************************************************************
    //
    // This internal function reads a request data packet and dispatches it to
    // either a standard request handler or the registered device request
    // callback depending upon the request type.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDReadAndDispatchRequest(uint32_t ui32Index)
    {
        uint32_t ui32Size;
        tUSBRequest *psRequest;
    
        //
        // Cast the buffer to a request structure.
        //
        psRequest = (tUSBRequest *)g_pui8DataBufferIn;
    
        //
        // Set the buffer size.
        //
        ui32Size = EP0_MAX_PACKET_SIZE;
    
        //
        // Get the data from the USB controller end point 0.
        //
        MAP_USBEndpointDataGet(USB0_BASE, USB_EP_0, g_pui8DataBufferIn,
                               &ui32Size);
    
        //
        // If there was a null setup packet then just return.
        //
        if(!ui32Size)
        {
            return;
        }
    
        //
        // See if this is a standard request or not.
        //
        if((psRequest->bmRequestType & USB_RTYPE_TYPE_M) != USB_RTYPE_STANDARD)
        {
            //
            // Since this is not a standard request, see if there is
            // an external handler present.
            //
            if(g_ppsDevInfo[0]->psCallbacks->pfnRequestHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnRequestHandler(
                                                        g_psDCDInst[0].pvCBData,
                                                        psRequest);
            }
            else
            {
                //
                // If there is no handler then stall this request.
                //
                USBDCDStallEP0(0);
            }
        }
        else
        {
            //
            // Assure that the jump table is not out of bounds.
            //
            if((psRequest->bRequest <
               (sizeof(g_psUSBDStdRequests) / sizeof(tStdRequest))) &&
               (g_psUSBDStdRequests[psRequest->bRequest] != 0))
            {
                //
                // Jump table to the appropriate handler.
                //
                g_psUSBDStdRequests[psRequest->bRequest](&g_psDCDInst[0],
                                                         psRequest);
            }
            else
            {
                //
                // If there is no handler then stall this request.
                //
                USBDCDStallEP0(0);
            }
        }
    }
    
    //*****************************************************************************
    //
    // This is interrupt handler for endpoint zero.
    //
    // This function handles all interrupts on endpoint zero in order to maintain
    // the state needed for the control endpoint on endpoint zero.  In order to
    // successfully enumerate and handle all USB standard requests, all requests
    // on endpoint zero must pass through this function.  The endpoint has the
    // following states: \b eUSBStateIdle, \b eUSBStateTx, \b eUSBStateRx,
    // \b eUSBStateStall, and \b eUSBStateStatus.  In the \b eUSBStateIdle
    // state the USB controller has not received the start of a request, and once
    // it does receive the data for the request it will either enter the
    // \b eUSBStateTx, \b eUSBStateRx, or \b eUSBStateStall depending on the
    // command.  If the controller enters the \b eUSBStateTx or \b eUSBStateRx
    // then once all data has been sent or received, it must pass through the
    // \b eUSBStateStatus state to allow the host to acknowledge completion of
    // the request.  The \b eUSBStateStall is entered from \b eUSBStateIdle in
    // the event that the USB request was not valid.  Both the \b eUSBStateStall
    // and \b eUSBStateStatus are transitional states that return to the
    // \b eUSBStateIdle state.
    //
    // \return None.
    //
    // eUSBStateIdle -*--> eUSBStateTx -*-> eUSBStateStatus -*->eUSBStateIdle
    //                |                 |                    |
    //                |--> eUSBStateRx                       |
    //                |                                      |
    //                |--> eUSBStateStall ---------->--------
    //
    //  ----------------------------------------------------------------
    // | Current State       | State 0           | State 1              |
    // | --------------------|-------------------|----------------------
    // | eUSBStateIdle       | eUSBStateTx/RX    | eUSBStateStall       |
    // | eUSBStateTx         | eUSBStateStatus   |                      |
    // | eUSBStateRx         | eUSBStateStatus   |                      |
    // | eUSBStateStatus     | eUSBStateIdle     |                      |
    // | eUSBStateStall      | eUSBStateIdle     |                      |
    //  ----------------------------------------------------------------
    //
    //*****************************************************************************
    void
    USBDeviceEnumHandler(tDCDInstance *pDevInstance)
    {
        uint32_t ui32EPStatus, ui32DataSize;
    
        //
        // Get the end point 0 status.
        //
        ui32EPStatus = MAP_USBEndpointStatus(USB0_BASE, USB_EP_0);
    
        switch(pDevInstance->iEP0State)
        {
            //
            // Handle the status state, this is a transitory state from
            // eUSBStateTx or eUSBStateRx back to eUSBStateIdle.
            //
            case eUSBStateStatus:
            {
                //
                // Just go back to the idle state.
                //
                pDevInstance->iEP0State = eUSBStateIdle;
    
                //
                // If there is a pending address change then set the address.
                //
                if(pDevInstance->ui32DevAddress & DEV_ADDR_PENDING)
                {
                    //
                    // Clear the pending address change and set the address.
                    //
                    pDevInstance->ui32DevAddress &= ~DEV_ADDR_PENDING;
                    MAP_USBDevAddrSet(USB0_BASE, pDevInstance->ui32DevAddress);
                }
    
                //
                // If a new packet is already pending, we need to read it
                // and handle whatever request it contains.
                //
                if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY)
                {
                    //
                    // Process the newly arrived packet.
                    //
                    USBDReadAndDispatchRequest(0);
                }
                break;
            }
    
            //
            // In the IDLE state the code is waiting to receive data from the host.
            //
            case eUSBStateIdle:
            {
                //
                // Is there a packet waiting for us?
                //
                if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY)
                {
                    //
                    // Yes - process it.
                    //
                    USBDReadAndDispatchRequest(0);
                }
                break;
            }
    
            //
            // Data is still being sent to the host so handle this in the
            // EP0StateTx() function.
            //
            case eUSBStateTx:
            {
                USBDEP0StateTx(0);
                break;
            }
    
            //
            // We are still in the middle of sending the configuration descriptor
            // so handle this in the EP0StateTxConfig() function.
            //
            case eUSBStateTxConfig:
            {
                USBDEP0StateTxConfig(0);
                break;
            }
    
            //
            // Handle the receive state for commands that are receiving data on
            // endpoint zero.
            //
            case eUSBStateRx:
            {
                //
                // Set the number of bytes to get out of this next packet.
                //
                if(pDevInstance->ui32EP0DataRemain > EP0_MAX_PACKET_SIZE)
                {
                    //
                    // Don't send more than EP0_MAX_PACKET_SIZE bytes.
                    //
                    ui32DataSize = EP0_MAX_PACKET_SIZE;
                }
                else
                {
                    //
                    // There was space so send the remaining bytes.
                    //
                    ui32DataSize = pDevInstance->ui32EP0DataRemain;
                }
    
                //
                // Get the data from the USB controller end point 0.
                //
                MAP_USBEndpointDataGet(USB0_BASE, USB_EP_0,
                                       pDevInstance->pui8EP0Data, &ui32DataSize);
    
                //
                // If there we not more that EP0_MAX_PACKET_SIZE or more bytes
                // remaining then this transfer is complete.  If there were exactly
                // EP0_MAX_PACKET_SIZE remaining then there still needs to be
                // null packet sent before this is complete.
                //
                if(pDevInstance->ui32EP0DataRemain < EP0_MAX_PACKET_SIZE)
                {
                    //
                    // Return to the idle state.
                    //
                    pDevInstance->iEP0State =  eUSBStateStatus;
    
                    //
                    // If there is a receive callback then call it.
                    //
                    if((g_ppsDevInfo[0]->psCallbacks->pfnDataReceived) &&
                       (pDevInstance->ui32OUTDataSize != 0))
                    {
                        //
                        // Call the custom receive handler to handle the data
                        // that was received.
                        //
                        g_ppsDevInfo[0]->psCallbacks->pfnDataReceived(
                                                    g_psDCDInst[0].pvCBData,
                                                    pDevInstance->ui32OUTDataSize);
    
                        //
                        // Indicate that there is no longer any data being waited
                        // on.
                        //
                        pDevInstance->ui32OUTDataSize = 0;
                    }
    
                    //
                    // Need to ACK the data on end point 0 in this case and set the
                    // data end as this is the last of the data.
                    //
                    MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
                }
                else
                {
                    //
                    // Need to ACK the data on end point 0 in this case
                    // without setting data end because more data is coming.
                    //
                    MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
                }
    
                //
                // Advance the pointer.
                //
                pDevInstance->pui8EP0Data += ui32DataSize;
    
                //
                // Decrement the number of bytes that are being waited on.
                //
                pDevInstance->ui32EP0DataRemain -= ui32DataSize;
    
                break;
            }
            //
            // The device stalled endpoint zero so check if the stall needs to be
            // cleared once it has been successfully sent.
            //
            case eUSBStateStall:
            {
                //
                // If we sent a stall then acknowledge this interrupt.
                //
                if(ui32EPStatus & USB_DEV_EP0_SENT_STALL)
                {
                    //
                    // Clear the Setup End condition.
                    //
                    MAP_USBDevEndpointStatusClear(USB0_BASE, USB_EP_0,
                                                  USB_DEV_EP0_SENT_STALL);
    
                    //
                    // Reset the global end point 0 state to IDLE.
                    //
                    pDevInstance->iEP0State = eUSBStateIdle;
    
                }
                break;
            }
            //
            // Halt on an unknown state, but only in DEBUG mode builds.
            //
            default:
            {
                ASSERT(0);
                break;
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function handles bus reset notifications.
    //
    // This function is called from the low level USB interrupt handler whenever
    // a bus reset is detected.  It performs tidy-up as required and resets the
    // configuration back to defaults in preparation for descriptor queries from
    // the host.
    //
    // \return None.
    //
    //*****************************************************************************
    void
    USBDeviceEnumResetHandler(tDCDInstance *pDevInstance)
    {
        uint32_t ui32Loop;
    
        //
        // Disable remote wake up signaling (as per USB 2.0 spec 9.1.1.6).
        //
        pDevInstance->ui8Status &= ~USB_STATUS_REMOTE_WAKE;
        pDevInstance->bRemoteWakeup = false;
    
        //
        // Call the device dependent code to indicate a bus reset has occurred.
        //
        if(g_ppsDevInfo[0]->psCallbacks->pfnResetHandler)
        {
            g_ppsDevInfo[0]->psCallbacks->pfnResetHandler(g_psDCDInst[0].pvCBData);
        }
    
        //
        // Reset the default configuration identifier and alternate function
        // selections.
        //
        pDevInstance->ui32Configuration = pDevInstance->ui32DefaultConfiguration;
    
        for(ui32Loop = 0; ui32Loop < USB_MAX_INTERFACES_PER_DEVICE; ui32Loop++)
        {
            pDevInstance->pui8AltSetting[ui32Loop] = (uint8_t)0;
        }
    }
    
    //*****************************************************************************
    //
    // This function handles the GET_STATUS standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the request type and endpoint number if endpoint
    // status is requested.
    //
    // This function handles responses to a Get Status request from the host
    // controller.  A status request can be for the device, an interface or an
    // endpoint.  If any other type of request is made this function will cause
    // a stall condition to indicate that the command is not supported.  The
    // \e psUSBRequest structure holds the type of the request in the
    // bmRequestType field.  If the type indicates that this is a request for an
    // endpoint's status, then the wIndex field holds the endpoint number.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDGetStatus(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        uint16_t ui16Data, ui16Index;
        uint32_t ui32Dir;
        tDCDInstance *psUSBControl;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
    
        //
        // Need to ACK the data on end point 0 without setting last data as there
        // will be a data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
    
        //
        // Determine what type of status was requested.
        //
        switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
        {
            //
            // This was a Device Status request.
            //
            case USB_RTYPE_DEVICE:
            {
                //
                // Return the current status for the device.
                //
                ui16Data = (uint16_t)psUSBControl->ui8Status;
    
                break;
            }
    
            //
            // This was a Interface status request.
            //
            case USB_RTYPE_INTERFACE:
            {
                //
                // Interface status always returns 0.
                //
                ui16Data = (uint16_t)0;
    
                break;
            }
    
            //
            // This was an endpoint status request.
            //
            case USB_RTYPE_ENDPOINT:
            {
                //
                // Which endpoint are we dealing with?
                //
                ui16Index = psUSBRequest->wIndex & USB_REQ_EP_NUM_M;
    
                //
                // Check if this was a valid endpoint request.
                //
                if((ui16Index == 0) || (ui16Index >= NUM_USB_EP))
                {
                    USBDCDStallEP0(0);
                    return;
                }
                else
                {
                    //
                    // Are we dealing with an IN or OUT endpoint?
                    //
                    ui32Dir = ((psUSBRequest->wIndex & USB_REQ_EP_DIR_M) ==
                               USB_REQ_EP_DIR_IN) ? HALT_EP_IN : HALT_EP_OUT;
    
                    //
                    // Get the current halt status for this endpoint.
                    //
                    ui16Data =
                        (uint16_t)psUSBControl->ppui8Halt[ui32Dir][ui16Index - 1];
                }
                break;
            }
    
            //
            // This was an unknown request.
            //
            default:
            {
                //
                // Anything else causes a stall condition to indicate that the
                // command was not supported.
                //
                USBDCDStallEP0(0);
                return;
            }
        }
    
        //
        // Send the two byte status response.
        //
        psUSBControl->ui32EP0DataRemain = 2;
        psUSBControl->pui8EP0Data = (uint8_t *)&ui16Data;
    
        //
        // Send the response.
        //
        USBDEP0StateTx(0);
    }
    
    //*****************************************************************************
    //
    // This function handles the CLEAR_FEATURE standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the options for the Clear Feature USB request.
    //
    // This function handles device or endpoint clear feature requests.  The
    // \e psUSBRequest structure holds the type of the request in the bmRequestType
    // field and the feature is held in the wValue field.  The device can only
    // clear the Remote Wake feature.  This device request should only be made if
    // the descriptor indicates that Remote Wake is implemented by the device.
    // Endpoints can only clear a halt on a given endpoint.  If any other
    // requests are made, then the device will stall the request to indicate to
    // the host that the command was not supported.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDClearFeature(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        tDCDInstance *psUSBControl;
        uint32_t ui32Dir;
        uint16_t ui16Index;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
    
        //
        // Need to ACK the data on end point 0 with last data set as this has no
        // data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
    
        //
        // Determine what type of status was requested.
        //
        switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
        {
            //
            // This is a clear feature request at the device level.
            //
            case USB_RTYPE_DEVICE:
            {
                //
                // Only remote wake is can be cleared by this function.
                //
                if(USB_FEATURE_REMOTE_WAKE & psUSBRequest->wValue)
                {
                    //
                    // Clear the remote wake up state.
                    //
                    psUSBControl->ui8Status &= ~USB_STATUS_REMOTE_WAKE;
                }
                else
                {
                    USBDCDStallEP0(0);
                }
                break;
            }
    
            //
            // This is a clear feature request at the endpoint level.
            //
            case USB_RTYPE_ENDPOINT:
            {
                //
                // Which endpoint are we dealing with?
                //
                ui16Index = psUSBRequest->wIndex & USB_REQ_EP_NUM_M;
    
                //
                // Not a valid endpoint.
                //
                if((ui16Index == 0) || (ui16Index > NUM_USB_EP))
                {
                    USBDCDStallEP0(0);
                }
                else
                {
                    //
                    // Only the halt feature is supported.
                    //
                    if(USB_FEATURE_EP_HALT == psUSBRequest->wValue)
                    {
                        //
                        // Are we dealing with an IN or OUT endpoint?
                        //
                        ui32Dir = ((psUSBRequest->wIndex & USB_REQ_EP_DIR_M) ==
                                   USB_REQ_EP_DIR_IN) ? HALT_EP_IN : HALT_EP_OUT;
    
                        //
                        // Clear the halt condition on this endpoint.
                        //
                        psUSBControl->ppui8Halt[ui32Dir][ui16Index - 1] = 0;
    
                        if(ui32Dir == HALT_EP_IN)
                        {
                            MAP_USBDevEndpointStallClear(USB0_BASE,
                                                         IndexToUSBEP(ui16Index),
                                                         USB_EP_DEV_IN);
                        }
                        else
                        {
                            MAP_USBDevEndpointStallClear(USB0_BASE,
                                                         IndexToUSBEP(ui16Index),
                                                         USB_EP_DEV_OUT);
                        }
                    }
                    else
                    {
                        //
                        // If any other feature is requested, this is an error.
                        //
                        USBDCDStallEP0(0);
                        return;
                    }
                }
                break;
            }
    
            //
            // This is an unknown request.
            //
            default:
            {
                USBDCDStallEP0(0);
                return;
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_FEATURE standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the feature in the wValue field of the USB
    // request.
    //
    // This function handles device or endpoint set feature requests.  The
    // \e psUSBRequest structure holds the type of the request in the bmRequestType
    // field and the feature is held in the wValue field.  The device can only
    // set the Remote Wake feature.  This device request should only be made if the
    // descriptor indicates that Remote Wake is implemented by the device.
    // Endpoint requests can only issue a halt on a given endpoint.  If any other
    // requests are made, then the device will stall the request to indicate to the
    // host that the command was not supported.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetFeature(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        tDCDInstance *psUSBControl;
        uint16_t ui16Index;
        uint32_t ui32Dir;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
    
        //
        // Need to ACK the data on end point 0 with last data set as this has no
        // data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
    
        //
        // Determine what type of status was requested.
        //
        switch(psUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
        {
            //
            // This is a set feature request at the device level.
            //
            case USB_RTYPE_DEVICE:
            {
                //
                // Only remote wake is the only feature that can be set by this
                // function.
                //
                if(USB_FEATURE_REMOTE_WAKE & psUSBRequest->wValue)
                {
                    //
                    // Set the remote wake up state.
                    //
                    psUSBControl->ui8Status |= USB_STATUS_REMOTE_WAKE;
                }
                else
                {
                    USBDCDStallEP0(0);
                }
                break;
            }
    
            //
            // This is a set feature request at the endpoint level.
            //
            case USB_RTYPE_ENDPOINT:
            {
                //
                // Which endpoint are we dealing with?
                //
                ui16Index = psUSBRequest->wIndex & USB_REQ_EP_NUM_M;
    
                //
                // Not a valid endpoint?
                //
                if((ui16Index == 0) || (ui16Index >= NUM_USB_EP))
                {
                    USBDCDStallEP0(0);
                }
                else
                {
                    //
                    // Only the Halt feature can be set.
                    //
                    if(USB_FEATURE_EP_HALT == psUSBRequest->wValue)
                    {
                        //
                        // Are we dealing with an IN or OUT endpoint?
                        //
                        ui32Dir = ((psUSBRequest->wIndex & USB_REQ_EP_DIR_M) ==
                                   USB_REQ_EP_DIR_IN) ? HALT_EP_IN : HALT_EP_OUT;
    
                        //
                        // Clear the halt condition on this endpoint.
                        //
                        psUSBControl->ppui8Halt[ui32Dir][ui16Index - 1] = 1;
                    }
                    else
                    {
                        //
                        // No other requests are supported.
                        //
                        USBDCDStallEP0(0);
                        return;
                    }
                }
                break;
            }
    
            //
            // This is an unknown request.
            //
            default:
            {
                USBDCDStallEP0(0);
                return;
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_ADDRESS standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the new address to use in the wValue field of the
    // USB request.
    //
    // This function is called to handle the change of address request from the
    // host controller.  This can only start the sequence as the host must
    // acknowledge that the device has changed address.  Thus this function sets
    // the address change as pending until the status phase of the request has
    // been completed successfully.  This prevents the devices address from
    // changing and not properly responding to the status phase.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetAddress(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        tDCDInstance *psUSBControl;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
    
        //
        // Need to ACK the data on end point 0 with last data set as this has no
        // data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
    
        //
        // Save the device address as we cannot change address until the status
        // phase is complete.
        //
        psUSBControl->ui32DevAddress = psUSBRequest->wValue | DEV_ADDR_PENDING;
    
        //
        // Transition directly to the status state since there is no data phase
        // for this request.
        //
        psUSBControl->iEP0State = eUSBStateStatus;
    }
    
    //*****************************************************************************
    //
    // This function handles the GET_DESCRIPTOR standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This function will return most of the descriptors requested by the host
    // controller.  The descriptor specified by \e
    // pvInstance->psInfo->pui8DeviceDescriptor will be returned when the device
    // descriptor is requested.  If a request for a specific configuration
    // descriptor is made, then the appropriate descriptor from the \e
    // g_pConfigDescriptors will be returned.  When a request for a string
    // descriptor is made, the appropriate string from the
    // \e pvInstance->psInfo->pStringDescriptors will be returned.  If the
    // \e pvInstance->psInfo->psCallbacks->GetDescriptor is specified it will be
    // called to handle the request.  In this case it must call the
    // USBDCDSendDataEP0() function to send the data to the host controller.  If
    // the callback is not specified, and the descriptor request is not for a
    // device, configuration, or string descriptor then this function will stall
    // the request to indicate that the request was not supported by the device.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDGetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        bool bConfig;
        tDCDInstance *psUSBControl;
        tDeviceInfo *psDevice;
        const tConfigHeader *psConfig;
        const tDeviceDescriptor *psDeviceDesc;
        uint8_t ui8Index;
        int32_t i32Index;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
        psDevice = g_ppsDevInfo[0];
    
        //
        // Need to ACK the data on end point 0 without setting last data as there
        // will be a data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
    
        //
        // Assume we are not sending the configuration descriptor until we
        // determine otherwise.
        //
        bConfig = false;
    
        //
        // Which descriptor are we being asked for?
        //
        switch(psUSBRequest->wValue >> 8)
        {
            //
            // This request was for a device descriptor.
            //
            case USB_DTYPE_DEVICE:
            {
                //
                // Return the externally provided device descriptor.
                //
                psUSBControl->pui8EP0Data =
                                        (uint8_t *)psDevice->pui8DeviceDescriptor;
    
                //
                // The size of the device descriptor is in the first byte.
                //
                psUSBControl->ui32EP0DataRemain =
                    psDevice->pui8DeviceDescriptor[0];
    
                break;
            }
    
            //
            // This request was for a configuration descriptor.
            //
            case USB_DTYPE_CONFIGURATION:
            {
                //
                // Which configuration are we being asked for?
                //
                ui8Index = (uint8_t)(psUSBRequest->wValue & 0xFF);
    
                //
                // Is this valid?
                //
                psDeviceDesc =
                    (const tDeviceDescriptor *)psDevice->pui8DeviceDescriptor;
    
                if(ui8Index >= psDeviceDesc->bNumConfigurations)
                {
                    //
                    // This is an invalid configuration index.  Stall EP0 to
                    // indicate a request error.
                    //
                    USBDCDStallEP0(0);
                    psUSBControl->pui8EP0Data = 0;
                    psUSBControl->ui32EP0DataRemain = 0;
                }
                else
                {
                    //
                    // Return the externally specified configuration descriptor.
                    //
                    psConfig = psDevice->ppsConfigDescriptors[ui8Index];
    
                    //
                    // Start by sending data from the beginning of the first
                    // descriptor.
                    //
                    psUSBControl->ui8ConfigSection = 0;
                    psUSBControl->ui16SectionOffset = 0;
                    psUSBControl->pui8EP0Data =
                                    (uint8_t *)psConfig->psSections[0]->pui8Data;
    
                    //
                    // Determine the total size of the configuration descriptor
                    // by counting the sizes of the sections comprising it.
                    //
                    psUSBControl->ui32EP0DataRemain =
                                                USBDCDConfigDescGetSize(psConfig);
    
                    //
                    // Remember that we need to send the configuration descriptor
                    // and which descriptor we need to send.
                    //
                    psUSBControl->ui8ConfigIndex = ui8Index;
    
                    bConfig = true;
                }
                break;
            }
    
            //
            // This request was for a string descriptor.
            //
            case USB_DTYPE_STRING:
            {
                //
                // Determine the correct descriptor index based on the requested
                // language ID and index.
                //
                i32Index = USBDStringIndexFromRequest(psUSBRequest->wIndex,
                                                      psUSBRequest->wValue & 0xFF);
    
                //
                // If the mapping function returned -1 then stall the request to
                // indicate that the request was not valid.
                //
                if(i32Index == -1)
                {
                    USBDCDStallEP0(0);
                    break;
                }
    
                //
                // Return the externally specified configuration descriptor.
                //
                psUSBControl->pui8EP0Data =
                    (uint8_t *)psDevice->ppui8StringDescriptors[i32Index];
    
                //
                // The total size of a string descriptor is in byte 0.
                //
                psUSBControl->ui32EP0DataRemain =
                    psDevice->ppui8StringDescriptors[i32Index][0];
    
                break;
            }
    
            //
            // Any other request is not handled by the default enumeration handler
            // so see if it needs to be passed on to another handler.
            //
            default:
            {
                //
                // If there is a handler for requests that are not handled then
                // call it.
                //
                if(psDevice->psCallbacks->pfnGetDescriptor)
                {
                    psDevice->psCallbacks->pfnGetDescriptor(g_psDCDInst[0].pvCBData,
                                                          psUSBRequest);
                }
                else
                {
                    //
                    // Whatever this was this handler does not understand it so
                    // just stall the request.
                    //
                    USBDCDStallEP0(0);
                }
    
                return;
            }
        }
    
        //
        // If this request has data to send, then send it.
        //
        if(psUSBControl->pui8EP0Data)
        {
            //
            // If there is more data to send than is requested then just
            // send the requested amount of data.
            //
            if(psUSBControl->ui32EP0DataRemain > psUSBRequest->wLength)
            {
                psUSBControl->ui32EP0DataRemain = psUSBRequest->wLength;
            }
    
            //
            // Now in the transmit data state.  Be careful to call the correct
            // function since we need to handle the configuration descriptor
            // differently from the others.
            //
            if(!bConfig)
            {
                USBDEP0StateTx(0);
            }
            else
            {
                USBDEP0StateTxConfig(0);
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function determines which string descriptor to send to satisfy a
    // request for a given index and language.
    //
    // \param ui16Lang is the requested string language ID.
    // \param ui16Index is the requested string descriptor index.
    //
    // When a string descriptor is requested, the host provides a language ID and
    // index to identify the string ("give me string number 5 in French").  This
    // function maps these two parameters to an index within our device's string
    // descriptor array which is arranged as multiple groups of strings with
    // one group for each language advertised via string descriptor 0.
    //
    // We assume that there are an equal number of strings per language and
    // that the first descriptor is the language descriptor and use this fact to
    // perform the mapping.
    //
    // \return The index of the string descriptor to return or -1 if the string
    // could not be found.
    //
    //*****************************************************************************
    static int32_t
    USBDStringIndexFromRequest(uint16_t ui16Lang, uint16_t ui16Index)
    {
        tString0Descriptor *pLang;
        uint32_t ui32NumLangs, ui32NumStringi16PerLang, ui32Loop;
    
        //
        // Make sure we have a string table at all.
        //
        if((g_ppsDevInfo[0] == 0) ||
           (g_ppsDevInfo[0]->ppui8StringDescriptors == 0))
        {
            return(-1);
        }
    
        //
        // First look for the trivial case where descriptor 0 is being
        // requested.  This is the special case since descriptor 0 contains the
        // language codes supported by the device.
        //
        if(ui16Index == 0)
        {
            return(0);
        }
    
        //
        // How many languages does this device support?  This is determined by
        // looking at the length of the first descriptor in the string table,
        // subtracting 2 for the header and dividing by two (the size of each
        // language code).
        //
        ui32NumLangs =
                (g_ppsDevInfo[0]->ppui8StringDescriptors[0][0] - 2) / 2;
    
        //
        // We assume that the table includes the same number of strings for each
        // supported language.  We know the number of entries in the string table,
        // so how many are there for each language?  This may seem an odd way to
        // do this (why not just have the application tell us in the device info
        // structure?) but it's needed since we didn't want to change the API
        // after the first release which did not support multiple languages.
        //
        ui32NumStringi16PerLang =
            ((g_ppsDevInfo[0]->ui32NumStringDescriptors - 1) /ui32NumLangs);
    
        //
        // Just to be sure, make sure that the calculation indicates an equal
        // number of strings per language.  We expect the string table to contain
        // (1 + (strings_per_language * languages)) entries.
        //
        if((1 + (ui32NumStringi16PerLang * ui32NumLangs)) !=
                g_ppsDevInfo[0]->ui32NumStringDescriptors)
        {
            return(-1);
        }
    
        //
        // Now determine which language we are looking for.  It is assumed that
        // the order of the groups of strings per language in the table is the
        // same as the order of the language IDs listed in the first descriptor.
        //
        pLang = (tString0Descriptor *)
                            (g_ppsDevInfo[0]->ppui8StringDescriptors[0]);
    
        //
        // Look through the supported languages looking for the one we were asked
        // for.
        //
        for(ui32Loop = 0; ui32Loop < ui32NumLangs; ui32Loop++)
        {
            //
            // Have we found the requested language?
            //
            if(pLang->wLANGID[ui32Loop] == ui16Lang)
            {
                //
                // Yes - calculate the index of the descriptor to send.
                //
                return((ui32NumStringi16PerLang * ui32Loop) + ui16Index);
            }
        }
    
        //
        // If we drop out of the loop, the requested language was not found so
        // return -1 to indicate the error.
        //
        return(-1);
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_DESCRIPTOR standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This function currently is not supported and will respond with a Stall
    // to indicate that this command is not supported by the device.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetDescriptor(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        //
        // Need to ACK the data on end point 0 without setting last data as there
        // will be a data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
    
        //
        // This function is not handled by default.
        //
        USBDCDStallEP0(0);
    }
    
    //*****************************************************************************
    //
    // This function handles the GET_CONFIGURATION standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This function responds to a host request to return the current
    // configuration of the USB device.  The function will send the configuration
    // response to the host and return.  This value will either be 0 or the last
    // value received from a call to SetConfiguration().
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDGetConfiguration(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        uint8_t ui8Value;
        tDCDInstance *psUSBControl;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
    
        //
        // Need to ACK the data on end point 0 without setting last data as there
        // will be a data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
    
        //
        // If we still have an address pending then the device is still not
        // configured.
        //
        if(psUSBControl->ui32DevAddress & DEV_ADDR_PENDING)
        {
            ui8Value = 0;
        }
        else
        {
            ui8Value = (uint8_t)psUSBControl->ui32Configuration;
        }
    
        psUSBControl->ui32EP0DataRemain = 1;
        psUSBControl->pui8EP0Data = &ui8Value;
    
        //
        // Send the single byte response.
        //
        USBDEP0StateTx(0);
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_CONFIGURATION standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This function responds to a host request to change the current
    // configuration of the USB device.  The actual configuration number is taken
    // from the structure passed in via \e psUSBRequest.  This number should be one
    // of the configurations that was specified in the descriptors.  If the
    // \e ConfigChange callback is specified in \e pvInstance->psInfo->psCallbacks->
    // it will be called so that the application can respond to a change in
    // configuration.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetConfiguration(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        tDCDInstance *psUSBControl;
        tDeviceInfo *psDevice;
        const tConfigHeader *psHdr;
        const tConfigDescriptor *psDesc;
    
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
        psDevice = g_ppsDevInfo[0];
    
        //
        // Need to ACK the data on end point 0 with last data set as this has no
        // data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
    
        //
        // Cannot set the configuration to one that does not exist so check the
        // enumeration structure to see how many valid configurations are present.
        //
        if(psUSBRequest->wValue > psDevice->pui8DeviceDescriptor[17])
        {
            //
            // The passed configuration number is not valid.  Stall the endpoint to
            // signal the error to the host.
            //
            USBDCDStallEP0(0);
        }
        else
        {
            //
            // Save the configuration.
            //
            psUSBControl->ui32Configuration = psUSBRequest->wValue;
    
            //
            // If passed a configuration other than 0 (which tells us that we are
            // not currently configured), configure the endpoints (other than EP0)
            // appropriately.
            //
            if(psUSBControl->ui32Configuration)
            {
                //
                // Get a pointer to the configuration descriptor.  This will always
                // be the first section in the current configuration.
                //
                psHdr = psDevice->ppsConfigDescriptors[psUSBRequest->wValue - 1];
                psDesc =
                    (const tConfigDescriptor *)(psHdr->psSections[0]->pui8Data);
    
                //
                // Remember the new self- or bus-powered state if the user has not
                // already called us to tell us the state to report.
                //
                if(!psUSBControl->bPwrSrcSet)
                {
                    if((psDesc->bmAttributes & USB_CONF_ATTR_PWR_M) ==
                        USB_CONF_ATTR_SELF_PWR)
                    {
                        psUSBControl->ui8Status |= USB_STATUS_SELF_PWR;
                    }
                    else
                    {
                        psUSBControl->ui8Status &= ~USB_STATUS_SELF_PWR;
                    }
                }
    
                //
                // Configure endpoints for the new configuration.
                //
                USBDeviceConfig(psUSBControl,
                        psDevice->ppsConfigDescriptors[psUSBRequest->wValue - 1]);
            }
    
            //
            // If there is a configuration change callback then call it.
            //
            if(psDevice->psCallbacks->pfnConfigChange)
            {
                psDevice->psCallbacks->pfnConfigChange(g_psDCDInst[0].pvCBData,
                                                psUSBControl->ui32Configuration);
            }
        }
    }
    
    //*****************************************************************************
    //
    // This function handles the GET_INTERFACE standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This function is called when the host controller request the current
    // interface that is in use by the device.  This simply returns the value set
    // by the last call to SetInterface().
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDGetInterface(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        uint8_t ui8Value;
        tDCDInstance *psUSBControl;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
    
        //
        // Need to ACK the data on end point 0 without setting last data as there
        // will be a data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, false);
    
        //
        // If we still have an address pending then the device is still not
        // configured.
        //
        if(psUSBControl->ui32DevAddress & DEV_ADDR_PENDING)
        {
            ui8Value = (uint8_t)0;
        }
        else
        {
            //
            // Is the interface number valid?
            //
            if(psUSBRequest->wIndex < USB_MAX_INTERFACES_PER_DEVICE)
            {
                //
                // Read the current alternate setting for the required interface.
                //
                ui8Value = psUSBControl->pui8AltSetting[psUSBRequest->wIndex];
            }
            else
            {
                //
                // An invalid interface number was specified.
                //
                USBDCDStallEP0(0);
                return;
            }
        }
    
        //
        // Send the single byte response.
        //
        psUSBControl->ui32EP0DataRemain = 1;
        psUSBControl->pui8EP0Data = &ui8Value;
    
        //
        // Send the single byte response.
        //
        USBDEP0StateTx(0);
    }
    
    //*****************************************************************************
    //
    // This function handles the SET_INTERFACE standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This function is called when a standard request for changing the interface
    // is received from the host controller.  If this is a valid request the
    // function will call the function specified by the InterfaceChange in the
    // \e pvInstance->psInfo->psCallbacks->variable to notify the application that
    // the interface has changed and will pass it the new alternate interface
    // number.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSetInterface(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        const tConfigHeader *psConfig;
        tInterfaceDescriptor *psInterface;
        uint32_t ui32Loop, ui32Section, ui32NumInterfaces;
        uint8_t ui8Interface;
        bool bRetcode;
        tDCDInstance *psUSBControl;
        tDeviceInfo *psDevice;
    
        ASSERT(psUSBRequest != 0);
        ASSERT(pvInstance != 0);
    
        //
        // Create the device information pointer.
        //
        psUSBControl = (tDCDInstance *)pvInstance;
        psDevice = g_ppsDevInfo[0];
    
        //
        // Need to ACK the data on end point 0 with last data set as this has no
        // data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
    
        //
        // Use the current configuration.
        //
        psConfig =
            psDevice->ppsConfigDescriptors[psUSBControl->ui32Configuration - 1];
    
        //
        // How many interfaces are included in the descriptor?
        //
        ui32NumInterfaces = USBDCDConfigDescGetNum(psConfig, USB_DTYPE_INTERFACE);
    
        //
        // Find the interface descriptor for the supplied interface and alternate
        // setting numbers.
        //
        for(ui32Loop = 0; ui32Loop < ui32NumInterfaces; ui32Loop++)
        {
            //
            // Get the next interface descriptor in the configuration descriptor.
            //
            psInterface = USBDCDConfigGetInterface(psConfig, ui32Loop,
                                                   USB_DESC_ANY, &ui32Section);
    
            //
            // Is this the required interface with the correct alternate setting?
            //
            if(psInterface &&
               (psInterface->bInterfaceNumber == psUSBRequest->wIndex) &&
               (psInterface->bAlternateSetting == psUSBRequest->wValue))
            {
                ui8Interface = psInterface->bInterfaceNumber;
    
                //
                // Make sure we don't write outside the bounds of the
                // pui8AltSetting array (in a debug build, anyway, since this
                // indicates an error in the device descriptor).
                //
                ASSERT(ui8Interface < USB_MAX_INTERFACES_PER_DEVICE);
    
                //
                // This is the correct interface descriptor so save the
                // setting.
                //
                psUSBControl->pui8AltSetting[ui8Interface] =
                                                psInterface->bAlternateSetting;
    
                //
                // Reconfigure the endpoints to match the requirements of the
                // new alternate setting for the interface.
                //
                bRetcode = USBDeviceConfigAlternate(psUSBControl, psConfig,
                                                ui8Interface,
                                                psInterface->bAlternateSetting);
    
                //
                // If there is a callback then notify the application of the
                // change to the alternate interface.
                //
                if(bRetcode && psDevice->psCallbacks->pfnInterfaceChange)
                {
                    psDevice->psCallbacks->pfnInterfaceChange(
                                                    g_psDCDInst[0].pvCBData,
                                                    psUSBRequest->wIndex,
                                                    psUSBRequest->wValue);
                }
    
                //
                // All done.
                //
                return;
            }
        }
    
        //
        // If we drop out of the loop, we didn't find an interface descriptor
        // matching the requested number and alternate setting or there was an
        // error while trying to set up for the new alternate setting.
        //
        USBDCDStallEP0(0);
    }
    
    //*****************************************************************************
    //
    // This function handles the SYNC_FRAME standard USB request.
    //
    // \param pvInstance is the USB device controller instance data.
    // \param psUSBRequest holds the data for this request.
    //
    // This is currently a stub function that will stall indicating that the
    // command is not supported.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDSyncFrame(void *pvInstance, tUSBRequest *psUSBRequest)
    {
        //
        // Need to ACK the data on end point 0 with last data set as this has no
        // data phase.
        //
        MAP_USBDevEndpointDataAck(USB0_BASE, USB_EP_0, true);
    
        //
        // Not handled yet so stall this request.
        //
        USBDCDStallEP0(0);
    }
    
    //*****************************************************************************
    //
    // This internal function handles sending data on endpoint zero.
    //
    // \param ui32Index is the index of the USB controller which is to be
    // initialized.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDEP0StateTx(uint32_t ui32Index)
    {
        uint32_t ui32NumBytes;
        uint8_t *pui8Data;
    
        ASSERT(ui32Index == 0);
    
        //
        // In the TX state on endpoint zero.
        //
        g_psDCDInst[0].iEP0State = eUSBStateTx;
    
        //
        // Set the number of bytes to send this iteration.
        //
        ui32NumBytes = g_psDCDInst[0].ui32EP0DataRemain;
    
        //
        // Limit individual transfers to 64 bytes.
        //
        if(ui32NumBytes > EP0_MAX_PACKET_SIZE)
        {
            ui32NumBytes = EP0_MAX_PACKET_SIZE;
        }
    
        //
        // Save the pointer so that it can be passed to the USBEndpointDataPut()
        // function.
        //
        pui8Data = (uint8_t *)g_psDCDInst[0].pui8EP0Data;
    
        //
        // Advance the data pointer and counter to the next data to be sent.
        //
        g_psDCDInst[0].ui32EP0DataRemain -= ui32NumBytes;
        g_psDCDInst[0].pui8EP0Data += ui32NumBytes;
    
        //
        // Put the data in the correct FIFO.
        //
        MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, pui8Data, ui32NumBytes);
    
        //
        // If this is exactly 64 then don't set the last packet yet.
        //
        if(ui32NumBytes == EP0_MAX_PACKET_SIZE)
        {
            //
            // There is more data to send or exactly 64 bytes were sent, this
            // means that there is either more data coming or a null packet needs
            // to be sent to complete the transaction.
            //
            MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_IN);
        }
        else
        {
            //
            // Now go to the status state and wait for the transmit to complete.
            //
            g_psDCDInst[0].iEP0State = eUSBStateStatus;
    
            //
            // Send the last bit of data.
            //
            MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_IN_LAST);
    
            //
            // If there is a sent callback then call it.
            //
            if((g_ppsDevInfo[0]->psCallbacks->pfnDataSent) &&
               (g_psDCDInst[0].ui32OUTDataSize != 0))
            {
                //
                // Call the custom handler.
                //
                g_ppsDevInfo[0]->psCallbacks->pfnDataSent(
                                                g_psDCDInst[0].pvCBData,
                                                g_psDCDInst[0].ui32OUTDataSize);
    
                //
                // There is no longer any data pending to be sent.
                //
                g_psDCDInst[0].ui32OUTDataSize = 0;
            }
        }
    }
    
    //*****************************************************************************
    //
    // This internal function handles sending the configuration descriptor on
    // endpoint zero.
    //
    // \param ui32Index is the index of the USB controller.
    //
    // \return None.
    //
    //*****************************************************************************
    static void
    USBDEP0StateTxConfig(uint32_t ui32Index)
    {
        uint32_t ui32NumBytes, ui32SecBytes, ui32ToSend;
        uint8_t *pui8Data;
        tConfigDescriptor sConfDesc;
        const tConfigHeader *psConfig;
        const tConfigSection *psSection;
    
        ASSERT(ui32Index == 0);
    
        //
        // In the TX state on endpoint zero.
        //
        g_psDCDInst[0].iEP0State = eUSBStateTxConfig;
    
        //
        // Find the current configuration descriptor definition.
        //
        psConfig = g_ppsDevInfo[0]->ppsConfigDescriptors[
                                                g_psDCDInst[0].ui8ConfigIndex];
    
        //
        // Set the number of bytes to send this iteration.
        //
        ui32NumBytes = g_psDCDInst[0].ui32EP0DataRemain;
    
        //
        // Limit individual transfers to 64 bytes.
        //
        if(ui32NumBytes > EP0_MAX_PACKET_SIZE)
        {
            ui32NumBytes = EP0_MAX_PACKET_SIZE;
        }
    
        //
        // If this is the first call, we need to fix up the total length of the
        // configuration descriptor.  This has already been determined and set in
        // g_sUSBDeviceState.ui32EP0DataRemain.
        //
        if((g_psDCDInst[0].ui16SectionOffset == 0) &&
           (g_psDCDInst[0].ui8ConfigSection == 0))
        {
            //
            // Copy the USB configuration descriptor from the beginning of the
            // first section of the current configuration.
            //
            sConfDesc = *(tConfigDescriptor *)g_psDCDInst[0].pui8EP0Data;
    
            //
            // Update the total size.
            //
            sConfDesc.wTotalLength = (uint16_t)USBDCDConfigDescGetSize(psConfig);
    
            //
            // Write the descriptor to the USB FIFO.
            //
            ui32ToSend = (ui32NumBytes < sizeof(tConfigDescriptor)) ? ui32NumBytes:
                            sizeof(tConfigDescriptor);
            MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, (uint8_t *)&sConfDesc,
                                   ui32ToSend);
    
            //
            // Did we reach the end of the first section?
            //
            if(psConfig->psSections[0]->ui16Size == ui32ToSend)
            {
                //
                // Update our tracking indices to point to the start of the next
                // section.
                //
                g_psDCDInst[0].ui16SectionOffset = 0;
                g_psDCDInst[0].ui8ConfigSection = 1;
            }
            else
            {
                //
                // Note that we have sent the first few bytes of the descriptor.
                //
                g_psDCDInst[0].ui16SectionOffset = (uint8_t)ui32ToSend;
            }
    
            //
            // How many bytes do we have remaining to send on this iteration?
            //
            ui32ToSend = ui32NumBytes - ui32ToSend;
        }
        else
        {
            //
            // Set the number of bytes we still have to send on this call.
            //
            ui32ToSend = ui32NumBytes;
        }
    
        //
        // Add the relevant number of bytes to the USB FIFO
        //
        while(ui32ToSend)
        {
            //
            // Get a pointer to the current configuration section.
            //
            psSection = psConfig->psSections[g_psDCDInst[0].ui8ConfigSection];
    
            //
            // Calculate bytes are available in the current configuration section.
            //
            ui32SecBytes = (uint32_t)(psSection->ui16Size -
                                      g_psDCDInst[0].ui16SectionOffset);
    
            //
            // Save the pointer so that it can be passed to the
            // USBEndpointDataPut() function.
            //
            pui8Data = (uint8_t *)psSection->pui8Data +
                                  g_psDCDInst[0].ui16SectionOffset;
    
            //
            // Are there more bytes in this section that we still have to send?
            //
            if(ui32SecBytes > ui32ToSend)
            {
                //
                // Yes - send only the remaining bytes in the transfer.
                //
                ui32SecBytes = ui32ToSend;
            }
    
            //
            // Put the data in the correct FIFO.
            //
            MAP_USBEndpointDataPut(USB0_BASE, USB_EP_0, pui8Data, ui32SecBytes);
    
            //
            // Fix up our pointers for the next iteration.
            //
            ui32ToSend -= ui32SecBytes;
            g_psDCDInst[0].ui16SectionOffset += (uint8_t)ui32SecBytes;
    
            //
            // Have we reached the end of a section?
            //
            if(g_psDCDInst[0].ui16SectionOffset == psSection->ui16Size)
            {
                //
                // Yes - move to the next one.
                //
                g_psDCDInst[0].ui8ConfigSection++;
                g_psDCDInst[0].ui16SectionOffset = 0;
            }
        }
    
        //
        // Fix up the number of bytes remaining to be sent and the start pointer.
        //
        g_psDCDInst[0].ui32EP0DataRemain -= ui32NumBytes;
    
        //
        // If we ran out of bytes in the configuration section, bail and just
        // send out what we have.
        //
        if(psConfig->ui8NumSections <= g_psDCDInst[0].ui8ConfigSection)
        {
            g_psDCDInst[0].ui32EP0DataRemain = 0;
        }
    
        //
        // If there is no more data don't keep looking or ui8ConfigSection might
        // overrun the available space.
        //
        if(g_psDCDInst[0].ui32EP0DataRemain != 0)
        {
            pui8Data =(uint8_t *)
                psConfig->psSections[g_psDCDInst[0].ui8ConfigSection]->pui8Data;
            ui32ToSend = g_psDCDInst[0].ui16SectionOffset;
            g_psDCDInst[0].pui8EP0Data = (pui8Data + ui32ToSend);
        }
    
        //
        // If this is exactly 64 then don't set the last packet yet.
        //
        if(ui32NumBytes == EP0_MAX_PACKET_SIZE)
        {
            //
            // There is more data to send or exactly 64 bytes were sent, this
            // means that there is either more data coming or a null packet needs
            // to be sent to complete the transaction.
            //
            MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_IN);
        }
        else
        {
            //
            // Send the last bit of data.
            //
            MAP_USBEndpointDataSend(USB0_BASE, USB_EP_0, USB_TRANS_IN_LAST);
    
            //
            // If there is a sent callback then call it.
            //
            if((g_ppsDevInfo[0]->psCallbacks->pfnDataSent) &&
               (g_psDCDInst[0].ui32OUTDataSize != 0))
            {
                //
                // Call the custom handler.
                //
                g_ppsDevInfo[0]->psCallbacks->pfnDataSent(g_psDCDInst[0].pvCBData,
                                                g_psDCDInst[0].ui32OUTDataSize);
    
                //
                // There is no longer any data pending to be sent.
                //
                g_psDCDInst[0].ui32OUTDataSize = 0;
            }
    
            //
            // Now go to the status state and wait for the transmit to complete.
            //
            g_psDCDInst[0].iEP0State = eUSBStateStatus;
        }
    }
    
    //*****************************************************************************
    //
    // The internal USB device interrupt handler.
    //
    // \param ui32Index is the USB controller associated with this interrupt.
    // \param ui32Status is the current interrupt status as read via a call to
    // USBIntStatusControl().
    //
    // This function is called from either \e USB0DualModeIntHandler() or
    // \e USB0DeviceIntHandler() to process USB interrupts when in device mode.
    // This handler will branch the interrupt off to the appropriate application or
    // stack handlers depending on the current status of the USB controller.
    //
    // The two-tiered structure for the interrupt handler ensures that it is
    // possible to use the same handler code in both device and OTG modes and
    // means that host code can be excluded from applications that only require
    // support for USB device mode operation.
    //
    // \return None.
    //
    //*****************************************************************************
    void
    USBDeviceIntHandlerInternal(uint32_t ui32Index, uint32_t ui32Status)
    {
        static uint32_t ui32SOFDivide = 0;
        void *pvInstance;
        uint32_t ui32DMAIntStatus;
        uint32_t ui32LPMStatus;
        tUSBDBulkDevice *psBulkDevice;
        tBulkInstance *psInst;
    
        //
        // If device initialization has not been performed then just disconnect
        // from the USB bus and return from the handler.
        //
        if(g_ppsDevInfo[0] == 0)
        {
            MAP_USBDevDisconnect(USB0_BASE);
            return;
        }
    
        pvInstance = g_psDCDInst[0].pvCBData;
    
        //
        // Received a reset from the host.
        //
        if(ui32Status & USB_INTCTRL_RESET)
        {
            USBDeviceEnumResetHandler(&g_psDCDInst[0]);
        }
    
        //
        // Suspend was signaled on the bus.
        //
        if(ui32Status & USB_INTCTRL_SUSPEND)
        {
            //
            // Call the SuspendHandler() if it was specified.
            //
            if(g_ppsDevInfo[0]->psCallbacks->pfnSuspendHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnSuspendHandler(pvInstance);
            }
        }
    
        //
        // Resume was signaled on the bus.
        //
        if(ui32Status & USB_INTCTRL_RESUME)
        {
            //
            // Call the ResumeHandler() if it was specified.
            //
            if(g_ppsDevInfo[0]->psCallbacks->pfnResumeHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnResumeHandler(pvInstance);
            }
        }
    
        //
        // USB device was disconnected.
        //
        if(ui32Status & USB_INTCTRL_DISCONNECT)
        {
            //
            // Call the DisconnectHandler() if it was specified.
            //
            if(g_ppsDevInfo[0]->psCallbacks->pfnDisconnectHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnDisconnectHandler(pvInstance);
            }
        }
    
        //
        // Start of Frame was received.
        //
        if(ui32Status & USB_INTCTRL_SOF)
        {
            //
            // Increment the global Start of Frame counter.
            //
            g_ui32USBSOFCount++;
    
            //
            // Increment our SOF divider.
            //
            ui32SOFDivide++;
    
            //
            // Handle resume signaling if required.
            //
            USBDeviceResumeTickHandler(&g_psDCDInst[0]);
    
            //
            // Have we counted enough SOFs to allow us to call the tick function?
            //
            if(ui32SOFDivide == USB_SOF_TICK_DIVIDE)
            {
                //
                // Yes - reset the divider and call the SOF tick handler.
                //
                ui32SOFDivide = 0;
                InternalUSBStartOfFrameTick(USB_SOF_TICK_DIVIDE);
            }
        }
    
        //
        // Handle LPM interrupts.
        //
        ui32LPMStatus = USBLPMIntStatus(USB0_BASE);
    
        //
        // The host LPM resume request has been acknowledged, allow the device
        // class to handle the sleep state.
        //
        if((g_psDCDInst[0].ui32LPMState == USBLIB_LPM_STATE_SLEEP) &&
           ((ui32LPMStatus & (USB_INTLPM_ACK | USB_INTLPM_RESUME)) ==
            USB_INTLPM_RESUME))
        {
            //
            // Notify the class of the wake from LPM L1.
            //
            if(g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler(pvInstance,
                                                    USB_EVENT_LPM_RESUME,
                                                    (void *)0);
            }
    
            //
            // Now back in the awake state.
            //
            g_psDCDInst[0].ui32LPMState = USBLIB_LPM_STATE_AWAKE;
    
            //
            // Enable receiving of LPM packet.
            //
            USBDevLPMEnable(USB0_BASE);
        }
        //
        // The host LPM sleep request has been acknowledged, allow the device
        // class to handle the sleep state.
        //
        else if((g_psDCDInst[0].ui32LPMState == USBLIB_LPM_STATE_AWAKE) &&
                ((ui32LPMStatus & (USB_INTLPM_ACK | USB_INTLPM_RESUME)) ==
                 USB_INTLPM_ACK))
        {
            if(g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler(pvInstance,
                                                    USB_EVENT_LPM_SLEEP,
                                                    (void *)0);
            }
    
            //
            // Now back in the sleep state.
            //
            g_psDCDInst[0].ui32LPMState = USBLIB_LPM_STATE_SLEEP;
        }
        else if(ui32LPMStatus & USB_INTLPM_NYET)
        {
            //
            // The device has held off the sleep state because LPM
            // responses are disabled.
            //
            if(g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler)
            {
                g_ppsDevInfo[0]->psCallbacks->pfnDeviceHandler(pvInstance,
                                                    USB_EVENT_LPM_ERROR,
                                                    (void *)0);
            }
        }
    
        //
        // Get the controller interrupt status.
        //
        ui32Status = MAP_USBIntStatusEndpoint(USB0_BASE);
    
        //
        // Handle end point 0 interrupts.
        //
        if(ui32Status & USB_INTEP_0)
        {
            USBDeviceEnumHandler(&g_psDCDInst[0]);
            ui32Status &= ~USB_INTEP_0;
        }
    
        //
        // Check to see if any DMA transfers are pending
        //
        ui32DMAIntStatus = USBLibDMAIntStatus(g_psDCDInst[0].psDMAInstance);
    
        if(ui32DMAIntStatus)
        {
            //
            // Handle any DMA interrupt processing.
            //
            USBLibDMAIntHandler(g_psDCDInst[0].psDMAInstance, ui32DMAIntStatus);
            UARTprintf("DMA Done1\n");
        }
    
        //
        // Because there is no way to detect if a uDMA interrupt has occurred,
        // check for an endpoint callback and call it if it is available.
        //
        if((g_ppsDevInfo[0]->psCallbacks->pfnEndpointHandler) &&
           ((ui32Status != 0) || (ui32DMAIntStatus != 0)))
        {
            g_ppsDevInfo[0]->psCallbacks->pfnEndpointHandler(pvInstance, ui32Status);
        }
    }
    
    //*****************************************************************************
    //
    // Close the Doxygen group.
    //! @}
    //
    //*****************************************************************************
    

    Do you have any idea why no packets are being sent when I use the USB_EP_DMA_MODE_1 flag?

  • Hi KF,

    I am trying to use DMA. "Sending Multiple Packets" does not work, while "Sending a Single Packet" does work.

      I think you really get ahead of me on using the integrated DMA.  You said it works if sending a single packet. Can you elaborate if you see NAK in this mode? In another word, if you were to send 1024 bytes using Single Packet mode, will you get NAK? This would mean that you would need to manually trigger each single packet transfer (64 bytes) for a total of 16 times. I understand your desire is to use multiple packets in one shot but I don't know why it does not work. Your code seems to be the same as what is described in the driver library user's guide for multiple packet operation but I don't what is wrong. When you said it does not work, does it mean no data comes out of the USB controller, or only partial data comes out?

  • Hi Charles,

    Can you elaborate if you see NAK in this mode? In another word, if you were to send 1024 bytes using Single Packet mode, will you get NAK?

    When using the "Sending a Single Packet" method, it behaves similarly to the normal bulk example. There is still a NAK before transferring each 64-byte data block to the host, repeating 16 times to complete the transfer of 1024 bytes of data.

    When you said it does not work, does it mean no data comes out of the USB controller, or only partial data comes out?

    There is no data coming out of the USB controller.

    Is there something I might be missing when using the "USB_EP_DMA_MODE_1" flag?

  • Hi KF,

      I wish I could help but I don't know what to suggest. Your code looks pretty much the same as shown in the user's guide except channel 1 is used instead of channel 0 as in yours. You might want to check if the interrupt is triggered and find out if ScheduleNextTransmission() is entered and where is it stuck?

    //
    // Endpoint 1 uses Mode 1 and transmit and enables automatic sending
    // when a full packet is sent to the FIFO.
    //
    USBEndpointDMAConfigSet(USB0_BASE, USB_EP_1, USB_EP_HOST_OUT |
    USB_EP_DMA_MODE_1 |
    USB_EP_AUTO_SET);
    //
    // Assign endpoint 1 to DMA channel 1 using Mode 1, no bursting, transmit,
    // and enable DMA interrupts.
    //
    USBDMAChannelConfigSet(USB0_BASE, 1, USB_EP_1, USB_DMA_CFG_MODE_1 |
    USB_DMA_CFG_BURST_NONE |
    USB_DMA_CFG_DIR_TX |
    USB_DMA_CFG_INT_EN);
    
    //
    // Set the source address for the transfer to pvBuffer.
    //
    USBDMAChannelAddressSet(USB0_BASE, 1, pvBuffer);
    //
    // Set the transfer size to 1024 bytes and the packet count to 16.
    // The packet count does not require a + 1 because 1024/64 leaves no
    // remaining bytes to send in a final packet.
    //
    USBDMAChannelCountSet(USB0_BASE, 0, 1024);
    USBEndpointPacketCountSet(USB0_BASE, 0, 1024/64);
    //
    // Enable the DMA transfer.
    //
    USBDMAChannelEnable();