diff options
| author | Yuval Adam <yuv.adm@gmail.com> | 2014-03-16 14:41:11 +0200 |
|---|---|---|
| committer | Yuval Adam <yuv.adm@gmail.com> | 2014-03-16 14:41:11 +0200 |
| commit | 990090a4cc9070837d31e66b58d40f0c3d038741 (patch) | |
| tree | cf1b905082c364e9b223e0c5058566103138dae5 /usblib/device/usbdenum.c | |
| parent | 7f4da522479c0f00126219f0c23b804c3a93d7a6 (diff) | |
Add usblib and utils
Diffstat (limited to 'usblib/device/usbdenum.c')
| -rw-r--r-- | usblib/device/usbdenum.c | 3190 |
1 files changed, 3190 insertions, 0 deletions
diff --git a/usblib/device/usbdenum.c b/usblib/device/usbdenum.c new file mode 100644 index 0000000..94e4cce --- /dev/null +++ b/usblib/device/usbdenum.c @@ -0,0 +1,3190 @@ +//*****************************************************************************
+//
+// usbenum.c - Enumeration code to handle all endpoint zero traffic.
+//
+// Copyright (c) 2007-2014 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.1.0.12573 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/usblibpriv.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.
+ //
+ 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);
+}
+
+//*****************************************************************************
+//
+//! 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;
+
+ //
+ // 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);
+ }
+
+ //
+ // 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.
+//! @}
+//
+//*****************************************************************************
|
