diff options
| author | Yuval Adam <yuval@y3xz.com> | 2015-03-13 12:24:52 +0200 |
|---|---|---|
| committer | Yuval Adam <yuval@y3xz.com> | 2015-03-13 12:24:52 +0200 |
| commit | 4085ae3ddfbbf10c8ccbd3dccd43452c40a1fe40 (patch) | |
| tree | ac63581949a49511136e7e9e47d265bfb4119b26 /boot_loader/bl_usbfuncs.c | |
| parent | 788db64b8642bf31de6930d18a62177c64163ee0 (diff) | |
Add bootloader, nfclib and sensorlib
Diffstat (limited to 'boot_loader/bl_usbfuncs.c')
| -rw-r--r-- | boot_loader/bl_usbfuncs.c | 1915 |
1 files changed, 1915 insertions, 0 deletions
diff --git a/boot_loader/bl_usbfuncs.c b/boot_loader/bl_usbfuncs.c new file mode 100644 index 0000000..552fabc --- /dev/null +++ b/boot_loader/bl_usbfuncs.c @@ -0,0 +1,1915 @@ +//*****************************************************************************
+//
+// bl_usbfuncs.c - The subset of USB library functions required by the USB DFU
+// boot loader.
+//
+// Copyright (c) 2008-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 Firmware Development Package.
+//
+//*****************************************************************************
+
+#include <stdbool.h>
+#include <stdint.h>
+#include "inc/hw_types.h"
+#include "inc/hw_memmap.h"
+#include "inc/hw_usb.h"
+#include "inc/hw_sysctl.h"
+#include "inc/hw_nvic.h"
+#include "inc/hw_ints.h"
+#include "inc/hw_gpio.h"
+#include "bl_config.h"
+#include "boot_loader/bl_usbfuncs.h"
+
+//*****************************************************************************
+//
+//! \addtogroup bl_usb_api
+//! @{
+//
+//*****************************************************************************
+#if defined(USB_ENABLE_UPDATE) || defined(DOXYGEN)
+
+//*****************************************************************************
+//
+// Local functions prototypes.
+//
+//*****************************************************************************
+static void USBDGetStatus(tUSBRequest *pUSBRequest);
+static void USBDClearFeature(tUSBRequest *pUSBRequest);
+static void USBDSetFeature(tUSBRequest *pUSBRequest);
+static void USBDSetAddress(tUSBRequest *pUSBRequest);
+static void USBDGetDescriptor(tUSBRequest *pUSBRequest);
+static void USBDSetDescriptor(tUSBRequest *pUSBRequest);
+static void USBDGetConfiguration(tUSBRequest *pUSBRequest);
+static void USBDSetConfiguration(tUSBRequest *pUSBRequest);
+static void USBDGetInterface(tUSBRequest *pUSBRequest);
+static void USBDSetInterface(tUSBRequest *pUSBRequest);
+static void USBDEP0StateTx(void);
+static int32_t USBDStringIndexFromRequest(uint16_t ui16Lang,
+ uint16_t ui16Index);
+
+//*****************************************************************************
+//
+// This structure holds the full state for the device enumeration.
+//
+//*****************************************************************************
+typedef struct
+{
+ //
+ // The devices current address, this also has a change pending bit in the
+ // MSB of this value specified by DEV_ADDR_PENDING.
+ //
+ volatile uint32_t ui32DevAddress;
+
+ //
+ // This holds the current active configuration for this device.
+ //
+ uint32_t ui32Configuration;
+
+ //
+ // This holds the current alternate interface for this device. We only have
+ // 1 interface so only need to hold 1 setting.
+ //
+ uint8_t ui8AltSetting;
+
+ //
+ // This is the pointer to the current data being sent out or received
+ // on endpoint zero.
+ //
+ uint8_t *pui8EP0Data;
+
+ //
+ // This is the number of bytes that remain to be sent from or received
+ // into the g_sUSBDeviceState.pui8EP0Data data buffer.
+ //
+ volatile uint32_t ui32EP0DataRemain;
+
+ //
+ // The amount of data being sent/received due to a custom request.
+ //
+ uint32_t ui32OUTDataSize;
+
+ //
+ // Holds the current device status.
+ //
+ uint8_t ui8Status;
+
+ //
+ // This flag indicates whether or not remote wakeup signalling is in
+ // progress.
+ //
+ bool bRemoteWakeup;
+
+ //
+ // During remote wakeup signalling, this counter is used to track the
+ // number of milliseconds since the signalling was initiated.
+ //
+ uint8_t ui8RemoteWakeupCount;
+}
+tDeviceState;
+
+//*****************************************************************************
+//
+// The states for endpoint zero during enumeration.
+//
+//*****************************************************************************
+typedef enum
+{
+ //
+ // The USB device is waiting on a request from the host controller on
+ // endpoint zero.
+ //
+ USB_STATE_IDLE,
+
+ //
+ // The USB device is sending data back to the host due to an IN request.
+ //
+ USB_STATE_TX,
+
+ //
+ // The USB device is receiving data from the host due to an OUT
+ // request from the host.
+ //
+ USB_STATE_RX,
+
+ //
+ // The USB device has completed the IN or OUT request and is now waiting
+ // for the host to acknowledge the end of the IN/OUT transaction. This
+ // is the status phase for a USB control transaction.
+ //
+ USB_STATE_STATUS,
+
+ //
+ // This endpoint has signaled a stall condition and is waiting for the
+ // stall to be acknowledged by the host controller.
+ //
+ USB_STATE_STALL
+}
+tEP0State;
+
+//*****************************************************************************
+//
+// 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.
+//
+//*****************************************************************************
+#define DEFAULT_CONFIG_ID 1
+
+//*****************************************************************************
+//
+// This label defines the number of milliseconds that the remote wakeup signal
+// must remain asserted before removing it. Section 7.1.7.7 of the USB 2.0 spec
+// states that "the remote wakeup 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 wakeup 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 signalling when the device's initial signal is
+// detected) must hold the resume signalling for at least 20mS.
+//
+//*****************************************************************************
+#define REMOTE_WAKEUP_READY_MS 20
+
+//*****************************************************************************
+//
+// The buffer for reading data coming into EP0
+//
+//*****************************************************************************
+static uint8_t g_pui8DataBufferIn[EP0_MAX_PACKET_SIZE];
+
+//*****************************************************************************
+//
+// This global holds the current state information for the USB device.
+//
+//*****************************************************************************
+static volatile tDeviceState g_sUSBDeviceState;
+
+//*****************************************************************************
+//
+// This global holds the current state of endpoint zero.
+//
+//*****************************************************************************
+static volatile tEP0State g_eUSBDEP0State = USB_STATE_IDLE;
+
+//*****************************************************************************
+//
+// Function table to handle standard requests.
+//
+//*****************************************************************************
+static const tStdRequest g_ppfnUSBDStdRequests[] =
+{
+ USBDGetStatus,
+ USBDClearFeature,
+ 0,
+ USBDSetFeature,
+ 0,
+ USBDSetAddress,
+ USBDGetDescriptor,
+ USBDSetDescriptor,
+ USBDGetConfiguration,
+ USBDSetConfiguration,
+ USBDGetInterface,
+ USBDSetInterface,
+};
+
+//*****************************************************************************
+//
+// Amount to shift the RX interrupt sources by in the flags used in the
+// interrupt calls.
+//
+//*****************************************************************************
+#define USB_INT_RX_SHIFT 8
+
+//*****************************************************************************
+//
+// Amount to shift the status interrupt sources by in the flags used in the
+// interrupt calls.
+//
+//*****************************************************************************
+#define USB_INT_STATUS_SHIFT 24
+
+//*****************************************************************************
+//
+// Amount to shift the RX endpoint status sources by in the flags used in the
+// calls.
+//
+//*****************************************************************************
+#define USB_RX_EPSTATUS_SHIFT 16
+
+//*****************************************************************************
+//
+// Converts from an endpoint specifier to the offset of the endpoint's
+// control/status registers.
+//
+//*****************************************************************************
+#define EP_OFFSET(Endpoint) (Endpoint - 0x10)
+
+//*****************************************************************************
+//
+// Retrieves data from endpoint 0's FIFO.
+//
+// \param pui8Data is a pointer to the data area used to return the data from
+// the FIFO.
+// \param pui32Size is initially the size of the buffer passed into this call
+// via the \e pui8Data parameter. It will be set to the amount of data
+// returned in the buffer.
+//
+// This function will return the data from the FIFO for endpoint 0.
+// The \e pui32Size parameter should indicate the size of the buffer passed in
+// the \e pui32Data parameter. The data in the \e pui32Size parameter will be
+// changed to match the amount of data returned in the \e pui8Data parameter.
+// If a zero byte packet was received this call will not return a error but
+// will instead just return a zero in the \e pui32Size parameter. The only
+// error case occurs when there is no data packet available.
+//
+// \return This call will return 0, or -1 if no packet was received.
+//
+//*****************************************************************************
+int32_t
+USBEndpoint0DataGet(uint8_t *pui8Data, uint32_t *pui32Size)
+{
+ uint32_t ui32ByteCount;
+
+ //
+ // Don't allow reading of data if the RxPktRdy bit is not set.
+ //
+ if((HWREGH(USB0_BASE + USB_O_CSRL0) & USB_CSRL0_RXRDY) == 0)
+ {
+ //
+ // Can't read the data because none is available.
+ //
+ *pui32Size = 0;
+
+ //
+ // Return a failure since there is no data to read.
+ //
+ return(-1);
+ }
+
+ //
+ // Get the byte count in the FIFO.
+ //
+ ui32ByteCount = HWREGH(USB0_BASE + USB_O_COUNT0 + USB_EP_0);
+
+ //
+ // Determine how many bytes we will actually copy.
+ //
+ ui32ByteCount = (ui32ByteCount < *pui32Size) ? ui32ByteCount : *pui32Size;
+
+ //
+ // Return the number of bytes we are going to read.
+ //
+ *pui32Size = ui32ByteCount;
+
+ //
+ // Read the data out of the FIFO.
+ //
+ for(; ui32ByteCount > 0; ui32ByteCount--)
+ {
+ //
+ // Read a byte at a time from the FIFO.
+ //
+ *pui8Data++ = HWREGB(USB0_BASE + USB_O_FIFO0 + (USB_EP_0 >> 2));
+ }
+
+ //
+ // Success.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Acknowledge that data was read from endpoint 0's FIFO.
+//
+// \param bIsLastPacket indicates if this is the last packet.
+//
+// This function acknowledges that the data was read from the endpoint 0's
+// FIFO. The \e bIsLastPacket parameter is set to a \b true value if this is
+// the last in a series of data packets. This call can be used if processing
+// is required between reading the data and acknowledging that the data has
+// been read.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USBDevEndpoint0DataAck(bool bIsLastPacket)
+{
+ //
+ // Clear RxPktRdy, and optionally DataEnd, on endpoint zero.
+ //
+ HWREGB(USB0_BASE + USB_O_CSRL0) =
+ USB_CSRL0_RXRDYC | (bIsLastPacket ? USB_CSRL0_DATAEND : 0);
+
+}
+
+//*****************************************************************************
+//
+// Puts data into endpoint 0's FIFO.
+//
+// \param pui8Data is a pointer to the data area used as the source for the
+// data to put into the FIFO.
+// \param ui32Size is the amount of data to put into the FIFO.
+//
+// This function will put the data from the \e pui8Data parameter into the FIFO
+// for endpoint 0. If a packet is already pending for transmission then
+// this call will not put any of the data into the FIFO and will return -1.
+//
+// \return This call will return 0 on success, or -1 to indicate that the FIFO
+// is in use and cannot be written.
+//
+//*****************************************************************************
+int32_t
+USBEndpoint0DataPut(uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Don't allow transmit of data if the TxPktRdy bit is already set.
+ //
+ if(HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) & USB_CSRL0_TXRDY)
+ {
+ return(-1);
+ }
+
+ //
+ // Write the data to the FIFO.
+ //
+ for(; ui32Size > 0; ui32Size--)
+ {
+ HWREGB(USB0_BASE + USB_O_FIFO0 + (USB_EP_0 >> 2)) = *pui8Data++;
+ }
+
+ //
+ // Success.
+ //
+ return(0);
+}
+
+//*****************************************************************************
+//
+// Starts the transfer of data from endpoint 0's FIFO.
+//
+// \param ui32TransType is set to indicate what type of data is being sent.
+//
+// This function will start the transfer of data from the FIFO for
+// endpoint 0. This is necessary if the \b USB_EP_AUTO_SET bit was not enabled
+// for the endpoint. Setting the \e ui32TransType parameter will allow the
+// appropriate signaling on the USB bus for the type of transaction being
+// requested. The \e ui32TransType parameter should be one of the following:
+//
+// - USB_TRANS_OUT for OUT transaction on any endpoint in host mode.
+// - USB_TRANS_IN for IN transaction on any endpoint in device mode.
+// - USB_TRANS_IN_LAST for the last IN transactions on endpoint zero in a
+// sequence of IN transactions.
+// - USB_TRANS_SETUP for setup transactions on endpoint zero.
+// - USB_TRANS_STATUS for status results on endpoint zero.
+//
+// \return This call will return 0 on success, or -1 if a transmission is
+// already in progress.
+//
+//*****************************************************************************
+int32_t
+USBEndpoint0DataSend(uint32_t ui32TransType)
+{
+ //
+ // Don't allow transmit of data if the TxPktRdy bit is already set.
+ //
+ if(HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) & USB_CSRL0_TXRDY)
+ {
+ return(-1);
+ }
+
+ //
+ // Set TxPktRdy in order to send the data.
+ //
+ HWREGB(USB0_BASE + USB_O_CSRL0 + USB_EP_0) = ui32TransType & 0xff;
+
+ //
+ // Success.
+ //
+ return(0);
+}
+
+#if defined(USB_VBUS_CONFIG) || defined(USB_ID_CONFIG) || \
+ defined(USB_DP_CONFIG) || defined(USB_DM_CONFIG) || defined(DOXYGEN)
+//*****************************************************************************
+//
+//! Initialize the pins used by USB functions.
+//!
+//! This function configures the pins for USB functions depending on defines
+//! from the bl_config.h file.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBConfigurePins(void)
+{
+ //
+ // Enable the clocks to the GPIOs.
+ //
+ HWREG(SYSCTL_RCGCGPIO) |= (0x0
+#if defined(USB_VBUS_CONFIG)
+ | USB_VBUS_PERIPH
+#endif
+#if defined(USB_ID_CONFIG)
+ | USB_ID_PERIPH
+#endif
+#if defined(USB_DP_CONFIG)
+ | USB_DP_PERIPH
+#endif
+#if defined(USB_DM_CONFIG)
+ | USB_DM_PERIPH
+#endif
+ );
+
+ //
+ // Setup the pins based on bl_config.h
+ //
+#if defined(USB_VBUS_CONFIG)
+ //
+ // Set the VBUS pin to be an analog input.
+ //
+ HWREG(USB_VBUS_PORT + GPIO_O_DIR) &= ~(1 << USB_VBUS_PIN);
+ HWREG(USB_VBUS_PORT + GPIO_O_AMSEL) |= (1 << USB_VBUS_PIN);
+#endif
+
+#if defined(USB_ID_CONFIG)
+ //
+ // Set the ID pin to be an analog input.
+ //
+ HWREG(USB_ID_PORT + GPIO_O_DIR) &= ~(1 << USB_ID_PIN);
+ HWREG(USB_ID_PORT + GPIO_O_AMSEL) |= (1 << USB_ID_PIN);
+#endif
+
+#if defined(USB_DP_CONFIG)
+ //
+ // Set the DP pin to be an analog input.
+ //
+ HWREG(USB_DP_PORT + GPIO_O_DIR) &= ~(1 << USB_DP_PIN);
+ HWREG(USB_DP_PORT + GPIO_O_AMSEL) |= (1 << USB_DP_PIN);
+#endif
+
+#if defined(USB_DM_CONFIG)
+ //
+ // Set the DM pin to be an analog input.
+ //
+ HWREG(USB_DM_PORT + GPIO_O_DIR) &= ~(1 << USB_DM_PIN);
+ HWREG(USB_DM_PORT + GPIO_O_AMSEL) |= (1 << USB_DM_PIN);
+#endif
+
+}
+#endif
+
+//*****************************************************************************
+//
+//! Initialize the boot loader USB functions.
+//!
+//! This function initializes the boot loader USB functions and places the DFU
+//! device onto the USB bus.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBBLInit(void)
+{
+ //
+ // Configure the USB Pins based on the bl_config.h settings.
+ //
+#if defined(USB_VBUS_CONFIG) || defined(USB_ID_CONFIG) || \
+ defined(USB_DP_CONFIG) || defined(USB_DM_CONFIG)
+ USBConfigurePins();
+#endif
+
+ //
+ // Initialize a couple of fields in the device state structure.
+ //
+ g_sUSBDeviceState.ui32Configuration = DEFAULT_CONFIG_ID;
+
+ //
+ // Enable the USB controller.
+ //
+ HWREG(SYSCTL_RCGC2) |= 0x10000;
+
+ //
+ // Turn on USB Phy clock.
+ //
+ HWREG(SYSCTL_RCC2) &= ~SYSCTL_RCC2_USBPWRDN;
+
+ //
+ // Clear any pending interrupts.
+ //
+ HWREGH(USB0_BASE + USB_O_TXIS);
+ HWREGB(USB0_BASE + USB_O_IS);
+
+ //
+ // Enable USB Interrupts.
+ //
+ HWREGH(USB0_BASE + USB_O_TXIE) = USB_TXIS_EP0;
+ HWREGB(USB0_BASE + USB_O_IE) = (USB_IS_DISCON | USB_IS_RESET);
+
+ //
+ // Default to the state where remote wakeup is disabled.
+ //
+ g_sUSBDeviceState.ui8Status = 0;
+ g_sUSBDeviceState.bRemoteWakeup = false;
+
+ //
+ // Determine the self- or bus-powered state based on bl_config.h setting.
+ //
+#if USB_BUS_POWERED
+ g_sUSBDeviceState.ui8Status &= ~USB_STATUS_SELF_PWR;
+#else
+ g_sUSBDeviceState.ui8Status |= USB_STATUS_SELF_PWR;
+#endif
+
+ //
+ // Attach the device using the soft connect.
+ //
+ HWREGB(USB0_BASE + USB_O_POWER) |= USB_POWER_SOFTCONN;
+
+ //
+ // Enable the USB interrupt.
+ //
+ HWREG(NVIC_EN1) = 1 << (INT_USB0 - 48);
+}
+
+//*****************************************************************************
+//
+// This function starts the request for data from the host on endpoint zero.
+//
+// \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. When the requested data is received,
+// the function HandleEP0Data() will be called.
+//
+// \return None.
+//
+//*****************************************************************************
+void
+USBBLRequestDataEP0(uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Enter the RX state on end point 0.
+ //
+ g_eUSBDEP0State = USB_STATE_RX;
+
+ //
+ // Save the pointer to the data.
+ //
+ g_sUSBDeviceState.pui8EP0Data = pui8Data;
+
+ //
+ // Location to save the current number of bytes received.
+ //
+ g_sUSBDeviceState.ui32OUTDataSize = ui32Size;
+
+ //
+ // Bytes remaining to be received.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain = ui32Size;
+}
+
+//*****************************************************************************
+//
+//! This function requests transfer of data to the host on endpoint zero.
+//!
+//! \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.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBBLSendDataEP0(uint8_t *pui8Data, uint32_t ui32Size)
+{
+ //
+ // Return the externally provided device descriptor.
+ //
+ g_sUSBDeviceState.pui8EP0Data = pui8Data;
+
+ //
+ // The size of the device descriptor is in the first byte.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain = ui32Size;
+
+ //
+ // Save the total size of the data sent.
+ //
+ g_sUSBDeviceState.ui32OUTDataSize = ui32Size;
+
+ //
+ // Now in the transmit data state.
+ //
+ USBDEP0StateTx();
+}
+
+//*****************************************************************************
+//
+//! This function generates a stall condition on endpoint zero.
+//!
+//! 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.
+//!
+//! \return None.
+//
+//*****************************************************************************
+void
+USBBLStallEP0(void)
+{
+ //
+ // Perform a stall on endpoint zero.
+ //
+ HWREGB(USB0_BASE + USB_O_CSRL0) |= (USB_CSRL0_STALL | USB_CSRL0_RXRDYC);
+
+ //
+ // Enter the stalled state.
+ //
+ g_eUSBDEP0State = USB_STATE_STALL;
+}
+
+//*****************************************************************************
+//
+// 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(void)
+{
+ uint32_t ui32Size;
+ tUSBRequest *pRequest;
+
+ //
+ // Cast the buffer to a request structure.
+ //
+ pRequest = (tUSBRequest *)g_pui8DataBufferIn;
+
+ //
+ // Set the buffer size.
+ //
+ ui32Size = EP0_MAX_PACKET_SIZE;
+
+ //
+ // Get the data from the USB controller end point 0.
+ //
+ USBEndpoint0DataGet(g_pui8DataBufferIn, &ui32Size);
+
+ if(!ui32Size)
+ {
+ return;
+ }
+
+ //
+ // See if this is a standard request or not.
+ //
+ if((pRequest->bmRequestType & USB_RTYPE_TYPE_M) != USB_RTYPE_STANDARD)
+ {
+ //
+ // Pass this non-standard request on to the DFU handler
+ //
+ HandleRequests(pRequest);
+ }
+ else
+ {
+ //
+ // Assure that the jump table is not out of bounds.
+ //
+ if((pRequest->bRequest <
+ (sizeof(g_ppfnUSBDStdRequests) / sizeof(tStdRequest))) &&
+ (g_ppfnUSBDStdRequests[pRequest->bRequest] != 0))
+ {
+ //
+ // Jump table to the appropriate handler.
+ //
+ g_ppfnUSBDStdRequests[pRequest->bRequest](pRequest);
+ }
+ else
+ {
+ //
+ // If there is no handler then stall this request.
+ //
+ USBBLStallEP0();
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This is the low level 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 USB_STATE_IDLE, \b USB_STATE_TX, \b USB_STATE_RX,
+// \b USB_STATE_STALL, and \b USB_STATE_STATUS. In the \b USB_STATE_IDLE
+// 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 USB_STATE_TX, \b USB_STATE_RX, or \b USB_STATE_STALL depending on the
+// command. If the controller enters the \b USB_STATE_TX or \b USB_STATE_RX
+// then once all data has been sent or received, it must pass through the
+// \b USB_STATE_STATUS state to allow the host to acknowledge completion of
+// the request. The \b USB_STATE_STALL is entered from \b USB_STATE_IDLE in
+// the event that the USB request was not valid. Both the \b USB_STATE_STALL
+// and \b USB_STATE_STATUS are transitional states that return to the
+// \b USB_STATE_IDLE state.
+//
+// \return None.
+//
+// USB_STATE_IDLE -*--> USB_STATE_TX -*-> USB_STATE_STATUS -*->USB_STATE_IDLE
+// | | |
+// |--> USB_STATE_RX - |
+// | |
+// |--> USB_STATE_STALL ---------->---------
+//
+// ----------------------------------------------------------------
+// | Current State | State 0 | State 1 |
+// | --------------------|-------------------|----------------------
+// | USB_STATE_IDLE | USB_STATE_TX/RX | USB_STATE_STALL |
+// | USB_STATE_TX | USB_STATE_STATUS | |
+// | USB_STATE_RX | USB_STATE_STATUS | |
+// | USB_STATE_STATUS | USB_STATE_IDLE | |
+// | USB_STATE_STALL | USB_STATE_IDLE | |
+// ----------------------------------------------------------------
+//
+//*****************************************************************************
+void
+USBDeviceEnumHandler(void)
+{
+ uint32_t ui32EPStatus;
+
+ //
+ // Get the TX portion of the endpoint status.
+ //
+ ui32EPStatus = HWREGH(USB0_BASE + EP_OFFSET(USB_EP_0) + USB_O_TXCSRL1);
+
+ //
+ // Get the RX portion of the endpoint status.
+ //
+ ui32EPStatus |=
+ ((HWREGH(USB0_BASE + EP_OFFSET(USB_EP_0) + USB_O_RXCSRL1)) <<
+ USB_RX_EPSTATUS_SHIFT);
+
+ //
+ // What state are we currently in?
+ //
+ switch(g_eUSBDEP0State)
+ {
+ //
+ // Handle the status state, this is a transitory state from
+ // USB_STATE_TX or USB_STATE_RX back to USB_STATE_IDLE.
+ //
+ case USB_STATE_STATUS:
+ {
+ //
+ // Just go back to the idle state.
+ //
+ g_eUSBDEP0State = USB_STATE_IDLE;
+
+ //
+ // If there is a pending address change then set the address.
+ //
+ if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING)
+ {
+ //
+ // Clear the pending address change and set the address.
+ //
+ g_sUSBDeviceState.ui32DevAddress &= ~DEV_ADDR_PENDING;
+ HWREGB(USB0_BASE + USB_O_FADDR) =
+ (uint8_t)g_sUSBDeviceState.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();
+ }
+ break;
+ }
+
+ //
+ // In the IDLE state the code is waiting to receive data from the host.
+ //
+ case USB_STATE_IDLE:
+ {
+ //
+ // Is there a packet waiting for us?
+ //
+ if(ui32EPStatus & USB_DEV_EP0_OUT_PKTRDY)
+ {
+ //
+ // Yes - process it.
+ //
+ USBDReadAndDispatchRequest();
+ }
+ break;
+ }
+
+ //
+ // Data is still being sent to the host so handle this in the
+ // EP0StateTx() function.
+ //
+ case USB_STATE_TX:
+ {
+ USBDEP0StateTx();
+ break;
+ }
+
+ //
+ // Handle the receive state for commands that are receiving data on
+ // endpoint zero.
+ //
+ case USB_STATE_RX:
+ {
+ uint32_t ui32DataSize;
+
+ //
+ // Set the number of bytes to get out of this next packet.
+ //
+ if(g_sUSBDeviceState.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 = g_sUSBDeviceState.ui32EP0DataRemain;
+ }
+
+ //
+ // Get the data from the USB controller end point 0.
+ //
+ USBEndpoint0DataGet(g_sUSBDeviceState.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(g_sUSBDeviceState.ui32EP0DataRemain < EP0_MAX_PACKET_SIZE)
+ {
+ //
+ // Need to ack the data on end point 0 in this case
+ // without setting data end.
+ //
+ USBDevEndpoint0DataAck(true);
+
+ //
+ // Return to the idle state.
+ //
+ g_eUSBDEP0State = USB_STATE_IDLE;
+
+ //
+ // If there is a receive callback then call it.
+ //
+ if(g_sUSBDeviceState.ui32OUTDataSize != 0)
+ {
+ //
+ // Call the receive handler to handle the data
+ // that was received.
+ //
+ HandleEP0Data(g_sUSBDeviceState.ui32OUTDataSize);
+
+ //
+ // Indicate that there is no longer any data being waited
+ // on.
+ //
+ g_sUSBDeviceState.ui32OUTDataSize = 0;
+ }
+ }
+ else
+ {
+ //
+ // Need to ack the data on end point 0 in this case
+ // without setting data end.
+ //
+ USBDevEndpoint0DataAck(false);
+ }
+
+ //
+ // Advance the pointer.
+ //
+ g_sUSBDeviceState.pui8EP0Data += ui32DataSize;
+
+ //
+ // Decrement the number of bytes that are being waited on.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain -= ui32DataSize;
+
+ break;
+ }
+ //
+ // The device stalled endpoint zero so check if the stall needs to be
+ // cleared once it has been successfully sent.
+ //
+ case USB_STATE_STALL:
+ {
+ //
+ // If we sent a stall then acknowledge this interrupt.
+ //
+ if(ui32EPStatus & USB_DEV_EP0_SENT_STALL)
+ {
+ //
+ // Clear the stall condition.
+ //
+ HWREGB(USB0_BASE + USB_O_CSRL0) &= ~(USB_DEV_EP0_SENT_STALL);
+
+ //
+ // Reset the global end point 0 state to IDLE.
+ //
+ g_eUSBDEP0State = USB_STATE_IDLE;
+
+ }
+ break;
+ }
+ //
+ // Halt on an unknown state, but only in DEBUG mode builds.
+ //
+ default:
+ {
+#ifdef DEBUG
+ while(1);
+#endif
+ 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(void)
+{
+ //
+ // Disable remote wakeup signalling (as per USB 2.0 spec 9.1.1.6).
+ //
+ g_sUSBDeviceState.ui8Status &= ~USB_STATUS_REMOTE_WAKE;
+ g_sUSBDeviceState.bRemoteWakeup = false;
+
+ //
+ // Call the device dependent code to indicate a bus reset has occurred.
+ //
+ HandleReset();
+
+ //
+ // Reset the default configuration identifier and alternate function
+ // selections.
+ //
+ g_sUSBDeviceState.ui32Configuration = DEFAULT_CONFIG_ID;
+ g_sUSBDeviceState.ui8AltSetting = 0;
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_STATUS standard USB request.
+//
+// \param pUSBRequest 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 pUSBRequest 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(tUSBRequest *pUSBRequest)
+{
+ uint16_t ui16Data;
+
+ //
+ // Determine what type of status was requested.
+ //
+ switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ //
+ // This was a Device Status request.
+ //
+ case USB_RTYPE_DEVICE:
+ {
+ //
+ // Return the current status for the device.
+ //
+ ui16Data = g_sUSBDeviceState.ui8Status;
+
+ break;
+ }
+
+ //
+ // This was a Interface status request.
+ //
+ case USB_RTYPE_INTERFACE:
+ {
+ //
+ // Interface status always returns 0.
+ //
+ ui16Data = 0;
+
+ break;
+ }
+
+ //
+ // This was an unknown request or a request for an endpoint (of which
+ // we have none) so set a stall.
+ //
+ case USB_RTYPE_ENDPOINT:
+ default:
+ {
+ //
+ // Anything else causes a stall condition to indicate that the
+ // command was not supported.
+ //
+ USBBLStallEP0();
+ return;
+ }
+ }
+
+ //
+ // Send the two byte status response.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain = 2;
+ g_sUSBDeviceState.pui8EP0Data = (uint8_t *)&ui16Data;
+
+ //
+ // Send the response.
+ //
+ USBDEP0StateTx();
+}
+
+//*****************************************************************************
+//
+// This function handles the CLEAR_FEATURE standard USB request.
+//
+// \param pUSBRequest holds the options for the Clear Feature USB request.
+//
+// This function handles device or endpoint clear feature requests. The
+// \e pUSBRequest structure holds the type of the request in the bmRequestType
+// field and the feature is held in the wValue field. For device, the only
+// clearable feature is the Remote Wake feature. This device request
+// should only be made if the descriptor indicates that Remote Wake is
+// implemented by the device. For endpoint requests the only clearable
+// feature is the ability to 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(tUSBRequest *pUSBRequest)
+{
+ //
+ // Determine what type of status was requested.
+ //
+ switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ //
+ // This is a clear feature request at the device level.
+ //
+ case USB_RTYPE_DEVICE:
+ {
+ //
+ // Only remote wake is clearable by this function.
+ //
+ if(USB_FEATURE_REMOTE_WAKE & pUSBRequest->wValue)
+ {
+ //
+ // Clear the remote wake up state.
+ //
+ g_sUSBDeviceState.ui8Status &= ~USB_STATUS_REMOTE_WAKE;
+
+ //
+ // Need to ack the data on end point 0.
+ //
+ USBDevEndpoint0DataAck(true);
+ }
+ else
+ {
+ USBBLStallEP0();
+ }
+ break;
+ }
+
+ //
+ // This is an unknown request or one destined for an invalid endpoint.
+ //
+ case USB_RTYPE_ENDPOINT:
+ default:
+ {
+ USBBLStallEP0();
+ return;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_FEATURE standard USB request.
+//
+// \param pUSBRequest holds the feature in the wValue field of the USB
+// request.
+//
+// This function handles device or endpoint set feature requests. The
+// \e pUSBRequest structure holds the type of the request in the bmRequestType
+// field and the feature is held in the wValue field. For device, the only
+// settable feature is the Remote Wake feature. This device request
+// should only be made if the descriptor indicates that Remote Wake is
+// implemented by the device. For endpoint requests the only settable feature
+// is the ability to 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(tUSBRequest *pUSBRequest)
+{
+ //
+ // Determine what type of status was requested.
+ //
+ switch(pUSBRequest->bmRequestType & USB_RTYPE_RECIPIENT_M)
+ {
+ //
+ // This is a set feature request at the device level.
+ //
+ case USB_RTYPE_DEVICE:
+ {
+ //
+ // Only remote wake is setable by this function.
+ //
+ if(USB_FEATURE_REMOTE_WAKE & pUSBRequest->wValue)
+ {
+ //
+ // Set the remote wakeup state.
+ //
+ g_sUSBDeviceState.ui8Status |= USB_STATUS_REMOTE_WAKE;
+
+ //
+ // Need to ack the data on end point 0.
+ //
+ USBDevEndpoint0DataAck(true);
+ }
+ else
+ {
+ USBBLStallEP0();
+ }
+ break;
+ }
+
+ //
+ // This is an unknown request or one destined for an invalid endpoint.
+ //
+ case USB_RTYPE_ENDPOINT:
+ default:
+ {
+ USBBLStallEP0();
+ return;
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_ADDRESS standard USB request.
+//
+// \param pUSBRequest 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(tUSBRequest *pUSBRequest)
+{
+ //
+ // The data needs to be acknowledged on end point 0 without setting data
+ // end because there is no data coming.
+ //
+ USBDevEndpoint0DataAck(true);
+
+ //
+ // Save the device address as we cannot change address until the status
+ // phase is complete.
+ //
+ g_sUSBDeviceState.ui32DevAddress = pUSBRequest->wValue | DEV_ADDR_PENDING;
+
+ //
+ // Transition directly to the status state since there is no data phase
+ // for this request.
+ //
+ g_eUSBDEP0State = USB_STATE_STATUS;
+
+ //
+ // Clear the DFU status just in case we were in an error state last time
+ // the device was accessed and we were unplugged and replugged (for a self-
+ // powered implementation, of course).
+ //
+ HandleSetAddress();
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_DESCRIPTOR standard USB request.
+//
+// \param pUSBRequest holds the data for this request.
+//
+// This function will return all configured standard USB descriptors to the
+// host - device, config and string descriptors. Any request for a descriptor
+// which is not available will result in endpoint 0 being stalled.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDGetDescriptor(tUSBRequest *pUSBRequest)
+{
+ uint32_t ui32Stall;
+
+ //
+ // Default to no stall.
+ //
+ ui32Stall = 0;
+
+ //
+ // Which descriptor are we being asked for?
+ //
+ switch(pUSBRequest->wValue >> 8)
+ {
+ //
+ // This request was for a device descriptor.
+ //
+ case USB_DTYPE_DEVICE:
+ {
+ //
+ // Return the externally provided device descriptor.
+ //
+ g_sUSBDeviceState.pui8EP0Data =
+ (uint8_t *)g_pui8DFUDeviceDescriptor;
+
+ //
+ // The size of the device descriptor is in the first byte.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain =
+ g_pui8DFUDeviceDescriptor[0];
+ break;
+ }
+
+ //
+ // This request was for a configuration descriptor.
+ //
+ case USB_DTYPE_CONFIGURATION:
+ {
+ uint8_t ui8Index;
+
+ //
+ // Which configuration are we being asked for?
+ //
+ ui8Index = (uint8_t)(pUSBRequest->wValue & 0xFF);
+
+ //
+ // Is this valid?
+ //
+ if(ui8Index != 0)
+ {
+ //
+ // This is an invalid configuration index. Stall EP0 to
+ // indicate a request error.
+ //
+ USBBLStallEP0();
+ g_sUSBDeviceState.pui8EP0Data = 0;
+ g_sUSBDeviceState.ui32EP0DataRemain = 0;
+ }
+ else
+ {
+ //
+ // Start by sending data from the beginning of the first
+ // descriptor.
+ //
+
+ g_sUSBDeviceState.pui8EP0Data =
+ (uint8_t *)g_pui8DFUConfigDescriptor;
+
+ //
+ // Get the size of the config descriptor (remembering that in
+ // this case, we only have a single section)
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain =
+ *(uint16_t *)&(g_pui8DFUConfigDescriptor[2]);
+ }
+ break;
+ }
+
+ //
+ // This request was for a string descriptor.
+ //
+ case USB_DTYPE_STRING:
+ {
+ int32_t i32Index;
+
+ //
+ // Determine the correct descriptor index based on the requested
+ // language ID and index.
+ //
+ i32Index = USBDStringIndexFromRequest(pUSBRequest->wIndex,
+ pUSBRequest->wValue & 0xFF);
+
+ //
+ // If the mapping function returned -1 then stall the request to
+ // indicate that the request was not valid.
+ //
+ if(i32Index == -1)
+ {
+ USBBLStallEP0();
+ break;
+ }
+
+ //
+ // Return the externally specified configuration descriptor.
+ //
+ g_sUSBDeviceState.pui8EP0Data =
+ (uint8_t *)g_ppui8StringDescriptors[i32Index];
+
+ //
+ // The total size of a string descriptor is in byte 0.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain =
+ g_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:
+ {
+ //
+ // All other requests are not handled.
+ //
+ USBBLStallEP0();
+ ui32Stall = 1;
+ break;
+ }
+ }
+
+ //
+ // If there was no stall, ACK the data and see if data needs to be sent.
+ //
+ if(ui32Stall == 0)
+ {
+ //
+ // Need to ack the data on end point 0 in this case without
+ // setting data end.
+ //
+ USBDevEndpoint0DataAck(false);
+
+ //
+ // If this request has data to send, then send it.
+ //
+ if(g_sUSBDeviceState.pui8EP0Data)
+ {
+ //
+ // If there is more data to send than is requested then just
+ // send the requested amount of data.
+ //
+ if(g_sUSBDeviceState.ui32EP0DataRemain > pUSBRequest->wLength)
+ {
+ g_sUSBDeviceState.ui32EP0DataRemain = pUSBRequest->wLength;
+ }
+
+ //
+ // Now in the transmit data state. Be careful to call the correct
+ // function since we need to handle the config descriptor
+ // differently from the others.
+ //
+ USBDEP0StateTx();
+ }
+ }
+}
+
+//*****************************************************************************
+//
+// 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;
+ uint32_t ui32NumStringsPerLang;
+ uint32_t ui32Loop;
+
+ //
+ // 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_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.
+ //
+ ui32NumStringsPerLang = ((NUM_STRING_DESCRIPTORS - 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 + (ui32NumStringsPerLang * ui32NumLangs)) != NUM_STRING_DESCRIPTORS)
+ {
+ 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_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((ui32NumStringsPerLang * 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 pUSBRequest 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(tUSBRequest *pUSBRequest)
+{
+ //
+ // This function is not handled by default.
+ //
+ USBBLStallEP0();
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_CONFIGURATION standard USB request.
+//
+// \param pUSBRequest 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(tUSBRequest *pUSBRequest)
+{
+ uint8_t ui8Value;
+
+ //
+ // If we still have an address pending then the device is still not
+ // configured.
+ //
+ if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING)
+ {
+ ui8Value = 0;
+ }
+ else
+ {
+ ui8Value = (uint8_t)g_sUSBDeviceState.ui32Configuration;
+ }
+
+ g_sUSBDeviceState.ui32EP0DataRemain = 1;
+ g_sUSBDeviceState.pui8EP0Data = &ui8Value;
+
+ //
+ // Send the single byte response.
+ //
+ USBDEP0StateTx();
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_CONFIGURATION standard USB request.
+//
+// \param pUSBRequest 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 pUSBRequest.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetConfiguration(tUSBRequest *pUSBRequest)
+{
+ //
+ // Cannot set the configuration to one that does not exist so check the
+ // enumeration structure to see how many valid configurations are present.
+ //
+ if(pUSBRequest->wValue > 1)
+ {
+ //
+ // The passed configuration number is not valid. Stall the endpoint to
+ // signal the error to the host.
+ //
+ USBBLStallEP0();
+ }
+ else
+ {
+ //
+ // Need to ack the data on end point 0.
+ //
+ USBDevEndpoint0DataAck(true);
+
+ //
+ // Save the configuration.
+ //
+ g_sUSBDeviceState.ui32Configuration = pUSBRequest->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(g_sUSBDeviceState.ui32Configuration)
+ {
+ //
+ // Set the power state
+ //
+#if USB_BUS_POWERED
+ g_sUSBDeviceState.ui8Status &= ~USB_STATUS_SELF_PWR;
+#else
+ g_sUSBDeviceState.ui8Status |= USB_STATUS_SELF_PWR;
+#endif
+ }
+
+ //
+ // Do whatever needs to be done as a result of the config change.
+ //
+ HandleConfigChange(g_sUSBDeviceState.ui32Configuration);
+ }
+}
+
+//*****************************************************************************
+//
+// This function handles the GET_INTERFACE standard USB request.
+//
+// \param pUSBRequest 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(tUSBRequest *pUSBRequest)
+{
+ uint8_t ui8Value;
+
+ //
+ // If we still have an address pending then the device is still not
+ // configured.
+ //
+ if(g_sUSBDeviceState.ui32DevAddress & DEV_ADDR_PENDING)
+ {
+ ui8Value = 0;
+ }
+ else
+ {
+ //
+ // Is the interface number valid?
+ //
+ if(pUSBRequest->wIndex == 0)
+ {
+ //
+ // Read the current alternate setting for the required interface.
+ //
+ ui8Value = g_sUSBDeviceState.ui8AltSetting;
+ }
+ else
+ {
+ //
+ // An invalid interface number was specified.
+ //
+ USBBLStallEP0();
+ return;
+ }
+ }
+
+ //
+ // Send the single byte response.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain = 1;
+ g_sUSBDeviceState.pui8EP0Data = &ui8Value;
+
+ //
+ // Send the single byte response.
+ //
+ USBDEP0StateTx();
+}
+
+//*****************************************************************************
+//
+// This function handles the SET_INTERFACE standard USB request.
+//
+// \param pUSBRequest holds the data for this request.
+//
+// The DFU device supports a single interface with no alternate settings so
+// this handler is hardcoded assuming this configuration.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDSetInterface(tUSBRequest *pUSBRequest)
+{
+ if((pUSBRequest->wIndex == 0) && (pUSBRequest->wValue == 0))
+ {
+ //
+ // We were passed a valid interface number so acknowledge the request.
+ //
+ USBDevEndpoint0DataAck(true);
+ }
+ else
+ {
+ //
+ // The values passed were not valid so stall endpoint 0.
+ //
+ USBBLStallEP0();
+ }
+}
+
+//*****************************************************************************
+//
+// This internal function handles sending data on endpoint zero.
+//
+// \return None.
+//
+//*****************************************************************************
+static void
+USBDEP0StateTx(void)
+{
+ uint32_t ui32NumBytes;
+ uint8_t *pui8Data;
+
+ //
+ // In the TX state on endpoint zero.
+ //
+ g_eUSBDEP0State = USB_STATE_TX;
+
+ //
+ // Set the number of bytes to send this iteration.
+ //
+ ui32NumBytes = g_sUSBDeviceState.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 = g_sUSBDeviceState.pui8EP0Data;
+
+ //
+ // Advance the data pointer and counter to the next data to be sent.
+ //
+ g_sUSBDeviceState.ui32EP0DataRemain -= ui32NumBytes;
+ g_sUSBDeviceState.pui8EP0Data += ui32NumBytes;
+
+ //
+ // Put the data in the correct FIFO.
+ //
+ USBEndpoint0DataPut(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.
+ //
+ USBEndpoint0DataSend(USB_TRANS_IN);
+ }
+ else
+ {
+ //
+ // Now go to the status state and wait for the transmit to complete.
+ //
+ g_eUSBDEP0State = USB_STATE_STATUS;
+
+ //
+ // Send the last bit of data.
+ //
+ USBEndpoint0DataSend(USB_TRANS_IN_LAST);
+ g_sUSBDeviceState.ui32OUTDataSize = 0;
+ }
+}
+
+//*****************************************************************************
+//
+// Close the Doxygen group.
+//! @}
+//
+//*****************************************************************************
+#endif // USB_ENABLE_UPDATE
|
